Generating an Abstract Syntax Tree for java source code using ANTLR - java

How Can I Generate an AST from java src code Using ANTLR?
any help?

OK, here are the steps:
Go to the ANTLR site and download the latest version
Download the Java.g and the JavaTreeParser.g files from here.
Run the following commands:
java -jar antlrTool Java.g
java -jar antlrTool JavaTreeParser.g
5 files will be generated:
Java.tokens
JavaLexer.java
JavaParser.java
JavaTreeParser.g
JavaTreeParser.tokens
use this java code to generate the Abstract Syntax Tree and to print it:
String input = "public class HelloWord {"+
"public void print(String r){" +
"for(int i = 0;true;i+=2)" +
"System.out.println(r);" +
"}" +
"}";
CharStream cs = new ANTLRStringStream(input);
JavaLexer jl = new JavaLexer(cs);
CommonTokenStream tokens = new CommonTokenStream();
tokens.setTokenSource(jl);
JavaParser jp = new JavaParser(tokens);
RuleReturnScope result = jp.compilationUnit();
CommonTree t = (CommonTree) result.getTree();
CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
nodes.setTokenStream(tokens);
JavaTreeParser walker = new JavaTreeParser(nodes);
System.out.println("\nWalk tree:\n");
printTree(t,0);
System.out.println(tokens.toString());
}
public static void printTree(CommonTree t, int indent) {
if ( t != null ) {
StringBuffer sb = new StringBuffer(indent);
for ( int i = 0; i < indent; i++ )
sb = sb.append(" ");
for ( int i = 0; i < t.getChildCount(); i++ ) {
System.out.println(sb.toString() + t.getChild(i).toString());
printTree((CommonTree)t.getChild(i), indent+1);
}
}
}

The setps to generate java src AST using antlr4 are:
Install antlr4 you can use this link to do that.
After installation download the JAVA grammar from here.
Now generate Java8Lexer and Java8Parser using the command:
antlr4 -visitor Java8.g4
This will generate several files such as Java8BaseListener.java Java8BaseVisitor.java Java8Lexer.java Java8Lexer.tokens Java8Listener.java Java8Parser.java Java8.tokens Java8Visitor.java
Use this code to generate AST:
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
public class ASTGenerator {
public static String readFile() throws IOException {
File file = new File("path/to/the/test/file.java");
byte[] encoded = Files.readAllBytes(file.toPath());
return new String(encoded, Charset.forName("UTF-8"));
}
public static void main(String args[]) throws IOException {
String inputString = readFile();
ANTLRInputStream input = new ANTLRInputStream(inputString);
Java8Lexer lexer = new Java8Lexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
Java8Parser parser = new Java8Parser(tokens);
ParserRuleContext ctx = parser.classDeclaration();
printAST(ctx, false, 0);
}
private static void printAST(RuleContext ctx, boolean verbose, int indentation) {
boolean toBeIgnored = !verbose && ctx.getChildCount() == 1 && ctx.getChild(0) instanceof ParserRuleContext;
if (!toBeIgnored) {
String ruleName = Java8Parser.ruleNames[ctx.getRuleIndex()];
for (int i = 0; i < indentation; i++) {
System.out.print(" ");
}
System.out.println(ruleName + " -> " + ctx.getText());
}
for (int i = 0; i < ctx.getChildCount(); i++) {
ParseTree element = ctx.getChild(i);
if (element instanceof RuleContext) {
printAST((RuleContext) element, verbose, indentation + (toBeIgnored ? 0 : 1));
}
}
}
}
After you are done coding you can use gradle to build your project or you can download antlr-4.7.1-complete.jar in your project directory and start compiling.
If you want a the output in a DOT file so that u can visualise the AST then you can refer to this QnA post or directly refer to this repository in which i have used gradle to build the project.
Hope this helps. :)

Related

System.out.format not working in java for loop

Below is the concerned code. Basically what the code is supposed to do is output the URL, name and version of each GitHub release defined by GetUpdateInfo.getInfo().
GetUpdateInfo.getInfo (NOTE Strings login, oauth and password omitted for security reasons.):
import java.util.List;
import org.kohsuke.github.*;
import org.apache.commons.lang3.ArrayUtils;
public class GetUpdateInfo {
public static getInfo() {
String version = "";
String url = "";
String[] urls = {};
String[] names = {};
String[] versions = {};
String[] releases = {};
GitHub github = GitHubBuilder.fromEnvironment(login, password, oauth).build();
//Get the repo name from the organization
GHOrganization gho = github.getOrganization("NuovoLauncher-Mods");
PagedIterable<GHRepository> repos = gho.listRepositories();
List<GHRepository> repos_list = repos.asList();
for(int i=0; i < repos_list.size(); i++) {
GHRepository repo_test = repos_list.get(i);
GHRelease latest = repo_test.getLatestRelease();
ArrayUtils.add(releases, latest.toString());
ArrayUtils.add(names, latest.getName());
ui.setName(names);
ui.setRelease(releases);
List<GHAsset> assets = latest.getAssets();
for( int x = 0; x < assets.size(); x++ ) {
GHAsset asset = assets.get(x);
url = asset.getBrowserDownloadUrl();
version = url.split("/")[7];
System.out.format("URL: %s, Name: %s, Latest Release: %s. Version %s\n", url, latest.getName(), latest, version);
ArrayUtils.add(urls, url);
ArrayUtils.add(versions, version);
ui.setURL(urls);
ui.setVersion(versions);
}
}
return ui;
}
public static void main(String[] args) throws Exception {
GetUpdateInfo.getInfo();
}
}
DownloadUpdate.runner:
public static void runner() throws Exception {
String system_type = System.getProperty("os.name");
File fpath = new File("");
UpdateInfo ui = GetUpdateInfo.getInfo();
for(int i = 0; i < ui.getName().length; i++) {
System.out.format("URL: %s, Name %s, Version, %s", ui.getURL()[i], ui.getName()[i], ui.getVersion()[i]);
System.out.format("Downloading %s-%s", ui.getName()[i], ui.getVersion()[i]);
System.out.print("\n");
if(system_type.equals("Linux")) {
fpath = new File(System.getProperty("user.home") + "/.minecraft/mods/" + ui.getName()[i] + "-" + ui.getVersion()[i] + ".jar");
} else if(system_type.equals("Windows")) {
fpath = new File(System.getProperty("user.home") + "/AppData/Roaming/.minecraft/mods" + ui.getName()[i] + "-" + ui.getVersion()[i] + ".jar");
} else {
fpath = new File(System.getProperty("user.home") + "/.minecraft/mods/" + ui.getName()[i] + "-" + ui.getVersion()[i] + ".jar");
}
String url = ui.getURL()[i];
FileUtils.copyURLToFile(new URL(url), fpath);
}
}
public static void main(String[] args) throws Exception {
System.out.println("DEBUG START");
DownloadUpdate.runner();
}
}
Looking at the code, I cannot see a reason why the code is not outputting like expected; I am getting zero output on console, simply the line stating that the code is being executed. No exceptions either.
EDIT: variable ui is not being returned properly. For example, ui.getName[0] throws an ArrayIndexOutOfBoundsException, due to the length being zero. Seeing this, I now understand why the for loop isn't behaving as expected. Is this a scope issue? What am I missing here?
An obvious problem of your code is the use of ArrayUtils.add: you have to reassign its result to the input array, as you cannot modify arrays like lists in Java.
Use it like this:
releases = ArrayUtils.add(releases, latest.toString());
names = ArrayUtils.add(names, latest.getName());
and later in the for-loop:
urls = ArrayUtils.add(urls, url);
versions = ArrayUtils.add(versions, version);
Also you don't need to set the elements in each loop cycle to the result:
ui.setURL(urls);
ui.setVersion(versions);
Those would be sufficient once the for-loop has completed.
An alternative would be to first use List<String> instead of the arrays. If you have control over the UpdateInfo class, change it there to be lists too, otherwise create an array from the lists before you set it in UpdateInfo.
As a general advice I would recommend that you get rid of your static methods. Create instances and use your credentials (login, password, oauth) as member fields OR pass in even the whole GitHub instance. This way you would have an easier time writing proper tests.

Apache POI doesn't find highlighted text

I have a file saved in doc format, and I need to extract highlighted text.
I have code like in following:
HWPFDocument document = new HWPFDocument(fis);
Range r = document.getRange();
for (int i=0;i<5;i++) {
CharacterRun t = r.getCharacterRun(i);
System.out.println(t.isHighlighted());
System.out.println(t.getHighlightedColor());
System.out.println(r.getCharacterRun(i).SPRM_HIGHLIGHT);
System.out.println(r.getCharacterRun(i));
}
None of the above methods show that text is highlighted, but when I open it, it is highlighted.
What can be the reason, and how to find if the text is highlighted or not?
Highlighting text in Word is possible using two different methods. First is applying highlighting to text runs. Second is applying shading to words or paragraphs.
For the first and using *.doc, the Word binary file format, apache poi provides methods in CharacterRun. For the second apache poi provides Paragraph.getShading. But this is only set if the shading applies to the whole paragraph. If the shading is applied only to single runs, then apache poi provides nothing for that. So using the underlying SprmOperations is needed.
Microsoft's documentation 2.6.1 Character Properties describes sprmCShd80 (0x4866) which is "A Shd80 structure that specifies the background shading for the text.". So we need searching for that.
Example:
import java.io.FileInputStream;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.hwpf.sprm.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class HWPFInspectBgColor {
private static void showCharacterRunInternals(CharacterRun run) throws Exception {
Field _chpx = CharacterRun.class.getDeclaredField("_chpx");
_chpx.setAccessible(true);
SprmBuffer sprmBuffer = (SprmBuffer) _chpx.get(run);
for (SprmIterator sprmIterator = sprmBuffer.iterator(); sprmIterator.hasNext(); ) {
SprmOperation sprmOperation = sprmIterator.next();
System.out.println(sprmOperation);
}
}
static SprmOperation getCharacterRunShading(CharacterRun run) throws Exception {
SprmOperation shd80Operation = null;
Field _chpx = CharacterRun.class.getDeclaredField("_chpx");
_chpx.setAccessible(true);
Field _value = SprmOperation.class.getDeclaredField("_value");
_value.setAccessible(true);
SprmBuffer sprmBuffer = (SprmBuffer) _chpx.get(run);
for (SprmIterator sprmIterator = sprmBuffer.iterator(); sprmIterator.hasNext(); ) {
SprmOperation sprmOperation = sprmIterator.next();
short sprmValue = (short)_value.get(sprmOperation);
if (sprmValue == (short)0x4866) { // we have a Shd80 structure, see https://msdn.microsoft.com/en-us/library/dd947480(v=office.12).aspx
shd80Operation = sprmOperation;
}
}
return shd80Operation;
}
public static void main(String[] args) throws Exception {
HWPFDocument document = new HWPFDocument(new FileInputStream("sample.doc"));
Range range = document.getRange();
for (int p = 0; p < range.numParagraphs(); p++) {
Paragraph paragraph = range.getParagraph(p);
System.out.println(paragraph);
if (!paragraph.getShading().isEmpty()) {
System.out.println("Paragraph's shading: " + paragraph.getShading());
}
for (int r = 0; r < paragraph.numCharacterRuns(); r++) {
CharacterRun run = paragraph.getCharacterRun(r);
System.out.println(run);
if (run.isHighlighted()) {
System.out.println("Run's highlighted color: " + run.getHighlightedColor());
}
if (getCharacterRunShading(run) != null) {
System.out.println("Run's Shd80 structure: " + getCharacterRunShading(run));
}
}
}
}
}

Problems with the import statement

I've created the following java file:
import java.awt.*;
public class Text {
public static void main(String[] args) {
String str = "I AM A SENTENCE";
String[] lines = wrap(str, 5);
for (int i=0;i<lines.length;i++) {
if (lines[i] != null) System.out.println(lines[i]);
}
Font myFont = new Font("Impact", Font.BOLD, 36);
System.out.println(String.valueOf(charToPixel(str, myFont)));
}
public static String[] wrap(String str, int w) {
char[] string = str.toCharArray();
System.out.println("string.length: " + String.valueOf(string.length));
int charCounter = 0;
String[] line = new String[20];
String work = "";
int x = 0;
for (int i=0;i<string.length;i++) {
charCounter++;
System.out.println("charCounter: " + String.valueOf(charCounter));
System.out.println("i: " + string[i]);
if (charCounter > w) {
charCounter = 0;
System.out.println(String.valueOf(x));
line[x] = work;
x++;
work = "";
i--;
}
else {
work += string[i];
}
}
line[x] = work;
return line;
}
}
Now, I also created a simple applet that I want to use to receive the String[] and then one by one output it using Graphics.drawString().
I created a .jar file using the default manifest and the previous class file. The class file's directory is as follows within the jar: Dennis\Text.class.
I added my jar into the CLASSPATH.
I used the import statement as follows: import Dennis.*;
However when I compile the applet (btw the Text.class had compiled perfectly)
I get the following compilation error:
bad class file: B:\Apps\Java\JDK\lib\Text.jar(Dennis/Text.class)
class file contains wrong class: Text
Please remove or make sure it appears in the correct subdirectory of the classpath.
As far as I can tell, I put everything in the right place and the import statement was successful.
So what am I doing wrong?
The class file's directory is as follows within the jar: Dennis\Text.class.
It shouldn't be. It's not in any package, so it should just be directly within the root directory of the jar file. Ideally put it within a package (not Dennis, which violates Java naming conventions) and then make your jar file structure match the package structure.

Why the HelloWorld of opennlp library works fine on Java but doesn't work with Jruby?

I am getting this error:
SyntaxError: hello.rb:13: syntax error, unexpected tIDENTIFIER
public HelloWorld( InputStream data ) throws IOException {
The HelloWorld.rb is:
require "java"
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import opennlp.tools.postag.POSModel;
import opennlp.tools.postag.POSTaggerME;
public class HelloWorld {
private POSModel model;
public HelloWorld( InputStream data ) throws IOException {
setModel( new POSModel( data ) );
}
public void run( String sentence ) {
POSTaggerME tagger = new POSTaggerME( getModel() );
String[] words = sentence.split( "\\s+" );
String[] tags = tagger.tag( words );
double[] probs = tagger.probs();
for( int i = 0; i < tags.length; i++ ) {
System.out.println( words[i] + " => " + tags[i] + " # " + probs[i] );
}
}
private void setModel( POSModel model ) {
this.model = model;
}
private POSModel getModel() {
return this.model;
}
public static void main( String args[] ) throws IOException {
if( args.length < 2 ) {
System.out.println( "HelloWord <file> \"sentence to tag\"" );
return;
}
InputStream is = new FileInputStream( args[0] );
HelloWorld hw = new HelloWorld( is );
is.close();
hw.run( args[1] );
}
}
when running ruby HelloWorld.rb "I am trying to make it work"
when I run the HelloWorld.java "I am trying to make it work" it works perfectly, of course the .java doesn't contain the require java statement.
EDIT:
I followed the following steps.
The output for jruby -v :
jruby 1.6.7.2 (ruby-1.8.7-p357) (2012-05-01 26e08ba) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_35) [darwin-x86_64-java]
JRuby is a ruby implementation in Java, this means if you want to use JRuby, you have to use the ruby syntax. You can indeed use Java objects in JRuby, but using the ruby syntax – you just can’t use Java syntax.
For example, frame = javax.swing.JFrame.new("Window") uses JFrame, but with a ruby syntax (i.e. JFrame.new rather than new JFrame).
And so your code would be something like:
require 'java'
# Require opennlp jars
Dir.glob('**/*.jar').each do |jar|
require jar
end
java_import 'opennlp.tools.postag.POSTaggerME'
java_import 'opennlp.tools.postag.POSModel'
class HelloWorld
def initialize(data)
#model = POSModel.new(data)
end
def run(sentence)
tagger = POSTaggerME.new(#model)
words = sentence.split
tags = tagger.tag(words)
probs = tagger.probs
probs.each_with_index do |p,i|
puts "#{words[i]} => #{tags[i]} # #{p}"
end
end
end
stream = File.new(ARGV[0]).to_java.getInStream
HelloWorld.new(stream).run(ARGV[1])
All. ruby. code.
Because it's written in Java and not Ruby?

Java Generate software configuration

I am working on a project which has some .properties configuration files for datasource, MQ and some other stuff. We do also have launch shell scripts and user profile scripts. The problem i am facing is that we do actually deploy this software on 5 different environments, and of course the configuration is different for each of them. It's being a little bit hard to maintain about 30 plain text files with the configuration. Most of them are pretty much equal, like shell scripts that only have some different path references on.
Do you guys know any kind of tool i could integrate on our build script that might grab these properties from a single file or an embedded database and then generate the proper environment configuration? If it could also generate the scripts it would be even more interesting.
Thanks
Maven provides this out-of-the-box: http://maven.apache.org/guides/mini/guide-building-for-different-environments.html.
I am the maintainer of Config4*, which is a configuration-file parser library in C++ and Java flavours. Most of the contents in a Config4* configuration file are name=value statements, but you can reference environment variables and the standard output of executing some commands like hostname. You can also have if-then-else statements in a configuration file. For example (keywords are prefixed with "#"):
#if (exec("hostname") #in ["host1", "host2", "host3"]) {
... # set variables to values for production environment
} #elseIf (exec("hostname") #in ["host4", "host5", "host6"]) {
... # set variables to values for staging environment
} #else {
#error "Unknown host";
}
I call this adaptable configuration because a single configuration file can adapt its contents for a variety of hosts, user names, and so on. Config4* provides a trivial way to integrate command-line options with a configuration file, so it is possible to have a configuration file that adapts its contents based on the presence of a command-line option such as -env production or -env staging. For example:
env ?= ""; # set by a command-line option
if (env == "production") {
... # set variables to values for production environment
} #elseIf (env == "staging") {
... # set variables to values for staging environment
} #else {
#error "You must specify '-env production' or '-env staging' as a command-line option";
}
I can think of two possible ways that Config4* might be of help to you.
One option is for you to embed the Config4* parser in your applications. However, although I think that is a good approach when developing new applications, I think might be tedious to retrofit Config4* to an existing application (not because the Config4* is difficult to use, but just because you will be modifying existing code that uses, say, the Java properties API or an XML API to use a different API, and such modifications tend to be tedious).
The second option better fits with the specifics of your question. You write template versions of your shell scripts and property files. These template files will use a particular syntax, such as '${variable.name}' to specify where values from a configuration file should be used. You then write a small utility application that reads a template file and a configuration file, performs the required substitutions, and then writes the transformed file to disk. You could run that utility application from your build system.
You could have a look at newly announced tools4j-config which lets you handle configuration at runtime rather than build time.
In a previous answer, I outlined how Config4* could satisfy your needs. I decided to eat my own dog food, so I knocked up a ready-to-compile-and-run Config4*-based application that will do what you want. I am providing the code inline in this answer. Rather than reading the code via the StackOverview webpage, you might find it easier to copy-and-paste the code into files so you can view it with a text editor.
First, we need a configuration file that defines three variables:
deploymentType (specified as a command-line argument to have the value dev, staging or prod);
files (pairs of template files and output files);
searchAndReplace (pairs of search and replace strings to be applied to the template files to produce the output files). The pairs of strings used depend on the value of deploymentType.
Here is an example of such a file (copy-and-paste this into templates.cfg):
deploymentType ?= ""; # specified with a command-line argument
files = [
# template file output file
# ----------------------------------------------------
"log4j-template.properties", "log4j.properties",
"hello-template.sh", "hello.sh",
];
#if (deploymentType == "dev") {
searchAndReplace = [
"${db.host}", "localhost",
"${db.user}", "guest",
"${db.log.level}", "2",
];
} #elseIf (deploymentType == "staging") {
searchAndReplace = [
"${db.host}", exec("hostname"),
"${db.user}", getenv("USERNAME"),
"${db.log.level}", "0",
];
} #elseIf (deploymentType == "prod") {
searchAndReplace = [
"${db.host}", "production.example.com",
"${db.user}", getenv("USERNAME"),
"${db.log.level}", "0",
];
} #else {
#error "deploymentType must be 'dev', 'staging' or 'prod'";
}
Here is the main-line of the application. You should cut-n-paste the following into InstantiateTemplateFiles.java:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import org.config4j.Configuration;
import org.config4j.SchemaValidator;
import org.config4j.ConfigurationException;
public class InstantiateTemplateFiles
{
public static void main(String[] args)
{
Configuration cfg = Configuration.create();
SchemaValidator sv = new SchemaValidator();
String[] searchAndReplace;
String[] files;
String contents;
String modifiedContents;
String templateFile;
String outputFile;
int i;
String[] schema = new String[] {
"deploymentType = string",
"searchAndReplace=table[string,search, string,replace]",
"files=table[string,template-file, string,output-file]",
};
if (args.length != 2) {
System.err.println("\nusage: java InstantiateTemplateFiles"
+ " meta-config-file.cfg deploymentType\n");
System.exit(1);
}
try {
//--------
// Parse the configuration file, perform schema validation
// and retrieve the required configuration variables.
//--------
cfg.insertString("", "deploymentType", args[1]);
cfg.parse(args[0]);
sv.parseSchema(schema);
sv.validate(cfg, "", "");
searchAndReplace = cfg.lookupList("", "searchAndReplace");
files = cfg.lookupList("", "files");
//--------
// Do the real work
//--------
for (i = 0; i < files.length; i += 2) {
Util.searchAndReplaceInFile(files[i + 0], files[i + 1],
searchAndReplace);
}
} catch(IOException ex) {
System.err.println("\n" + ex.getMessage() + "\n");
System.exit(1);
} catch(ConfigurationException ex) {
System.err.println("\n" + ex.getMessage() + "\n");
System.exit(1);
}
}
}
Finally, here is the code to perform the search-and-replace on files. This code is independent of Config4*, so you might find it useful even if you decide to build a non-Config4*-based utility. You should cut-n-paste this code into Util.java:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Util
{
public static void searchAndReplaceInFile(
String inputFile,
String outputFile,
String[] searchAndReplacePairs) throws IOException
{
String contents;
String modifiedContents;
contents = Util.readTextFile(inputFile);
modifiedContents = Util.replace(contents, searchAndReplacePairs);
Util.writeTextFile(outputFile, modifiedContents);
}
public static String readTextFile(String fileName) throws IOException
{
BufferedReader in;
StringBuffer result;
String line;
result = new StringBuffer();
in = new BufferedReader(new FileReader(fileName));
while ((line = in.readLine()) != null) {
result.append(line).append("\n");
}
in.close();
return result.toString();
}
public static void writeTextFile(String fileName, String contents)
throws IOException
{
PrintWriter out;
StringBuffer result;
String line;
out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
out.print(contents);
out.close();
}
public static String replace(
String origStr,
String searchStr,
String replacementStr)
{
StringBuffer result;
int origStrLen;
int searchStrLen;
int currStart;
int pIndex;
result = new StringBuffer();
origStrLen = origStr.length();
searchStrLen = searchStr.length();
currStart = 0;
pIndex = origStr.indexOf(searchStr, currStart);
while (pIndex != -1) {
result.append(origStr.substring(currStart, pIndex));
result.append(replacementStr);
currStart = pIndex + searchStrLen;
pIndex = origStr.indexOf(searchStr, currStart);
}
result.append(origStr.substring(currStart));
return result.toString();
}
public static String replace(
String origStr,
String[] searchAndReplacePairs)
{
int i;
int currIndex;
String subStr;
String replaceStr;
StringBuffer result;
SearchAndReplacePair[] pairs;
SearchAndReplacePair nextPair;
pairs = new SearchAndReplacePair[searchAndReplacePairs.length / 2];
for (i = 0; i < searchAndReplacePairs.length; i += 2) {
pairs[i/2] = new SearchAndReplacePair(origStr,
searchAndReplacePairs[i + 0],
searchAndReplacePairs[i + 1]);
}
result = new StringBuffer();
currIndex = 0;
nextPair = findNextPair(origStr, currIndex, pairs);
while (nextPair != null) {
subStr = origStr.substring(currIndex, nextPair.indexOf);
result.append(subStr);
result.append(nextPair.replace);
currIndex = nextPair.indexOf + nextPair.length;
for (i = 0; i < pairs.length; i++) {
pairs[i].findNext(currIndex);
}
nextPair = findNextPair(origStr, currIndex, pairs);
}
subStr = origStr.substring(currIndex);
result.append(subStr);
return result.toString();
}
private static SearchAndReplacePair findNextPair(
String origStr,
int currIndex,
SearchAndReplacePair[] pairs)
{
int i;
SearchAndReplacePair bestSoFar;
SearchAndReplacePair item;
bestSoFar = null;
for (i = 0; i < pairs.length; i++) {
item = pairs[i];
if (item.indexOf == -1) {
continue;
}
if (bestSoFar == null) {
bestSoFar = item;
continue;
}
if (bestSoFar.indexOf < item.indexOf) {
continue;
}
if (bestSoFar.indexOf > item.indexOf) {
bestSoFar = item;
continue;
}
if (bestSoFar.length < item.length) {
bestSoFar = item;
}
}
return bestSoFar;
}
}
class SearchAndReplacePair
{
String source;
String search;
String replace;
int length;
int indexOf;
int sourceLength;
public SearchAndReplacePair(String source, String search, String replace)
{
this.source = source;
this.sourceLength = source.length();
this.search = search;
this.replace = replace;
this.length = search.length();
this.indexOf = source.indexOf(search);
}
public void findNext(int fromIndex)
{
if (indexOf == -1 || indexOf + 1 == sourceLength) {
indexOf = -1;
} else {
indexOf = source.indexOf(search, fromIndex);
}
}
}
Assuming you have downloaded and installed Config4J (from the Config4* website), you can compile the utility with the following:
CLASSPATH=.:/path/to/config4j.jar;
export CLASSPATH
javac -classpath .:/ag/projects/config4j/lib/config4j.jar *.java
Here is an example of running it:
java InstantiateTemplateFiles templates.cfg prod
If the file hello-template.sh looks like:
#!/bin/sh
DB_HOST=${db.host}
DB_USER=${db.user}
DB_LOG_LEVEL=${db.log.level}
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST
then the generated hello.sh file will look like:
#!/bin/sh
DB_HOST=production.example.com
DB_USER=cjmchale
DB_LOG_LEVEL=0
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST

Categories

Resources