You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ai...@apache.org on 2008/04/24 03:54:42 UTC
svn commit: r651133 [2/17] - in /incubator/qpid/trunk/qpid: gentools/
gentools/src/org/apache/qpid/gentools/ java/ java/broker/
java/broker/src/main/grammar/
java/broker/src/main/java/org/apache/qpid/server/exchange/
java/broker/src/main/java/org/apach...
Modified: incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/Generator.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/Generator.java?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/Generator.java (original)
+++ incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/Generator.java Wed Apr 23 18:54:20 2008
@@ -1,848 +1,857 @@
-/*
- *
- * 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 org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.Velocity;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.LineNumberReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-
-public abstract class Generator implements LanguageConverter
-{
- protected static String CR = Utils.LINE_SEPARATOR;
-
-
- private static final Map<String, Integer> FIXED_SIZE_TYPES = new HashMap<String, Integer>();
-
- static
- {
- FIXED_SIZE_TYPES.put("bit", 1);
- FIXED_SIZE_TYPES.put("bitfield", 1);
- FIXED_SIZE_TYPES.put("long", 4);
- FIXED_SIZE_TYPES.put("longlong", 8);
- FIXED_SIZE_TYPES.put("octet", 1);
- FIXED_SIZE_TYPES.put("short", 2);
- FIXED_SIZE_TYPES.put("timestamp", 8);
-
- }
-
- private String _templateDirectory;
- private String _outputDirectory;
-
- public AmqpDomainMap getDomainMap()
- {
- return _domainMap;
- }
-
- public AmqpConstantSet getConstantSet()
- {
- return _constantSet;
- }
-
- public AmqpModel getModel()
- {
- return _model;
- }
-
- abstract public String getNativeType(String type);
-
- abstract public String getEncodingType(String type);
-
-
-
- protected static enum EnumConstOutputTypes
- {
- OUTPUT_STRING,
- OUTPUT_INTEGER,
- OUTPUT_DOUBLE;
- }
-
- ;
-
- public static enum TemplateType
- {
- model("model"),
- clazz("class"),
- method("method"),
- field("field");
-
- private final String _name;
-
- private TemplateType(String name)
- {
- _name = name;
- }
-
- public String getName()
- {
- return _name;
- }
- }
-
- ;
-
-
- public static interface Factory<X extends Generator>
- {
- public X newInstance();
- }
-
-
- protected static final class NamedTemplate
- {
- private final String _name;
- private final String _template;
- private final File _file;
-
-
- public NamedTemplate(String relativePath, File templateFile)
- {
- _file = templateFile;
- _name = relativePath + Utils.FILE_SEPARATOR + templateFile.getName();
-
- _template = loadTemplate(templateFile);
- }
-
-
- public String getName()
- {
- return _name;
- }
-
- public String getTemplate()
- {
- return _template;
- }
-
-
- public File getFile()
- {
- return _file;
- }
-
- }
-
-
- private static final String VELOCITY_TEMPLATE_SUFFIX = ".vm";
- private static final String STANDARD_TEMPLATE_SUFFIX = ".tmpl";
- private static FilenameFilter _tmplFileFilter = new FilenameFilter()
- {
-
- public boolean accept(File dir, String name)
- {
- return name.endsWith(STANDARD_TEMPLATE_SUFFIX) || name.endsWith(VELOCITY_TEMPLATE_SUFFIX);
- }
- };
-
-
- // This string is reproduced in every generated file as a comment
- // TODO: Tie the version info into the build system.
- protected static final String GENERATOR_INFO = "Qpid Gentools v.0.1";
-
-
- private final Map<TemplateType, Collection<NamedTemplate>> _templates =
- new EnumMap<TemplateType, Collection<NamedTemplate>>(TemplateType.class);
-
- private final Map<TemplateType, Collection<NamedTemplate>> _versionSpecificTemplates =
- new EnumMap<TemplateType, Collection<NamedTemplate>>(TemplateType.class);
-
-
- private final AmqpVersionSet _versionSet;
-
- private final AmqpDomainMap _domainMap;
- private final Map<AmqpVersion, AmqpDomainMap> _versionToDomainMapMap = new HashMap<AmqpVersion, AmqpDomainMap>();
-
- private final AmqpConstantSet _constantSet;
- private final Map<AmqpVersion, AmqpConstantSet> _versionToConstantSetMap = new HashMap<AmqpVersion, AmqpConstantSet>();
-
-
- public AmqpVersionSet getVersionSet()
- {
- return _versionSet;
- }
-
- private final AmqpModel _model;
- private final Map<AmqpVersion, AmqpModel> _versionToModelMap = new HashMap<AmqpVersion, AmqpModel>();
-
- protected int generatedFileCounter;
-
- public Generator()
- {
- _versionSet = new AmqpVersionSet();
- _model = new AmqpModel(this);
- _constantSet = new AmqpConstantSet(this);
- _domainMap = new AmqpDomainMap(this);
-
- generatedFileCounter = 0;
- }
-
-// public final AmqpVersionSet getVersionSet()
-// {
-// return _versionSet;
-// }
-
-
- public void addVersion(AmqpVersion version)
- {
- _versionSet.add(version);
- if (!_versionToModelMap.containsKey(version))
- {
- _versionToModelMap.put(version, new AmqpModel(this));
- }
- if (!_versionToDomainMapMap.containsKey(version))
- {
- _versionToDomainMapMap.put(version, new AmqpDomainMap(this));
- }
- if (!_versionToConstantSetMap.containsKey(version))
- {
- _versionToConstantSetMap.put(version, new AmqpConstantSet(this));
- }
- }
-
- public int getNumberGeneratedFiles()
- {
- return generatedFileCounter;
- }
-
-// public AmqpDomainMap getDomainMap()
-// {
-// return _domainMap;
-// }
-//
-// public AmqpConstantSet getConstantSet()
-// {
-// return _constantSet;
-// }
-//
-//
-// public AmqpModel getModel()
-// {
-// return _model;
-// }
-
- public void initializeTemplates() throws IOException
- {
-
- for (TemplateType type : EnumSet.allOf(TemplateType.class))
- {
- ArrayList<NamedTemplate> typeTemplates = new ArrayList<NamedTemplate>();
- _templates.put(type, typeTemplates);
- ArrayList<NamedTemplate> versionSpecificTypeTemplates = new ArrayList<NamedTemplate>();
- _versionSpecificTemplates.put(type, versionSpecificTypeTemplates);
-
- File templateDirectory = new File(getTemplateDirectory() + Utils.FILE_SEPARATOR + type.getName());
- File versionTemplateDirectory = new File(getTemplateDirectory() + Utils.FILE_SEPARATOR + type.getName() + Utils.FILE_SEPARATOR + "version");
-
- File[] templateFiles = templateDirectory.listFiles(_tmplFileFilter);
-
- File[] versionTemplateFiles = new File[0];
- if (versionTemplateDirectory.exists())
- {
- versionTemplateFiles = versionTemplateDirectory.listFiles(_tmplFileFilter);
- }
-
- if(templateFiles != null)
- {
- for (File templateFile : templateFiles)
- {
- System.out.println(type.getName() + " template file(s):");
- System.out.println(" " + templateFile.getCanonicalPath());
- typeTemplates.add(new NamedTemplate(type.getName(), templateFile));
- }
- }
-
- if(versionTemplateFiles != null)
- {
- for (File versionTemplateFile : versionTemplateFiles)
- {
- System.out.println(type.getName() + " template file(s):");
- System.out.println(" " + versionTemplateFile.getCanonicalPath());
- versionSpecificTypeTemplates.add(new NamedTemplate(type.getName() + Utils.FILE_SEPARATOR + "version", versionTemplateFile));
- }
- }
-
- }
- }
-
- public String getTemplateDirectory()
- {
- return _templateDirectory;
- }
-
-
- public void setTemplateDirectory(String templateDirectory)
- {
- _templateDirectory = templateDirectory;
- }
-
-
- public void setOutputDirectory(String outputDirectory)
- {
- _outputDirectory = outputDirectory;
- }
-
- public void generate()
- {
- prepareTargetDirectory(new File(_outputDirectory), true);
- System.out.println("Generation directory: " + _outputDirectory);
-
-
- processModelTemplates(_templates);
-
- for (AmqpClass amqpClass : _model.getClassMap().values())
- {
- processClassTemplates(_templates, amqpClass);
-
- for (AmqpMethod amqpMethod : amqpClass.getMethodMap().values())
- {
- processMethodTemplates(_templates, amqpClass, amqpMethod);
-
- for (AmqpField amqpField : amqpMethod.getFieldMap().values())
- {
- processFieldTemplates(_templates, amqpClass, amqpMethod, amqpField, null);
- }
- }
- }
-
-
- for (AmqpVersion version : _versionSet)
- {
- AmqpModel model = _versionToModelMap.get(version);
- processModelTemplates(_versionSpecificTemplates, version);
-
- for (AmqpClass amqpClass : model.getClassMap().values())
- {
- processClassTemplates(_versionSpecificTemplates, amqpClass, version);
-
- for (AmqpMethod amqpMethod : amqpClass.getMethodMap().values())
- {
- processMethodTemplates(_versionSpecificTemplates, amqpClass, amqpMethod, version);
-
- for (AmqpField amqpField : amqpMethod.getFieldMap().values())
- {
- processFieldTemplates(_versionSpecificTemplates, amqpClass, amqpMethod, amqpField, version);
- }
- }
- }
-
- }
- }
-
- private void processMethodTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpVersion version)
- {
- for (NamedTemplate template : templates.get(TemplateType.method))
- {
- if(isVelocityTemplate(template))
- {
- processVelocityTemplate(template,version,amqpClass,amqpMethod,null);
- }
- else
- {
- processMethodTemplate(template, amqpClass, amqpMethod);
- }
- }
-
- }
-
- private void processClassTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpVersion version)
- {
- for (NamedTemplate template : templates.get(TemplateType.clazz))
- {
- if(isVelocityTemplate(template))
- {
- processVelocityTemplate(template,version,amqpClass,null,null);
- }
- else
- {
- processClassTemplate(template, amqpClass);
- }
- }
-
- }
-
-
- private void processModelTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpVersion version)
- {
- for (NamedTemplate template : templates.get(TemplateType.model))
- {
- if (isVelocityTemplate(template))
- {
- processModelVelocityTemplate(template, version);
- }
- else
- {
- processModelTemplate(template, version);
- }
- }
- }
-
- abstract void processModelTemplate(NamedTemplate template, AmqpVersion version);
-
-
- protected void processModelTemplates(Map<TemplateType, Collection<NamedTemplate>> templates)
- {
- for (NamedTemplate template : templates.get(TemplateType.model))
- {
- if (isVelocityTemplate(template))
- {
- processModelVelocityTemplate(template, null);
- }
- else
- {
- processModelTemplate(template);
- }
- }
- }
-
- private boolean isVelocityTemplate(NamedTemplate template)
- {
- return template.getName().endsWith(VELOCITY_TEMPLATE_SUFFIX);
- }
-
- private void processModelVelocityTemplate(NamedTemplate template, AmqpVersion version)
- {
- processVelocityTemplate(template,version,null,null,null);
- }
-
- private void processVelocityTemplate(NamedTemplate template, AmqpVersion version,
- AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpField amqpField)
- {
-
- VelocityContext context = new VelocityContext();
-
- AmqpModel model = _model;
- if(version != null)
- {
- model = _versionToModelMap.get(version);
- }
- context.put("model", model);
- context.put("generator", GENERATOR_INFO);
-
- if (version != null)
- {
- context.put("version", version);
- }
- if(amqpClass != null)
- {
- context.put("amqpClass", amqpClass);
- }
-
- if(amqpClass != null)
- {
- context.put("amqpMethod", amqpMethod);
- }
-
-
- StringWriter sw = new StringWriter();
-
-
- try
- {
- Template velocityTemplate = Velocity.getTemplate(template.getName());
- velocityTemplate.merge(context, sw);
- String filename = String.valueOf(context.get("filename"));
- FileWriter outputFileWriter = new FileWriter(getOutputDirectory() + Utils.FILE_SEPARATOR + filename);
- outputFileWriter.append(sw.toString());
- outputFileWriter.close();
-
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
-
-
- }
-
-
- protected void processClassTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass)
- {
- for (NamedTemplate template : templates.get(TemplateType.clazz))
- {
- if(isVelocityTemplate(template))
- {
- processVelocityTemplate(template,null,amqpClass,null,null);
- }
- else
- {
- processClassTemplate(template, amqpClass);
- }
- }
- }
-
- protected void processMethodTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpMethod amqpMethod)
- {
- for (NamedTemplate template : templates.get(TemplateType.method))
- {
- if(isVelocityTemplate(template))
- {
- processVelocityTemplate(template,null,amqpClass,amqpMethod,null);
- }
- else
- {
- processMethodTemplate(template, amqpClass, amqpMethod);
- }
- }
- }
-
-
- protected void processFieldTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpField amqpField, AmqpVersion amqpVersion)
- {
- for (NamedTemplate template : templates.get(TemplateType.field))
- {
- if(isVelocityTemplate(template))
- {
- processVelocityTemplate(template,amqpVersion,amqpClass,amqpMethod,amqpField);
- }
- else
- {
- processTemplate(template, amqpClass, amqpMethod, amqpField, amqpVersion);
- }
- }
- }
-
-
- protected void processVersionList(StringBuffer sb, int tokStart, int tokEnd)
- {
- int lend = sb.indexOf(Utils.LINE_SEPARATOR, 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 : _versionSet)
- {
- // Insert copy of target line
- StringBuffer isb = new StringBuffer(tline);
- if (isb.indexOf("${protocol-version-list-entry}") >= 0)
- {
- String versionListEntry = " { ${major}, ${minor} }" +
- (v.equals(_versionSet.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();
- }
- }
-
- // Helper functions common to all generators
-
- protected static void prepareTargetDirectory(File dir, boolean createFlag)
- {
- 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)
- {
- AmqpModel model = (version == null) ? _model : _versionToModelMap.get(version);
-
-
- 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, version);
- }
- 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.getFieldMap() : method.getFieldMap()),
- version);
- }
- else if (listToken.compareTo("TLIST") == 0)
- {
- processConstantList(sb, lstart, lend + 1, _constantSet);
- }
- 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)
- {
- 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)
- {
- try
- {
- f.getParentFile().mkdirs();
- FileWriter fw = new FileWriter(f);
- fw.write(sb.toString().toCharArray());
- fw.flush();
- fw.close();
- }
- catch (IOException e)
- {
- throw new AmqpTemplateException(e.getMessage());
- }
- }
-
-
- protected static String getTemplateFileName(StringBuffer sb)
- {
- if (sb.charAt(0) != '&')
- {
- throw new AmqpTemplateException("No filename marker &{filename} found at start of template.");
- }
- int cr = sb.indexOf(Utils.LINE_SEPARATOR);
- 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);
- if (start != -1)
- {
- 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)
- {
- try
- {
- StringBuffer sb = new StringBuffer();
- FileReader fr = new FileReader(f);
- LineNumberReader lnr = new LineNumberReader(fr);
- String line = lnr.readLine();
- while (line != null)
- {
-
- sb.append(line);
- sb.append(Utils.LINE_SEPARATOR);
-
- line = lnr.readLine();
- }
- lnr.close();
- fr.close();
- return sb.toString();
- }
- catch (FileNotFoundException e)
- {
- throw new AmqpTemplateException("File not found: " + e.getMessage());
- }
- catch (IOException e)
- {
- throw new AmqpTemplateException("IOException: " + e.getMessage());
- }
- }
-
- public String getDomainType(String domainName, AmqpVersion version)
- {
- if (version == null)
- {
- version = _versionSet.first();
- }
- return getDomainMap().getDomainType(domainName, version);
- }
-
-
- public void addFromNode(Node amqpNode, AmqpVersion version)
- {
- // 1c. Extract domains
- getConstantSet().addFromNode(amqpNode, 0, version);
- _versionToConstantSetMap.get(version).addFromNode(amqpNode, 0, version);
-
- // 1d. Extract domains
- getDomainMap().addFromNode(amqpNode, 0, version);
- _versionToDomainMapMap.get(version).addFromNode(amqpNode, 0, version);
-
- // 1e. Extract class/method/field heirarchy
- getModel().addFromNode(amqpNode, 0, version);
- _versionToModelMap.get(version).addFromNode(amqpNode, 0, version);
- }
-
-
- public String getOutputDirectory()
- {
- return _outputDirectory;
- }
-
- public String prepareConstantName(String constantName)
- {
- return prepareDomainName(constantName);
- }
-
-
- public boolean isFixedSizeType(String type)
- {
- return FIXED_SIZE_TYPES.containsKey(type);
- }
-
-
- public int getTypeSize(String type)
- {
- return FIXED_SIZE_TYPES.get(type);
- }
-
-
-
- // Model-level template processing
- abstract protected void processModelTemplate(NamedTemplate template);
-
- // Class-level template processing
- abstract protected void processClassTemplate(NamedTemplate template, AmqpClass thisClass);
-
- // Method-level template processing
- abstract protected void processMethodTemplate(NamedTemplate template, AmqpClass thisClass,
- AmqpMethod method);
-
- // Field-level template processing
- abstract protected void processTemplate(NamedTemplate template, AmqpClass thisClass,
- AmqpMethod method, AmqpField field, AmqpVersion version);
-
- abstract protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method,
- AmqpField field, AmqpVersion version);
-
- abstract protected String processToken(String token, AmqpClass thisClass, AmqpMethod method,
- AmqpField field, AmqpVersion version);
-
- abstract protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
- AmqpModel model, AmqpVersion version);
-
- abstract protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
- AmqpClass thisClass);
-
-
- abstract protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
- AmqpFieldMap fieldMap, AmqpVersion version);
-
- abstract protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
- AmqpConstantSet constantSet);
-
-
-}
+/*
+ *
+ * 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 org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.w3c.dom.Node;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class Generator implements LanguageConverter
+{
+ protected static String CR = Utils.LINE_SEPARATOR;
+
+
+ private static final Map<String, Integer> FIXED_SIZE_TYPES = new HashMap<String, Integer>();
+
+ static
+ {
+ FIXED_SIZE_TYPES.put("bit", 1);
+ FIXED_SIZE_TYPES.put("bitfield", 1);
+ FIXED_SIZE_TYPES.put("long", 4);
+ FIXED_SIZE_TYPES.put("longlong", 8);
+ FIXED_SIZE_TYPES.put("octet", 1);
+ FIXED_SIZE_TYPES.put("short", 2);
+ FIXED_SIZE_TYPES.put("timestamp", 8);
+
+ }
+
+ private String _templateDirectory;
+ private String _outputDirectory;
+
+ public AmqpDomainMap getDomainMap()
+ {
+ return _domainMap;
+ }
+
+ public AmqpConstantSet getConstantSet()
+ {
+ return _constantSet;
+ }
+
+ public AmqpModel getModel()
+ {
+ return _model;
+ }
+
+ abstract public String getNativeType(String type);
+
+ abstract public String getEncodingType(String type);
+
+
+
+ protected static enum EnumConstOutputTypes
+ {
+ OUTPUT_STRING,
+ OUTPUT_INTEGER,
+ OUTPUT_DOUBLE;
+ }
+
+ ;
+
+ public static enum TemplateType
+ {
+ model("model"),
+ clazz("class"),
+ method("method"),
+ field("field");
+
+ private final String _name;
+
+ private TemplateType(String name)
+ {
+ _name = name;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+ }
+
+ ;
+
+
+ public static interface Factory<X extends Generator>
+ {
+ public X newInstance();
+ }
+
+
+ protected static final class NamedTemplate
+ {
+ private final String _name;
+ private final String _template;
+ private final File _file;
+
+
+ public NamedTemplate(String relativePath, File templateFile)
+ {
+ _file = templateFile;
+ _name = relativePath + Utils.FILE_SEPARATOR + templateFile.getName();
+
+ _template = loadTemplate(templateFile);
+ }
+
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String getTemplate()
+ {
+ return _template;
+ }
+
+
+ public File getFile()
+ {
+ return _file;
+ }
+
+ }
+
+
+ private static final String VELOCITY_TEMPLATE_SUFFIX = ".vm";
+ private static final String STANDARD_TEMPLATE_SUFFIX = ".tmpl";
+ private static FilenameFilter _tmplFileFilter = new FilenameFilter()
+ {
+
+ public boolean accept(File dir, String name)
+ {
+ return name.endsWith(STANDARD_TEMPLATE_SUFFIX) || name.endsWith(VELOCITY_TEMPLATE_SUFFIX);
+ }
+ };
+
+
+ // This string is reproduced in every generated file as a comment
+ // TODO: Tie the version info into the build system.
+ protected static final String GENERATOR_INFO = "Qpid Gentools v.0.1";
+
+
+ private final Map<TemplateType, Collection<NamedTemplate>> _templates =
+ new EnumMap<TemplateType, Collection<NamedTemplate>>(TemplateType.class);
+
+ private final Map<TemplateType, Collection<NamedTemplate>> _versionSpecificTemplates =
+ new EnumMap<TemplateType, Collection<NamedTemplate>>(TemplateType.class);
+
+
+ private final AmqpVersionSet _versionSet;
+
+ private final AmqpDomainMap _domainMap;
+ private final Map<AmqpVersion, AmqpDomainMap> _versionToDomainMapMap = new HashMap<AmqpVersion, AmqpDomainMap>();
+
+ private final AmqpConstantSet _constantSet;
+ private final Map<AmqpVersion, AmqpConstantSet> _versionToConstantSetMap = new HashMap<AmqpVersion, AmqpConstantSet>();
+
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ private final AmqpModel _model;
+ private final Map<AmqpVersion, AmqpModel> _versionToModelMap = new HashMap<AmqpVersion, AmqpModel>();
+
+ protected int generatedFileCounter;
+
+ public Generator()
+ {
+ _versionSet = new AmqpVersionSet();
+ _model = new AmqpModel(this);
+ _constantSet = new AmqpConstantSet(this);
+ _domainMap = new AmqpDomainMap(this);
+
+ generatedFileCounter = 0;
+ }
+
+// public final AmqpVersionSet getVersionSet()
+// {
+// return _versionSet;
+// }
+
+
+ public void addVersion(AmqpVersion version)
+ {
+ _versionSet.add(version);
+ if (!_versionToModelMap.containsKey(version))
+ {
+ _versionToModelMap.put(version, new AmqpModel(this));
+ }
+ if (!_versionToDomainMapMap.containsKey(version))
+ {
+ _versionToDomainMapMap.put(version, new AmqpDomainMap(this));
+ }
+ if (!_versionToConstantSetMap.containsKey(version))
+ {
+ _versionToConstantSetMap.put(version, new AmqpConstantSet(this));
+ }
+ }
+
+ public int getNumberGeneratedFiles()
+ {
+ return generatedFileCounter;
+ }
+
+// public AmqpDomainMap getDomainMap()
+// {
+// return _domainMap;
+// }
+//
+// public AmqpConstantSet getConstantSet()
+// {
+// return _constantSet;
+// }
+//
+//
+// public AmqpModel getModel()
+// {
+// return _model;
+// }
+
+ public void initializeTemplates() throws IOException
+ {
+
+ for (TemplateType type : EnumSet.allOf(TemplateType.class))
+ {
+ ArrayList<NamedTemplate> typeTemplates = new ArrayList<NamedTemplate>();
+ _templates.put(type, typeTemplates);
+ ArrayList<NamedTemplate> versionSpecificTypeTemplates = new ArrayList<NamedTemplate>();
+ _versionSpecificTemplates.put(type, versionSpecificTypeTemplates);
+
+ File templateDirectory = new File(getTemplateDirectory() + Utils.FILE_SEPARATOR + type.getName());
+ File versionTemplateDirectory = new File(getTemplateDirectory() + Utils.FILE_SEPARATOR + type.getName() + Utils.FILE_SEPARATOR + "version");
+
+ System.out.println("Looking for template files in directory: " + templateDirectory.getAbsoluteFile());
+
+ File[] templateFiles = templateDirectory.listFiles(_tmplFileFilter);
+
+ File[] versionTemplateFiles = new File[0];
+
+ System.out.println("Looking for version specific template files in directory: " + versionTemplateDirectory.getAbsoluteFile());
+
+ if (versionTemplateDirectory.exists())
+ {
+ versionTemplateFiles = versionTemplateDirectory.listFiles(_tmplFileFilter);
+ }
+
+ if(templateFiles != null)
+ {
+ for (File templateFile : templateFiles)
+ {
+ System.out.println(type.getName() + " template file(s):");
+ System.out.println(" " + templateFile.getCanonicalPath());
+ typeTemplates.add(new NamedTemplate(type.getName(), templateFile));
+ }
+ }
+
+ if(versionTemplateFiles != null)
+ {
+ for (File versionTemplateFile : versionTemplateFiles)
+ {
+ System.out.println(type.getName() + " template file(s):");
+ System.out.println(" " + versionTemplateFile.getCanonicalPath());
+ versionSpecificTypeTemplates.add(new NamedTemplate(type.getName() + Utils.FILE_SEPARATOR + "version", versionTemplateFile));
+ }
+ }
+
+ }
+ }
+
+ public String getTemplateDirectory()
+ {
+ return _templateDirectory;
+ }
+
+
+ public void setTemplateDirectory(String templateDirectory)
+ {
+ _templateDirectory = templateDirectory;
+ }
+
+
+ public void setOutputDirectory(String outputDirectory)
+ {
+ _outputDirectory = outputDirectory;
+ }
+
+ public void generate()
+ {
+ prepareTargetDirectory(new File(_outputDirectory), true);
+ System.out.println("Generation directory: " + _outputDirectory);
+
+
+ processModelTemplates(_templates);
+
+ for (AmqpClass amqpClass : _model.getClassMap().values())
+ {
+ processClassTemplates(_templates, amqpClass);
+
+ for (AmqpMethod amqpMethod : amqpClass.getMethodMap().values())
+ {
+ processMethodTemplates(_templates, amqpClass, amqpMethod);
+
+ for (AmqpField amqpField : amqpMethod.getFieldMap().values())
+ {
+ processFieldTemplates(_templates, amqpClass, amqpMethod, amqpField, null);
+ }
+ }
+ }
+
+
+ for (AmqpVersion version : _versionSet)
+ {
+ AmqpModel model = _versionToModelMap.get(version);
+ processModelTemplates(_versionSpecificTemplates, version);
+
+ for (AmqpClass amqpClass : model.getClassMap().values())
+ {
+ processClassTemplates(_versionSpecificTemplates, amqpClass, version);
+
+ for (AmqpMethod amqpMethod : amqpClass.getMethodMap().values())
+ {
+ processMethodTemplates(_versionSpecificTemplates, amqpClass, amqpMethod, version);
+
+ for (AmqpField amqpField : amqpMethod.getFieldMap().values())
+ {
+ processFieldTemplates(_versionSpecificTemplates, amqpClass, amqpMethod, amqpField, version);
+ }
+ }
+ }
+
+ }
+ }
+
+ private void processMethodTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpVersion version)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.method))
+ {
+ if(isVelocityTemplate(template))
+ {
+ processVelocityTemplate(template,version,amqpClass,amqpMethod,null);
+ }
+ else
+ {
+ processMethodTemplate(template, amqpClass, amqpMethod);
+ }
+ }
+
+ }
+
+ private void processClassTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpVersion version)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.clazz))
+ {
+ if(isVelocityTemplate(template))
+ {
+ processVelocityTemplate(template,version,amqpClass,null,null);
+ }
+ else
+ {
+ processClassTemplate(template, amqpClass);
+ }
+ }
+
+ }
+
+
+ private void processModelTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpVersion version)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.model))
+ {
+ if (isVelocityTemplate(template))
+ {
+ processModelVelocityTemplate(template, version);
+ }
+ else
+ {
+ processModelTemplate(template, version);
+ }
+ }
+ }
+
+ abstract void processModelTemplate(NamedTemplate template, AmqpVersion version);
+
+
+ protected void processModelTemplates(Map<TemplateType, Collection<NamedTemplate>> templates)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.model))
+ {
+ if (isVelocityTemplate(template))
+ {
+ processModelVelocityTemplate(template, null);
+ }
+ else
+ {
+ processModelTemplate(template);
+ }
+ }
+ }
+
+ private boolean isVelocityTemplate(NamedTemplate template)
+ {
+ return template.getName().endsWith(VELOCITY_TEMPLATE_SUFFIX);
+ }
+
+ private void processModelVelocityTemplate(NamedTemplate template, AmqpVersion version)
+ {
+ processVelocityTemplate(template,version,null,null,null);
+ }
+
+ private void processVelocityTemplate(NamedTemplate template, AmqpVersion version,
+ AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpField amqpField)
+ {
+
+ VelocityContext context = new VelocityContext();
+
+ AmqpModel model = _model;
+ if(version != null)
+ {
+ model = _versionToModelMap.get(version);
+ }
+ context.put("model", model);
+ context.put("generator", GENERATOR_INFO);
+
+ if (version != null)
+ {
+ context.put("version", version);
+ }
+ if(amqpClass != null)
+ {
+ context.put("amqpClass", amqpClass);
+ }
+
+ if(amqpClass != null)
+ {
+ context.put("amqpMethod", amqpMethod);
+ }
+
+
+ StringWriter sw = new StringWriter();
+
+
+ try
+ {
+ Template velocityTemplate = Velocity.getTemplate(template.getName());
+ velocityTemplate.merge(context, sw);
+ String filename = String.valueOf(context.get("filename"));
+
+ File outputFile = new File(getOutputDirectory() + Utils.FILE_SEPARATOR + filename);
+ outputFile.getParentFile().mkdirs();
+ FileWriter outputFileWriter = new FileWriter(outputFile);
+
+ outputFileWriter.append(sw.toString());
+ outputFileWriter.close();
+
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ }
+
+
+ protected void processClassTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.clazz))
+ {
+ if(isVelocityTemplate(template))
+ {
+ processVelocityTemplate(template,null,amqpClass,null,null);
+ }
+ else
+ {
+ processClassTemplate(template, amqpClass);
+ }
+ }
+ }
+
+ protected void processMethodTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpMethod amqpMethod)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.method))
+ {
+ if(isVelocityTemplate(template))
+ {
+ processVelocityTemplate(template,null,amqpClass,amqpMethod,null);
+ }
+ else
+ {
+ processMethodTemplate(template, amqpClass, amqpMethod);
+ }
+ }
+ }
+
+
+ protected void processFieldTemplates(Map<TemplateType, Collection<NamedTemplate>> templates, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpField amqpField, AmqpVersion amqpVersion)
+ {
+ for (NamedTemplate template : templates.get(TemplateType.field))
+ {
+ if(isVelocityTemplate(template))
+ {
+ processVelocityTemplate(template,amqpVersion,amqpClass,amqpMethod,amqpField);
+ }
+ else
+ {
+ processTemplate(template, amqpClass, amqpMethod, amqpField, amqpVersion);
+ }
+ }
+ }
+
+
+ protected void processVersionList(StringBuffer sb, int tokStart, int tokEnd)
+ {
+ int lend = sb.indexOf(Utils.LINE_SEPARATOR, 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 : _versionSet)
+ {
+ // Insert copy of target line
+ StringBuffer isb = new StringBuffer(tline);
+ if (isb.indexOf("${protocol-version-list-entry}") >= 0)
+ {
+ String versionListEntry = " { ${major}, ${minor} }" +
+ (v.equals(_versionSet.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();
+ }
+ }
+
+ // Helper functions common to all generators
+
+ protected static void prepareTargetDirectory(File dir, boolean createFlag)
+ {
+ 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)
+ {
+ AmqpModel model = (version == null) ? _model : _versionToModelMap.get(version);
+
+
+ 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, version);
+ }
+ 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.getFieldMap() : method.getFieldMap()),
+ version);
+ }
+ else if (listToken.compareTo("TLIST") == 0)
+ {
+ processConstantList(sb, lstart, lend + 1, _constantSet);
+ }
+ 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)
+ {
+ 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)
+ {
+ try
+ {
+ f.getParentFile().mkdirs();
+ FileWriter fw = new FileWriter(f);
+ fw.write(sb.toString().toCharArray());
+ fw.flush();
+ fw.close();
+ }
+ catch (IOException e)
+ {
+ throw new AmqpTemplateException(e.getMessage());
+ }
+ }
+
+
+ protected static String getTemplateFileName(StringBuffer sb)
+ {
+ if (sb.charAt(0) != '&')
+ {
+ throw new AmqpTemplateException("No filename marker &{filename} found at start of template.");
+ }
+ int cr = sb.indexOf(Utils.LINE_SEPARATOR);
+ 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);
+ if (start != -1)
+ {
+ 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)
+ {
+ try
+ {
+ StringBuffer sb = new StringBuffer();
+ FileReader fr = new FileReader(f);
+ LineNumberReader lnr = new LineNumberReader(fr);
+ String line = lnr.readLine();
+ while (line != null)
+ {
+
+ sb.append(line);
+ sb.append(Utils.LINE_SEPARATOR);
+
+ line = lnr.readLine();
+ }
+ lnr.close();
+ fr.close();
+ return sb.toString();
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new AmqpTemplateException("File not found: " + e.getMessage());
+ }
+ catch (IOException e)
+ {
+ throw new AmqpTemplateException("IOException: " + e.getMessage());
+ }
+ }
+
+ public String getDomainType(String domainName, AmqpVersion version)
+ {
+ if (version == null)
+ {
+ version = _versionSet.first();
+ }
+ return getDomainMap().getDomainType(domainName, version);
+ }
+
+
+ public void addFromNode(Node amqpNode, AmqpVersion version)
+ {
+ // 1c. Extract domains
+ getConstantSet().addFromNode(amqpNode, 0, version);
+ _versionToConstantSetMap.get(version).addFromNode(amqpNode, 0, version);
+
+ // 1d. Extract domains
+ getDomainMap().addFromNode(amqpNode, 0, version);
+ _versionToDomainMapMap.get(version).addFromNode(amqpNode, 0, version);
+
+ // 1e. Extract class/method/field heirarchy
+ getModel().addFromNode(amqpNode, 0, version);
+ _versionToModelMap.get(version).addFromNode(amqpNode, 0, version);
+ }
+
+
+ public String getOutputDirectory()
+ {
+ return _outputDirectory;
+ }
+
+ public String prepareConstantName(String constantName)
+ {
+ return prepareDomainName(constantName);
+ }
+
+
+ public boolean isFixedSizeType(String type)
+ {
+ return FIXED_SIZE_TYPES.containsKey(type);
+ }
+
+
+ public int getTypeSize(String type)
+ {
+ return FIXED_SIZE_TYPES.get(type);
+ }
+
+
+
+ // Model-level template processing
+ abstract protected void processModelTemplate(NamedTemplate template);
+
+ // Class-level template processing
+ abstract protected void processClassTemplate(NamedTemplate template, AmqpClass thisClass);
+
+ // Method-level template processing
+ abstract protected void processMethodTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method);
+
+ // Field-level template processing
+ abstract protected void processTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method, AmqpField field, AmqpVersion version);
+
+ abstract protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, AmqpVersion version);
+
+ abstract protected String processToken(String token, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, AmqpVersion version);
+
+ abstract protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpModel model, AmqpVersion version);
+
+ abstract protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpClass thisClass);
+
+
+ abstract protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpFieldMap fieldMap, AmqpVersion version);
+
+ abstract protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpConstantSet constantSet);
+
+
+}
Modified: incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java (original)
+++ incubator/qpid/trunk/qpid/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java Wed Apr 23 18:54:20 2008
@@ -140,5 +140,15 @@
}
+ public boolean isServerMethod()
+ {
+ return _amqpMethod.isServerMethod(_amqpVersion);
+ }
+
+
+ public boolean isClientMethod()
+ {
+ return _amqpMethod.isClientMethod(_amqpVersion);
+ }
}
Modified: incubator/qpid/trunk/qpid/java/broker/pom.xml
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/broker/pom.xml?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/broker/pom.xml (original)
+++ incubator/qpid/trunk/qpid/java/broker/pom.xml Wed Apr 23 18:54:20 2008
@@ -22,14 +22,14 @@
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-broker</artifactId>
<packaging>jar</packaging>
- <version>1.0-incubating-M2.1-SNAPSHOT</version>
+ <version>1.0-incubating-M3-SNAPSHOT</version>
<name>Qpid Broker</name>
<url>http://cwiki.apache.org/confluence/display/qpid</url>
<parent>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid</artifactId>
- <version>1.0-incubating-M2.1-SNAPSHOT</version>
+ <version>1.0-incubating-M3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
Modified: incubator/qpid/trunk/qpid/java/broker/src/main/grammar/SelectorParser.jj
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/broker/src/main/grammar/SelectorParser.jj?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/broker/src/main/grammar/SelectorParser.jj (original)
+++ incubator/qpid/trunk/qpid/java/broker/src/main/grammar/SelectorParser.jj Wed Apr 23 18:54:20 2008
@@ -94,7 +94,7 @@
return this.JmsSelector();
}
catch (Throwable e) {
- throw (AMQInvalidArgumentException)new AMQInvalidArgumentException(sql).initCause(e);
+ throw (AMQInvalidArgumentException)new AMQInvalidArgumentException(sql, e);
}
}
Modified: incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java (original)
+++ incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java Wed Apr 23 18:54:20 2008
@@ -67,7 +67,7 @@
if (exchType == null)
{
- throw new AMQUnknownExchangeType("Unknown exchange type: " + type);
+ throw new AMQUnknownExchangeType("Unknown exchange type: " + type, null);
}
Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete);
return e;
Modified: incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java (original)
+++ incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java Wed Apr 23 18:54:20 2008
@@ -101,7 +101,7 @@
else if (!exchange.getType().equals(body.getType()))
{
- throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor());
+ throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getType() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(), null);
}
}
Modified: incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java (original)
+++ incubator/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java Wed Apr 23 18:54:20 2008
@@ -37,9 +37,9 @@
public AccessResult authorise(AMQProtocolSession session, Permission permission, AMQMethodBody body, Object... parameters)
{
- if (_logger.isDebugEnabled())
+ if (ACLManager.getLogger().isDebugEnabled())
{
- _logger.debug("Allowing user:" + session.getAuthorizedID() + " for :" + permission.toString()
+ ACLManager.getLogger().debug("Allowing user:" + session.getAuthorizedID() + " for :" + permission.toString()
+ " on " + body.getClass().getSimpleName()
+ (parameters == null || parameters.length == 0 ? "" : "-" + accessablesToString(parameters)));
}
Modified: incubator/qpid/trunk/qpid/java/client/build.xml
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/build.xml?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/build.xml (original)
+++ incubator/qpid/trunk/qpid/java/client/build.xml Wed Apr 23 18:54:20 2008
@@ -21,7 +21,7 @@
<project name="AMQ Client" default="build">
<property name="module.depends" value="common"/>
- <property name="module.test.depends" value="broker"/>
+ <property name="module.test.depends" value="broker junit-toolkit"/>
<import file="../module.xml"/>
@@ -29,9 +29,9 @@
<target name="precompile">
<mkdir dir="${output.dir}"/>
- <exec executable="javacc">
- <arg line="-OUTPUT_DIRECTORY=${output.dir} src/main/grammar/SelectorParser.jj"/>
- </exec>
+ <javacc target="src/main/grammar/SelectorParser.jj"
+ outputdirectory="${output.dir}"
+ javacchome="${project.root}/lib"/>
</target>
</project>
Added: incubator/qpid/trunk/qpid/java/client/example/src/main/java/org/apache/qpid/example/transport/ExistingSocketConnectorDemo.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/example/src/main/java/org/apache/qpid/example/transport/ExistingSocketConnectorDemo.java?rev=651133&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/example/src/main/java/org/apache/qpid/example/transport/ExistingSocketConnectorDemo.java (added)
+++ incubator/qpid/trunk/qpid/java/client/example/src/main/java/org/apache/qpid/example/transport/ExistingSocketConnectorDemo.java Wed Apr 23 18:54:20 2008
@@ -0,0 +1,171 @@
+/*
+ *
+ * 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.example.transport;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.SocketChannel;
+import java.util.UUID;
+
+/**
+ * This is a simple application that demonstrates how you can use the Qpid AMQP interfaces to use existing sockets as
+ * the transport for the Client API.
+ *
+ * The Demo here runs twice:
+ * 1. Just to show a simple publish and receive.
+ * 2. To demonstrate how to use existing sockets and utilise the underlying client failover mechnaism.
+ */
+public class ExistingSocketConnectorDemo implements ConnectionListener
+{
+ private static boolean DEMO_FAILOVER = false;
+
+ public static void main(String[] args) throws IOException, URLSyntaxException, AMQException, JMSException
+ {
+ System.out.println("Testing socket connection to localhost:5672.");
+
+ new ExistingSocketConnectorDemo();
+
+ System.out.println("Testing socket connection failover between localhost:5672 and localhost:5673.");
+
+ DEMO_FAILOVER = true;
+
+ new ExistingSocketConnectorDemo();
+ }
+
+ Connection _connection;
+ MessageProducer _producer;
+ Session _session;
+
+ String Socket1_ID = UUID.randomUUID().toString();
+ String Socket2_ID = UUID.randomUUID().toString();
+
+
+
+ /** Here we can see the broker we are connecting to is set to be 'socket:///' signifying we will provide the socket. */
+ public final String CONNECTION = "amqp://guest:guest@id/test?brokerlist='socket://" + Socket1_ID + ";socket://" + Socket2_ID + "'";
+
+
+ public ExistingSocketConnectorDemo() throws IOException, URLSyntaxException, AMQException, JMSException
+ {
+
+ Socket socket = SocketChannel.open().socket();
+ socket.connect(new InetSocketAddress("localhost", 5672));
+
+ TransportConnection.registerOpenSocket(Socket1_ID, socket);
+
+
+ _connection = new AMQConnection(CONNECTION);
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageConsumer consumer = _session.createConsumer(_session.createQueue("Queue"));
+
+ _producer = _session.createProducer(_session.createQueue("Queue"));
+
+ _connection.start();
+
+ if (!DEMO_FAILOVER)
+ {
+ _producer.send(_session.createTextMessage("Simple Test"));
+ }
+ else
+ {
+ // Using the Qpid interfaces we can set a listener that allows us to demonstrate failover
+ ((AMQConnection) _connection).setConnectionListener(this);
+
+ System.out.println("Testing failover: Please ensure second broker running on localhost:5673 and shutdown broker on 5672.");
+ }
+
+ //We do a blocking receive here so that we can demonstrate failover.
+ Message message = consumer.receive();
+
+ System.out.println("Recevied :" + message);
+
+ _connection.close();
+ }
+
+ // ConnectionListener Interface
+
+ public void bytesSent(long count)
+ {
+ //not used in this example
+ }
+ public void bytesReceived(long count)
+ {
+ //not used in this example
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ /**
+ * This method is called before the underlying client library starts to reconnect. This gives us the opportunity
+ * to set a new socket for the failover to occur on.
+ */
+ try
+ {
+ Socket socket = SocketChannel.open().socket();
+
+ socket.connect(new InetSocketAddress("localhost", 5673));
+
+ // This is the new method to pass in an open socket for the connection to use.
+ TransportConnection.registerOpenSocket(Socket2_ID, socket);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public boolean preResubscribe()
+ {
+ //not used in this example - but must return true to allow the resubscription of existing clients.
+ return true;
+ }
+
+ public void failoverComplete()
+ {
+ // Now that failover has completed we can send a message that the receiving thread will pick up
+ try
+ {
+ _producer.send(_session.createTextMessage("Simple Failover Test"));
+ }
+ catch (JMSException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
Modified: incubator/qpid/trunk/qpid/java/client/pom.xml
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/pom.xml?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/pom.xml (original)
+++ incubator/qpid/trunk/qpid/java/client/pom.xml Wed Apr 23 18:54:20 2008
@@ -69,18 +69,8 @@
<artifactId>commons-lang</artifactId>
</dependency>
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-filter-ssl</artifactId>
- </dependency>
<!-- Test Dependencies -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- <scope>test</scope>
- </dependency>
<dependency> <!-- for inVm Broker -->
<groupId>org.apache.qpid</groupId>
@@ -89,19 +79,7 @@
</dependency>
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.easymock</groupId>
- <artifactId>easymockclassextension</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>uk.co.thebadgerset</groupId>
+ <groupId>org.apache.qpid</groupId>
<artifactId>junit-toolkit</artifactId>
<scope>test</scope>
</dependency>
Modified: incubator/qpid/trunk/qpid/java/client/src/main/grammar/SelectorParser.jj
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/main/grammar/SelectorParser.jj?rev=651133&r1=651132&r2=651133&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/main/grammar/SelectorParser.jj (original)
+++ incubator/qpid/trunk/qpid/java/client/src/main/grammar/SelectorParser.jj Wed Apr 23 18:54:20 2008
@@ -170,6 +170,8 @@
TOKEN [IGNORE_CASE] :
{
< ID : ["a"-"z", "_", "$"] (["a"-"z","0"-"9","_", "$"])* >
+ | < QUOTED_ID : "\"" ( ("\"\"") | ~["\""] )* "\"" >
+
}
// ----------------------------------------------------------------------------
@@ -577,6 +579,7 @@
PropertyExpression variable() :
{
Token t;
+ StringBuffer rc = new StringBuffer();
PropertyExpression left=null;
}
{
@@ -585,6 +588,20 @@
{
left = new PropertyExpression(t.image);
}
+ |
+ t = <QUOTED_ID>
+ {
+ // Decode the sting value.
+ String image = t.image;
+ for( int i=1; i < image.length()-1; i++ ) {
+ char c = image.charAt(i);
+ if( c == '"' )
+ i++;
+ rc.append(c);
+ }
+ return new PropertyExpression(rc.toString());
+ }
+
)
{
return left;
Added: incubator/qpid/trunk/qpid/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java?rev=651133&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java (added)
+++ incubator/qpid/trunk/qpid/java/client/src/main/java/org/apache/mina/transport/socket/nio/ExistingSocketConnector.java Wed Apr 23 18:54:20 2008
@@ -0,0 +1,478 @@
+/*
+ * 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.mina.transport.socket.nio;
+
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.ExceptionMonitor;
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoConnectorConfig;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.support.BaseIoConnector;
+import org.apache.mina.common.support.DefaultConnectFuture;
+import org.apache.mina.util.NamePreservingRunnable;
+import org.apache.mina.util.NewThreadExecutor;
+import org.apache.mina.util.Queue;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * {@link IoConnector} for socket transport (TCP/IP).
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 627427 $, $Date: 2008-02-13 14:39:10 +0000 (Wed, 13 Feb 2008) $
+ */
+public class ExistingSocketConnector extends BaseIoConnector
+{
+ /** @noinspection StaticNonFinalField */
+ private static volatile int nextId = 0;
+
+ private final Object lock = new Object();
+ private final int id = nextId++;
+ private final String threadName = "SocketConnector-" + id;
+ private SocketConnectorConfig defaultConfig = new SocketConnectorConfig();
+ private final Queue connectQueue = new Queue();
+ private final SocketIoProcessor[] ioProcessors;
+ private final int processorCount;
+ private final Executor executor;
+
+ /** @noinspection FieldAccessedSynchronizedAndUnsynchronized */
+ private Selector selector;
+ private Worker worker;
+ private int processorDistributor = 0;
+ private int workerTimeout = 60; // 1 min.
+ private Socket _openSocket = null;
+
+ /** Create a connector with a single processing thread using a NewThreadExecutor */
+ public ExistingSocketConnector()
+ {
+ this(1, new NewThreadExecutor());
+ }
+
+ /**
+ * Create a connector with the desired number of processing threads
+ *
+ * @param processorCount Number of processing threads
+ * @param executor Executor to use for launching threads
+ */
+ public ExistingSocketConnector(int processorCount, Executor executor)
+ {
+ if (processorCount < 1)
+ {
+ throw new IllegalArgumentException("Must have at least one processor");
+ }
+
+ this.executor = executor;
+ this.processorCount = processorCount;
+ ioProcessors = new SocketIoProcessor[processorCount];
+
+ for (int i = 0; i < processorCount; i++)
+ {
+ ioProcessors[i] = new SocketIoProcessor("SocketConnectorIoProcessor-" + id + "." + i, executor);
+ }
+ }
+
+ /**
+ * How many seconds to keep the connection thread alive between connection requests
+ *
+ * @return Number of seconds to keep connection thread alive
+ */
+ public int getWorkerTimeout()
+ {
+ return workerTimeout;
+ }
+
+ /**
+ * Set how many seconds the connection worker thread should remain alive once idle before terminating itself.
+ *
+ * @param workerTimeout Number of seconds to keep thread alive. Must be >=0
+ */
+ public void setWorkerTimeout(int workerTimeout)
+ {
+ if (workerTimeout < 0)
+ {
+ throw new IllegalArgumentException("Must be >= 0");
+ }
+ this.workerTimeout = workerTimeout;
+ }
+
+ public ConnectFuture connect(SocketAddress address, IoHandler handler, IoServiceConfig config)
+ {
+ return connect(address, null, handler, config);
+ }
+
+ public ConnectFuture connect(SocketAddress address, SocketAddress localAddress,
+ IoHandler handler, IoServiceConfig config)
+ {
+ /** Changes here from the Mina OpenSocketConnector.
+ * Ignoreing all address as they are not needed */
+
+ if (handler == null)
+ {
+ throw new NullPointerException("handler");
+ }
+
+
+ if (config == null)
+ {
+ config = getDefaultConfig();
+ }
+
+ if (_openSocket == null)
+ {
+ throw new IllegalArgumentException("Specifed Socket not active");
+ }
+
+ boolean success = false;
+
+ try
+ {
+ DefaultConnectFuture future = new DefaultConnectFuture();
+ newSession(_openSocket, handler, config, future);
+ success = true;
+ return future;
+ }
+ catch (IOException e)
+ {
+ return DefaultConnectFuture.newFailedFuture(e);
+ }
+ finally
+ {
+ if (!success && _openSocket != null)
+ {
+ try
+ {
+ _openSocket.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ }
+ }
+ }
+
+ public IoServiceConfig getDefaultConfig()
+ {
+ return defaultConfig;
+ }
+
+ /**
+ * Sets the config this connector will use by default.
+ *
+ * @param defaultConfig the default config.
+ *
+ * @throws NullPointerException if the specified value is <code>null</code>.
+ */
+ public void setDefaultConfig(SocketConnectorConfig defaultConfig)
+ {
+ if (defaultConfig == null)
+ {
+ throw new NullPointerException("defaultConfig");
+ }
+ this.defaultConfig = defaultConfig;
+ }
+
+ private synchronized void startupWorker() throws IOException
+ {
+ if (worker == null)
+ {
+ selector = Selector.open();
+ worker = new Worker();
+ executor.execute(new NamePreservingRunnable(worker));
+ }
+ }
+
+ private void registerNew()
+ {
+ if (connectQueue.isEmpty())
+ {
+ return;
+ }
+
+ for (; ;)
+ {
+ ConnectionRequest req;
+ synchronized (connectQueue)
+ {
+ req = (ConnectionRequest) connectQueue.pop();
+ }
+
+ if (req == null)
+ {
+ break;
+ }
+
+ SocketChannel ch = req.channel;
+ try
+ {
+ ch.register(selector, SelectionKey.OP_CONNECT, req);
+ }
+ catch (IOException e)
+ {
+ req.setException(e);
+ }
+ }
+ }
+
+ private void processSessions(Set keys)
+ {
+ Iterator it = keys.iterator();
+
+ while (it.hasNext())
+ {
+ SelectionKey key = (SelectionKey) it.next();
+
+ if (!key.isConnectable())
+ {
+ continue;
+ }
+
+ SocketChannel ch = (SocketChannel) key.channel();
+ ConnectionRequest entry = (ConnectionRequest) key.attachment();
+
+ boolean success = false;
+ try
+ {
+ ch.finishConnect();
+ newSession(ch, entry.handler, entry.config, entry);
+ success = true;
+ }
+ catch (Throwable e)
+ {
+ entry.setException(e);
+ }
+ finally
+ {
+ key.cancel();
+ if (!success)
+ {
+ try
+ {
+ ch.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ }
+ }
+ }
+
+ keys.clear();
+ }
+
+ private void processTimedOutSessions(Set keys)
+ {
+ long currentTime = System.currentTimeMillis();
+ Iterator it = keys.iterator();
+
+ while (it.hasNext())
+ {
+ SelectionKey key = (SelectionKey) it.next();
+
+ if (!key.isValid())
+ {
+ continue;
+ }
+
+ ConnectionRequest entry = (ConnectionRequest) key.attachment();
+
+ if (currentTime >= entry.deadline)
+ {
+ entry.setException(new ConnectException());
+ try
+ {
+ key.channel().close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ finally
+ {
+ key.cancel();
+ }
+ }
+ }
+ }
+
+ private void newSession(Socket socket, IoHandler handler, IoServiceConfig config, ConnectFuture connectFuture)
+ throws IOException
+ {
+ SocketSessionImpl session = new SocketSessionImpl(this,
+ nextProcessor(),
+ getListeners(),
+ config,
+ socket.getChannel(),
+ handler,
+ socket.getRemoteSocketAddress());
+
+ newSession(session, config, connectFuture);
+ }
+
+ private void newSession(SocketChannel ch, IoHandler handler, IoServiceConfig config, ConnectFuture connectFuture)
+ throws IOException
+
+ {
+ SocketSessionImpl session = new SocketSessionImpl(this,
+ nextProcessor(),
+ getListeners(),
+ config,
+ ch,
+ handler,
+ ch.socket().getRemoteSocketAddress());
+
+ newSession(session, config, connectFuture);
+ }
+
+ private void newSession(SocketSessionImpl session, IoServiceConfig config, ConnectFuture connectFuture)
+ throws IOException
+ {
+ try
+ {
+ getFilterChainBuilder().buildFilterChain(session.getFilterChain());
+ config.getFilterChainBuilder().buildFilterChain(session.getFilterChain());
+ config.getThreadModel().buildFilterChain(session.getFilterChain());
+ }
+ catch (Throwable e)
+ {
+ throw (IOException) new IOException("Failed to create a session.").initCause(e);
+ }
+ session.getIoProcessor().addNew(session);
+ connectFuture.setSession(session);
+ }
+
+ private SocketIoProcessor nextProcessor()
+ {
+ return ioProcessors[processorDistributor++ % processorCount];
+ }
+
+ public void setOpenSocket(Socket openSocket)
+ {
+ _openSocket = openSocket;
+ }
+
+ private class Worker implements Runnable
+ {
+ private long lastActive = System.currentTimeMillis();
+
+ public void run()
+ {
+ Thread.currentThread().setName(ExistingSocketConnector.this.threadName);
+
+ for (; ;)
+ {
+ try
+ {
+ int nKeys = selector.select(1000);
+
+ registerNew();
+
+ if (nKeys > 0)
+ {
+ processSessions(selector.selectedKeys());
+ }
+
+ processTimedOutSessions(selector.keys());
+
+ if (selector.keys().isEmpty())
+ {
+ if (System.currentTimeMillis() - lastActive > workerTimeout * 1000L)
+ {
+ synchronized (lock)
+ {
+ if (selector.keys().isEmpty() &&
+ connectQueue.isEmpty())
+ {
+ worker = null;
+ try
+ {
+ selector.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ finally
+ {
+ selector = null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ lastActive = System.currentTimeMillis();
+ }
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e1)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e1);
+ }
+ }
+ }
+ }
+ }
+
+ private class ConnectionRequest extends DefaultConnectFuture
+ {
+ private final SocketChannel channel;
+ private final long deadline;
+ private final IoHandler handler;
+ private final IoServiceConfig config;
+
+ private ConnectionRequest(SocketChannel channel, IoHandler handler, IoServiceConfig config)
+ {
+ this.channel = channel;
+ long timeout;
+ if (config instanceof IoConnectorConfig)
+ {
+ timeout = ((IoConnectorConfig) config).getConnectTimeoutMillis();
+ }
+ else
+ {
+ timeout = ((IoConnectorConfig) getDefaultConfig()).getConnectTimeoutMillis();
+ }
+ this.deadline = System.currentTimeMillis() + timeout;
+ this.handler = handler;
+ this.config = config;
+ }
+ }
+}