summaryrefslogtreecommitdiff
path: root/gentools/src/org/apache/qpid/gentools/Generator.java
diff options
context:
space:
mode:
Diffstat (limited to 'gentools/src/org/apache/qpid/gentools/Generator.java')
-rw-r--r--gentools/src/org/apache/qpid/gentools/Generator.java439
1 files changed, 439 insertions, 0 deletions
diff --git a/gentools/src/org/apache/qpid/gentools/Generator.java b/gentools/src/org/apache/qpid/gentools/Generator.java
new file mode 100644
index 0000000000..44f15cc71a
--- /dev/null
+++ b/gentools/src/org/apache/qpid/gentools/Generator.java
@@ -0,0 +1,439 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.gentools;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public abstract class Generator implements LanguageConverter
+{
+ protected static String cr = Utils.lineSeparator;
+ protected static enum EnumConstOutputTypes { OUTPUT_STRING, OUTPUT_INTEGER, OUTPUT_DOUBLE; };
+
+ // This string is reproduced in every generated file as a comment
+ // TODO: Tie the version info into the build system.
+ protected static final String generatorInfo = "Qpid Gentools v.0.1";
+ protected static final int templateFileNameIndex = 0;
+ protected static final int templateStringIndex = 1;
+
+ protected ArrayList<String[]> modelTemplateList;
+ protected ArrayList<String[]> classTemplateList;
+ protected ArrayList<String[]> methodTemplateList;
+ protected ArrayList<String[]> fieldTemplateList;
+ protected String genDir;
+
+ protected AmqpVersionSet globalVersionSet;
+ protected AmqpDomainMap globalDomainMap;
+ protected AmqpConstantSet globalConstantSet;
+ protected AmqpModel model;
+
+ protected int generatedFileCounter;
+
+ public Generator(AmqpVersionSet versionList)
+ {
+ this.globalVersionSet = versionList;
+ modelTemplateList = new ArrayList<String[]>();
+ classTemplateList = new ArrayList<String[]>();
+ methodTemplateList = new ArrayList<String[]>();
+ fieldTemplateList = new ArrayList<String[]>();
+ generatedFileCounter = 0;
+ }
+
+ public int getNumberGeneratedFiles()
+ {
+ return generatedFileCounter;
+ }
+
+ public void setDomainMap(AmqpDomainMap domainMap)
+ {
+ this.globalDomainMap = domainMap;
+ }
+
+ public AmqpDomainMap getDomainMap()
+ {
+ return globalDomainMap;
+ }
+
+ public void setConstantSet(AmqpConstantSet constantSet)
+ {
+ this.globalConstantSet = constantSet;
+ }
+
+ public AmqpConstantSet getConstantSet()
+ {
+ return globalConstantSet;
+ }
+
+ public void setModel(AmqpModel model)
+ {
+ this.model = model;
+ }
+
+ public AmqpModel getModel()
+ {
+ return model;
+ }
+
+ public void initializeTemplates(File[] modelTemplateFiles, File[] classTemplatesFiles,
+ File[] methodTemplatesFiles, File[] fieldTemplatesFiles)
+ throws FileNotFoundException, IOException
+ {
+ if (modelTemplateFiles.length > 0)
+ {
+ System.out.println("Model template file(s):");
+ for (File mtf : modelTemplateFiles)
+ {
+ System.out.println(" " + mtf.getAbsolutePath());
+ String template[] = {mtf.getName(), loadTemplate(mtf)};
+ modelTemplateList.add(template);
+ }
+ }
+ if (classTemplatesFiles.length > 0)
+ {
+ System.out.println("Class template file(s):");
+ //for (int c=0; c<classTemplatesFiles.length; c++)
+ for (File ctf : classTemplatesFiles)
+ {
+ System.out.println(" " + ctf.getAbsolutePath());
+ String template[] = {ctf.getName(), loadTemplate(ctf)};
+ classTemplateList.add(template);
+ }
+ }
+ if (methodTemplatesFiles.length > 0)
+ {
+ System.out.println("Method template file(s):");
+ for (File mtf : methodTemplatesFiles)
+ {
+ System.out.println(" " + mtf.getAbsolutePath());
+ String template[] = {mtf.getName(), loadTemplate(mtf)};
+ methodTemplateList.add(template);
+ }
+ }
+ if (fieldTemplatesFiles.length > 0)
+ {
+ System.out.println("Field template file(s):");
+ for (File ftf : fieldTemplatesFiles)
+ {
+ System.out.println(" " + ftf.getAbsolutePath());
+ String template[] = {ftf.getName(), loadTemplate(ftf)};
+ fieldTemplateList.add(template);
+ }
+ }
+ }
+
+ abstract protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field);
+
+ abstract protected String processToken(String token, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, AmqpVersion version)
+ throws AmqpTemplateException, AmqpTypeMappingException;
+
+ abstract protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpModel model)
+ throws AmqpTemplateException, AmqpTypeMappingException;
+
+ abstract protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpClass thisClass)
+ throws AmqpTemplateException, AmqpTypeMappingException;
+
+ abstract protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpFieldMap fieldMap, AmqpVersion version)
+ throws AmqpTypeMappingException, AmqpTemplateException, IllegalAccessException,
+ InvocationTargetException;
+
+ abstract protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpConstantSet constantSet)
+ throws AmqpTemplateException, AmqpTypeMappingException;
+
+ public void generate(File genDir)
+ throws TargetDirectoryException, IOException, AmqpTypeMappingException,
+ AmqpTemplateException, IllegalAccessException, InvocationTargetException
+ {
+ prepareTargetDirectory(genDir, true);
+ System.out.println("Generation directory: " + genDir.getAbsolutePath());
+ this.genDir = genDir.getAbsolutePath();
+
+ // Use all model-level templates
+ for (String[] mt : modelTemplateList)
+ {
+ processTemplateA(mt);
+ }
+
+ // Cycle through classes
+ Iterator<String> citr = model.classMap.keySet().iterator();
+ while (citr.hasNext())
+ {
+ String className = citr.next();
+ AmqpClass thisClass = model.classMap.get(className);
+
+ // Use all class-level templates
+ for (String[] ct : classTemplateList)
+ {
+ processTemplateB(ct, thisClass);
+ }
+
+ // Cycle through all methods
+ Iterator<String> mitr = thisClass.methodMap.keySet().iterator();
+ while (mitr.hasNext())
+ {
+ String methodName = mitr.next();
+ AmqpMethod method = thisClass.methodMap.get(methodName);
+
+ // Use all method-level templates
+ for (String[] mt : methodTemplateList)
+ {
+ processTemplateC(mt, thisClass, method);
+ }
+
+ // Cycle through all fields
+ Iterator<String> fitr = method.fieldMap.keySet().iterator();
+ while (fitr.hasNext())
+ {
+ String fieldName = fitr.next();
+ AmqpField field = method.fieldMap.get(fieldName);
+
+ // Use all field-level templates
+ for (String[] ft : fieldTemplateList)
+ {
+ processTemplateD(ft, thisClass, method, field);
+ }
+ }
+ }
+ }
+ }
+
+ protected void processVersionList(StringBuffer sb, int tokStart, int tokEnd)
+ throws AmqpTypeMappingException
+ {
+ int lend = sb.indexOf(Utils.lineSeparator, tokStart) + 1; // Include cr at end of line
+ String tline = sb.substring(tokEnd, lend); // Line excluding line marker, including cr
+ sb.delete(tokStart, lend);
+
+ for (AmqpVersion v : globalVersionSet)
+ {
+ // Insert copy of target line
+ StringBuffer isb = new StringBuffer(tline);
+ if (isb.indexOf("${protocol-version-list-entry}") >= 0)
+ {
+ String versionListEntry = " { ${major}, ${minor} }" +
+ (v.equals(globalVersionSet.last()) ? "" : ",");
+ replaceToken(isb, "${protocol-version-list-entry}", String.valueOf(versionListEntry));
+ }
+ if (isb.indexOf("${major}") >= 0)
+ replaceToken(isb, "${major}", String.valueOf(v.getMajor()));
+ if (isb.indexOf("${minor}") >= 0)
+ replaceToken(isb, "${minor}", String.valueOf(v.getMinor()));
+ sb.insert(tokStart, isb.toString());
+ tokStart += isb.length();
+ }
+ }
+
+ // Model-level template processing
+ abstract protected void processTemplateA(String[] template)
+ throws IOException, AmqpTemplateException, AmqpTypeMappingException,
+ IllegalAccessException, InvocationTargetException;
+
+ // Class-level template processing
+ abstract protected void processTemplateB(String[] template, AmqpClass thisClass)
+ throws IOException, AmqpTemplateException, AmqpTypeMappingException,
+ IllegalAccessException, InvocationTargetException;
+
+ // Method-level template processing
+ abstract protected void processTemplateC(String[] template, AmqpClass thisClass,
+ AmqpMethod method)
+ throws IOException, AmqpTemplateException, AmqpTypeMappingException,
+ IllegalAccessException, InvocationTargetException;
+
+ // Field-level template processing
+ abstract protected void processTemplateD(String[] template, AmqpClass thisClass,
+ AmqpMethod method, AmqpField field)
+ throws IOException, AmqpTemplateException, AmqpTypeMappingException,
+ IllegalAccessException, InvocationTargetException;
+
+ // Helper functions common to all generators
+
+ protected static void prepareTargetDirectory(File dir, boolean createFlag)
+ throws TargetDirectoryException
+ {
+ if (dir.exists())
+ {
+ if (!dir.isDirectory())
+ throw new TargetDirectoryException("\"" + dir.getAbsolutePath() +
+ "\" exists, but is not a directory.");
+ }
+ else if (createFlag) // Create dir
+ {
+ if(!dir.mkdirs())
+ throw new TargetDirectoryException("Unable to create directory \"" +
+ dir.getAbsolutePath() + "\".");
+ }
+ else
+ throw new TargetDirectoryException("Directory \"" + dir.getAbsolutePath() +
+ "\" not found.");
+
+ }
+
+ protected void processAllLists(StringBuffer sb, AmqpClass thisClass, AmqpMethod method, AmqpVersion version)
+ throws AmqpTemplateException, AmqpTypeMappingException, IllegalAccessException,
+ InvocationTargetException
+ {
+ int lstart = sb.indexOf("%{");
+ while (lstart != -1)
+ {
+ int lend = sb.indexOf("}", lstart + 2);
+ if (lend > 0)
+ {
+ String listToken = sb.substring(lstart + 2, lend);
+ if (listToken.compareTo("VLIST") == 0)
+ {
+ processVersionList(sb, lstart, lend + 1);
+ }
+ else if (listToken.compareTo("CLIST") == 0)
+ {
+ processClassList(sb, lstart, lend + 1, model);
+ }
+ else if (listToken.compareTo("MLIST") == 0)
+ {
+ processMethodList(sb, lstart, lend + 1, thisClass);
+ }
+ else if (listToken.compareTo("FLIST") == 0)
+ {
+ // Pass the FieldMap from either a class or a method.
+ // If this is called from a class-level template, we assume that the
+ // class field list is required. In this case, method will be null.
+ processFieldList(sb, lstart, lend + 1,
+ (method == null ? thisClass.fieldMap : method.fieldMap),
+ version);
+ }
+ else if (listToken.compareTo("TLIST") == 0)
+ {
+ processConstantList(sb, lstart, lend + 1, globalConstantSet);
+ }
+ else
+ {
+ throw new AmqpTemplateException("Unknown list token \"%{" + listToken +
+ "}\" found in template at index " + lstart + ".");
+ }
+ }
+ lstart = sb.indexOf("%{", lstart + 1);
+ }
+ }
+
+ protected void processAllTokens(StringBuffer sb, AmqpClass thisClass, AmqpMethod method, AmqpField field,
+ AmqpVersion version)
+ throws AmqpTemplateException, AmqpTypeMappingException
+ {
+ int lstart = sb.indexOf("${");
+ while (lstart != -1)
+ {
+ int lend = sb.indexOf("}", lstart + 2);
+ if (lend > 0)
+ {
+ String token = sb.substring(lstart, lend + 1);
+ replaceToken(sb, lstart, token, processToken(token, thisClass, method, field, version));
+ }
+ lstart = sb.indexOf("${", lstart);
+ }
+ }
+
+ protected static void writeTargetFile(StringBuffer sb, File f)
+ throws IOException
+ {
+ FileWriter fw = new FileWriter(f);
+ fw.write(sb.toString().toCharArray());
+ fw.flush();
+ fw.close();
+ }
+
+ protected static String getTemplateFileName(StringBuffer sb)
+ throws AmqpTemplateException
+ {
+ if (sb.charAt(0) != '&')
+ throw new AmqpTemplateException("No filename marker &{filename} found at start of template.");
+ int cr = sb.indexOf(Utils.lineSeparator);
+ if (cr < 0)
+ throw new AmqpTemplateException("Bad template structure - unable to find first line.");
+ String fileName = sb.substring(2, cr-1);
+ sb.delete(0, cr + 1);
+ return fileName;
+ }
+
+ protected static void replaceToken(StringBuffer sb, String token, String replacement)
+ {
+ replaceToken(sb, 0, token, replacement);
+ }
+
+ protected static void replaceToken(StringBuffer sb, int index, String token, String replacement)
+ {
+ if (replacement != null)
+ {
+ int start = sb.indexOf(token, index);
+ int len = token.length();
+ // Find first letter in token and determine if it is capitalized
+ char firstTokenLetter = getFirstLetter(token);
+ if (firstTokenLetter != 0 && Character.isUpperCase(firstTokenLetter))
+ sb.replace(start, start+len, Utils.firstUpper(replacement));
+ else
+ sb.replace(start, start+len, replacement);
+ }
+ }
+
+ private static char getFirstLetter(String str)
+ {
+ int len = str.length();
+ int index = 0;
+ char tokChar = str.charAt(index);
+ while (!Character.isLetter(tokChar) && index<len-1)
+ tokChar = str.charAt(++index);
+ if (Character.isLetter(tokChar))
+ return tokChar;
+ return 0;
+ }
+
+ private static String loadTemplate(File f)
+ throws FileNotFoundException, IOException
+ {
+ StringBuffer sb = new StringBuffer();
+ FileReader fr = new FileReader(f);
+ LineNumberReader lnr = new LineNumberReader(fr);
+ String line = lnr.readLine();
+ while (line != null)
+ {
+ // Strip lines starting with '#' in template - treat these lines as template comments
+// if (line.length() > 0 && line.charAt(0) != '#') // Bad idea - '#' used in C/C++ files (#include)!
+ if (line.length() > 0)
+ sb.append(line + Utils.lineSeparator);
+ else
+ sb.append(Utils.lineSeparator);
+ line = lnr.readLine();
+ }
+ lnr.close();
+ fr.close();
+ return sb.toString();
+ }
+}