summaryrefslogtreecommitdiff
path: root/java/common
diff options
context:
space:
mode:
Diffstat (limited to 'java/common')
-rwxr-xr-xjava/common/bin/qpid-run8
-rw-r--r--java/common/build.xml21
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpClass.java197
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java29
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpConstant.java191
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java152
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpDomain.java89
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java128
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java62
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpField.java269
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java452
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java77
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpMethod.java351
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java36
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpModel.java132
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java96
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java76
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java29
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpParseException.java30
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java30
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java30
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpVersion.java72
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java79
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/BitFieldGenerateMethod.java29
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/CommandGenerateMethod.java26
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java120
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/CppGenerator.java1716
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java382
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/GenerateMethod.java27
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/Generator.java857
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/JavaGenerator.java1826
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/LanguageConverter.java42
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/Main.java301
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/MangledGenerateMethod.java26
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/NodeAware.java47
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/Printable.java28
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/SingleVersionClass.java103
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/SingleVersionField.java68
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java154
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/SingleVersionModel.java71
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java30
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/Utils.java159
-rw-r--r--java/common/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java26
-rw-r--r--java/common/protocol-version.xml70
-rwxr-xr-xjava/common/src/main/java/common.bnd2
-rw-r--r--java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java15
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java19
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTable.java1
-rw-r--r--java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java27
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Connection.java88
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java8
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Session.java22
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/Ticker.java29
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/TransportActivity.java33
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IdleTimeoutTicker.java87
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java31
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java51
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java100
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/BindingURL.java3
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/FileUtils.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/NetMatcher.java300
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/FieldTableTest.java (renamed from java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java)106
-rw-r--r--java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java10
-rw-r--r--java/common/src/test/java/org/apache/qpid/test/utils/TestFileUtils.java90
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java7
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java12
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java5
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/io/IdleTimeoutTickerTest.java257
73 files changed, 9525 insertions, 558 deletions
diff --git a/java/common/bin/qpid-run b/java/common/bin/qpid-run
index 1e373340ce..a10766b37a 100755
--- a/java/common/bin/qpid-run
+++ b/java/common/bin/qpid-run
@@ -88,10 +88,10 @@ SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="-DQPID_WORK=$QPID_WORK"
if [ -n "$QPID_LOG_PREFIX" ]; then
if [ "X$QPID_LOG_PREFIX" = "XPID" ]; then
log $INFO Using pid in qpid log name prefix
- LOG_PREFIX=" -Dlogprefix=$$"
+ LOG_PREFIX="-Dlogprefix=$$"
else
log $INFO Using qpid logprefix property
- LOG_PREFIX=" -Dlogprefix=$QPID_LOG_PREFIX"
+ LOG_PREFIX="-Dlogprefix=$QPID_LOG_PREFIX"
fi
SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="${LOG_PREFIX}"
fi
@@ -99,10 +99,10 @@ fi
if [ -n "$QPID_LOG_SUFFIX" ]; then
if [ "X$QPID_LOG_SUFFIX" = "XPID" ]; then
log $INFO Using pid in qpid log name suffix
- LOG_SUFFIX=" -Dlogsuffix=$$"
+ LOG_SUFFIX="-Dlogsuffix=$$"
else
log $INFO Using qpig logsuffix property
- LOG_SUFFIX=" -Dlogsuffix=$QPID_LOG_SUFFIX"
+ LOG_SUFFIX="-Dlogsuffix=$QPID_LOG_SUFFIX"
fi
SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="${LOG_SUFFIX}"
fi
diff --git a/java/common/build.xml b/java/common/build.xml
index 9caf93c026..e599c840db 100644
--- a/java/common/build.xml
+++ b/java/common/build.xml
@@ -53,7 +53,15 @@
</target>
<target name="compile_gentools">
- <ant dir="${gentools.home}" />
+ <mkdir dir="${gentools.build}/classes"/>
+ <javac srcdir="${gentools.home}/src" destdir="${gentools.build}/classes" source="${java.source}" target="${java.target}" fork="true" includeantruntime="false">
+ <classpath>
+ <fileset dir="${project.root}">
+ <include name="${velocity.jar}"/>
+ <include name="${velocity-dep.jar}"/>
+ </fileset>
+ </classpath>
+ </javac>
</target>
<target name="check_gentool_deps">
@@ -64,15 +72,12 @@
<target name="gentools" depends="compile_gentools,check_gentool_deps" unless="gentools.notRequired">
<mkdir dir="${framing.generated.dir}"/>
- <java classname="org.apache.qpid.gentools.Main" fork="true" dir="${gentools.home}/src" failonerror="true">
+ <java classname="org.apache.qpid.gentools.Main" fork="true" dir="${gentools.build}/classes" failonerror="true">
<arg line='-j -o "${framing.generated.dir}" -t "${project.root}/common/templates" ${xml.spec.list}'/>
<classpath>
- <pathelement path="${gentools.home}/src" />
- <fileset dir="${gentools.home}/lib">
- <include name="**/*.jar"/>
- </fileset>
- <pathelement path="${gentools.home}/lib/velocity-1.4.jar" />
- <pathelement path="${gentools.home}/lib/velocity-dep-1.4.jar" />
+ <pathelement path="${gentools.build}/classes" />
+ <pathelement path="${project.root}/${velocity.jar}" />
+ <pathelement path="${project.root}/${velocity-dep.jar}" />
</classpath>
</java>
<touch file="${gentools.timestamp}" />
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpClass.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpClass.java
new file mode 100644
index 0000000000..26195da2e3
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpClass.java
@@ -0,0 +1,197 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.PrintStream;
+import java.util.Collection;
+
+public class AmqpClass implements Printable, NodeAware
+{
+
+ private final AmqpVersionSet _versionSet = new AmqpVersionSet();
+ private final AmqpFieldMap _fieldMap = new AmqpFieldMap();
+ private final AmqpMethodMap _methodMap = new AmqpMethodMap();
+ private final AmqpOrdinalVersionMap _indexMap = new AmqpOrdinalVersionMap();
+
+
+ private final String _name;
+ private final Generator _generator;
+
+ public AmqpClass(String name, Generator generator)
+ {
+ _name = name;
+ _generator = generator;
+ }
+
+ public boolean addFromNode(Node classNode, int ordinal, AmqpVersion version)
+ throws AmqpParseException, AmqpTypeMappingException
+ {
+ getVersionSet().add(version);
+ int index = Utils.getNamedIntegerAttribute(classNode, "index");
+ AmqpVersionSet indexVersionSet = getIndexMap().get(index);
+ if (indexVersionSet != null)
+ {
+ indexVersionSet.add(version);
+ }
+ else
+ {
+ indexVersionSet = new AmqpVersionSet();
+ indexVersionSet.add(version);
+ getIndexMap().put(index, indexVersionSet);
+ }
+ NodeList nList = classNode.getChildNodes();
+ int fieldCntr = getFieldMap().size();
+ for (int i = 0; i < nList.getLength(); i++)
+ {
+ Node child = nList.item(i);
+ if (child.getNodeName().compareTo(Utils.ELEMENT_FIELD) == 0)
+ {
+ String fieldName = getGenerator().prepareDomainName(Utils.getNamedAttribute(child,
+ Utils.ATTRIBUTE_NAME));
+ AmqpField thisField = getFieldMap().get(fieldName);
+ if (thisField == null)
+ {
+ thisField = new AmqpField(fieldName, getGenerator());
+ getFieldMap().add(fieldName, thisField);
+ }
+ if (!thisField.addFromNode(child, fieldCntr++, version))
+ {
+ String className = getGenerator().prepareClassName(Utils.getNamedAttribute(classNode,
+ Utils.ATTRIBUTE_NAME));
+ System.out.println("INFO: Generation supression tag found for field " +
+ className + "." + fieldName + " - removing.");
+ thisField.removeVersion(version);
+ getFieldMap().remove(fieldName);
+ }
+ }
+ else if (child.getNodeName().compareTo(Utils.ELEMENT_METHOD) == 0)
+ {
+ String methodName = getGenerator().prepareMethodName(Utils.getNamedAttribute(child,
+ Utils.ATTRIBUTE_NAME));
+ AmqpMethod thisMethod = getMethodMap().get(methodName);
+ if (thisMethod == null)
+ {
+ thisMethod = new AmqpMethod(methodName, getGenerator());
+ getMethodMap().put(methodName, thisMethod);
+ }
+ if (!thisMethod.addFromNode(child, 0, version))
+ {
+ String className = getGenerator().prepareClassName(Utils.getNamedAttribute(classNode,
+ Utils.ATTRIBUTE_NAME));
+ System.out.println("INFO: Generation supression tag found for method " +
+ className + "." + methodName + " - removing.");
+ thisMethod.removeVersion(version);
+ getMethodMap().remove(methodName);
+ }
+ }
+ else if (child.getNodeName().compareTo(Utils.ELEMENT_CODEGEN) == 0)
+ {
+ String value = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_VALUE);
+ if (value.compareTo("no-gen") == 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void removeVersion(AmqpVersion version)
+ {
+ getIndexMap().removeVersion(version);
+ getFieldMap().removeVersion(version);
+ getMethodMap().removeVersion(version);
+ getVersionSet().remove(version);
+ }
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ String margin = Utils.createSpaces(marginSize);
+ String tab = Utils.createSpaces(tabSize);
+ out.println(margin + "[C] " + getName() + ": " + getVersionSet());
+
+ for (Integer thisIndex : getIndexMap().keySet())
+ {
+ AmqpVersionSet indexVersionSet = getIndexMap().get(thisIndex);
+ out.println(margin + tab + "[I] " + thisIndex + indexVersionSet);
+ }
+
+ for (String thisFieldName : getFieldMap().keySet())
+ {
+ AmqpField thisField = getFieldMap().get(thisFieldName);
+ thisField.print(out, marginSize + tabSize, tabSize);
+ }
+
+ for (String thisMethodName : getMethodMap().keySet())
+ {
+ AmqpMethod thisMethod = getMethodMap().get(thisMethodName);
+ thisMethod.print(out, marginSize + tabSize, tabSize);
+ }
+ }
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ public Generator getGenerator()
+ {
+ return _generator;
+ }
+
+
+ public AmqpFieldMap getFieldMap()
+ {
+ return _fieldMap;
+ }
+
+
+ public AmqpMethodMap getMethodMap()
+ {
+ return _methodMap;
+ }
+
+ public Collection<AmqpMethod> getMethods()
+ {
+ return getMethodMap().values();
+ }
+
+
+ public String getName()
+ {
+ return _name;
+ }
+
+
+ public AmqpOrdinalVersionMap getIndexMap()
+ {
+ return _indexMap;
+ }
+
+ public SingleVersionClass asSingleVersionClass(AmqpVersion version)
+ {
+ return new SingleVersionClass(this,version, _generator);
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java
new file mode 100644
index 0000000000..a27a50d07e
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpClassMap.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpClassMap extends TreeMap<String, AmqpClass>
+{
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpConstant.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpConstant.java
new file mode 100644
index 0000000000..df5bc6c362
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpConstant.java
@@ -0,0 +1,191 @@
+/*
+ *
+ * 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.PrintStream;
+import java.util.TreeMap;
+
+/**
+ * @author kpvdr
+ * Class to represent the &lt;constant&gt; declaration within the AMQP specification.
+ * Currently, only integer values exist within the specification, however looking forward
+ * to other possible types in the future, string and double types are also supported.
+ * <p/>
+ * The &lt;constant&gt; declaration in the specification contains only two attributes:
+ * name and value.
+ * <p/>
+ * The value of the constant is mapped against the version(s) for which the name is defined.
+ * This allows for a change in the value rather than the name only from one version to the next.
+ */
+@SuppressWarnings("serial")
+public class AmqpConstant extends TreeMap<String, AmqpVersionSet>
+ implements Printable, VersionConsistencyCheck, Comparable<AmqpConstant>
+{
+ /**
+ * Constant name as defined by the name attribute of the &lt;constant&gt; declaration.
+ */
+ private final String _name;
+
+ /**
+ * Set of versions for which this constant name is defined.
+ */
+ private final AmqpVersionSet _versionSet;
+
+ /**
+ * Constructor
+ *
+ * @param name Constant name as defined by the name attribute of the &lt;constant&gt; declaration.
+ * @param value Constant value as defined by the value attribute of the &lt;constant&gt; declaration.
+ * @param version AMQP version for which this constant is defined
+ */
+ public AmqpConstant(String name, String value, AmqpVersion version)
+ {
+ _name = name;
+ _versionSet = new AmqpVersionSet(version);
+ AmqpVersionSet valueVersionSet = new AmqpVersionSet(version);
+ put(value, valueVersionSet);
+ }
+
+
+ /**
+ * Get the name of this constant.
+ *
+ * @return Name of this constant, being the name attribute of the &lt;constant&gt; declaration
+ * represented by this class.
+ */
+ public String getName()
+ {
+ return _name;
+ }
+
+ /**
+ * Get the value of this constant as a String.
+ *
+ * @param version AMQP version for which this value is required.
+ * @return Value of this constant, being the value attribute of the &lt;constant&gt; declaration
+ * represented by this class.
+ * @throws AmqpTypeMappingException when a value is requested for a version for which it is not
+ * defined in the AMQP specifications.
+ */
+ public String getStringValue(AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ for (String thisValue : keySet())
+ {
+ AmqpVersionSet versionSet = get(thisValue);
+ if (versionSet.contains(version))
+ {
+ return thisValue;
+ }
+ }
+ throw new AmqpTypeMappingException("Unable to find value for constant \"" + getName() +
+ "\" for version " + version.toString() + ".");
+ }
+
+ /**
+ * Get the value of this constant as an integer.
+ *
+ * @param version AMQP version for which this value is required.
+ * @return Value of this constant, being the value attribute of the &lt;constant&gt; declaration
+ * represented by this class.
+ * @throws AmqpTypeMappingException when a value is requested for a version for which it is not
+ * defined in the AMQP specifications.
+ */
+ public int getIntegerValue(AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ return Integer.parseInt(getStringValue(version));
+ }
+
+ /**
+ * Get the value of this constant as a double.
+ *
+ * @param version AMQP version for which this value is required.
+ * @return Value of this constant, being the value attribute of the &lt;constant&gt; declaration
+ * represented by this class.
+ * @throws AmqpTypeMappingException when a value is requested for a version for which it is not
+ * defined in the AMQP specifications.
+ */
+ public double getDoubleValue(AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ return Double.parseDouble(getStringValue(version));
+ }
+
+ /**
+ * Get the version set for this constant. It contains the all the versions for which this
+ * constant name exists.
+ *
+ * @return Set of versions for which this constant exists.
+ */
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+
+ public int compareTo(AmqpConstant other)
+ {
+ int res = getName().compareTo(other.getName());
+ if (res != 0)
+ {
+ return res;
+ }
+ return getVersionSet().compareTo(other.getVersionSet());
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.qpid.gentools.VersionConsistencyCheck#isVersionConsistent(org.apache.qpid.gentools.AmqpVersionSet)
+ */
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (size() != 1)
+ {
+ return false;
+ }
+ return get(firstKey()).equals(globalVersionSet);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.qpid.gentools.Printable#print(java.io.PrintStream, int, int)
+ */
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ String margin = Utils.createSpaces(marginSize);
+ String tab = Utils.createSpaces(tabSize);
+ if (size() == 1)
+ {
+ out.println(margin + tab + "[C] " + getName() + " = \"" + firstKey() + "\" " + getVersionSet());
+ }
+ else
+ {
+ out.println(margin + tab + "[C] " + getName() + ": " + getVersionSet());
+ for (String thisValue : keySet())
+ {
+ out.println(margin + tab + tab + "= \"" + thisValue + "\" " + get(thisValue));
+ }
+ }
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java
new file mode 100644
index 0000000000..ab8b8be61e
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpConstantSet.java
@@ -0,0 +1,152 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+/**
+ * @author kpvdr
+ * This class implements a set collection for {@link AmqpConstant AmqpConstant} objects, being the collection
+ * of constants accumulated from various AMQP specification files processed. Each name occurs once only in the set.
+ * The {@link AmqpConstant AmqpConstant} objects (derived from {@link java.util.TreeMap TreeMap}) keep track of
+ * the value and version(s) assigned to this name.
+ */
+@SuppressWarnings("serial")
+public class AmqpConstantSet implements Printable, NodeAware //, Comparable<AmqpConstantSet>
+{
+ private final LanguageConverter _converter;
+ private final TreeSet<AmqpConstant> _constants = new TreeSet<AmqpConstant>();
+ private final AmqpVersionSet _versionSet = new AmqpVersionSet();
+
+ public AmqpConstantSet(LanguageConverter converter)
+ {
+ _converter = converter;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.qpid.gentools.NodeAware#addFromNode(org.w3c.dom.Node, int, org.apache.qpid.gentools.AmqpVersion)
+ */
+ public boolean addFromNode(Node node, int ordinal, AmqpVersion version)
+ throws AmqpParseException, AmqpTypeMappingException
+ {
+ _versionSet.add(version);
+ NodeList nodeList = node.getChildNodes();
+ for (int i = 0; i < nodeList.getLength(); i++)
+ {
+ Node childNode = nodeList.item(i);
+ if (childNode.getNodeName().compareTo(Utils.ELEMENT_CONSTANT) == 0)
+ {
+ String name = getConverter().prepareConstantName(Utils.getNamedAttribute(childNode, Utils.ATTRIBUTE_NAME));
+ String value = Utils.getNamedAttribute(childNode, Utils.ATTRIBUTE_VALUE);
+ // Find this name in the existing set of objects
+ boolean foundName = false;
+ Iterator<AmqpConstant> cItr = _constants.iterator();
+ while (cItr.hasNext() && !foundName)
+ {
+ AmqpConstant thisConstant = cItr.next();
+ if (name.compareTo(thisConstant.getName()) == 0)
+ {
+ foundName = true;
+ thisConstant.getVersionSet().add(version);
+ // Now, find the value in the map
+ boolean foundValue = false;
+ for (String thisValue : thisConstant.keySet())
+ {
+ if (value.compareTo(thisValue) == 0)
+ {
+ foundValue = true;
+ // Add this version to existing version set.
+ AmqpVersionSet versionSet = thisConstant.get(thisValue);
+ versionSet.add(version);
+ }
+ }
+ // Check that the value was found - if not, add it
+ if (!foundValue)
+ {
+ thisConstant.put(value, new AmqpVersionSet(version));
+ }
+ }
+ }
+ // Check that the name was found - if not, add it
+ if (!foundName)
+ {
+ _constants.add(new AmqpConstant(name, value, version));
+ }
+ }
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.qpid.gentools.Printable#print(java.io.PrintStream, int, int)
+ */
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ out.println(Utils.createSpaces(marginSize) + "Constants: ");
+ for (AmqpConstant thisAmqpConstant : _constants)
+ {
+ thisAmqpConstant.print(out, marginSize, tabSize);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+// public int compareTo(AmqpConstantSet other)
+// {
+// int res = size() - other.size();
+// if (res != 0)
+// return res;
+// Iterator<AmqpConstant> cItr = iterator();
+// Iterator<AmqpConstant> oItr = other.iterator();
+// while (cItr.hasNext() && oItr.hasNext())
+// {
+// AmqpConstant constant = cItr.next();
+// AmqpConstant oConstant = oItr.next();
+// res = constant.compareTo(oConstant);
+// if (res != 0)
+// return res;
+// }
+// return 0;
+// }
+
+ public Iterable<? extends AmqpConstant> getContstants()
+ {
+ return _constants;
+ }
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ public LanguageConverter getConverter()
+ {
+ return _converter;
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomain.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomain.java
new file mode 100644
index 0000000000..ba8552a6a6
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomain.java
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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.PrintStream;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpDomain extends TreeMap<String, AmqpVersionSet> implements Printable
+{
+ private final String _domainName;
+
+ public AmqpDomain(String domainName)
+ {
+ _domainName = domainName;
+ }
+
+ public void addDomain(String domainType, AmqpVersion version) throws AmqpParseException
+ {
+ AmqpVersionSet versionSet = get(domainType);
+ if (versionSet == null) // First time, create new entry
+ {
+ versionSet = new AmqpVersionSet();
+ put(domainType, versionSet);
+ }
+ versionSet.add(version);
+ }
+
+ public String getDomainType(AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ for (String thisDomainType : keySet())
+ {
+ AmqpVersionSet versionSet = get(thisDomainType);
+ if (versionSet.contains(version))
+ {
+ return thisDomainType;
+ }
+ }
+ throw new AmqpTypeMappingException("Unable to find version " + version + ".");
+ }
+
+ public boolean hasVersion(String type, AmqpVersion v)
+ {
+ AmqpVersionSet vs = get(type);
+ if (vs == null)
+ {
+ return false;
+ }
+ return vs.contains(v);
+ }
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ String margin = Utils.createSpaces(marginSize);
+ String tab = Utils.createSpaces(tabSize);
+ out.println(margin + getDomainName() + ":");
+
+ for (String thisDomainType : keySet())
+ {
+ AmqpVersionSet vs = get(thisDomainType);
+ out.println(margin + tab + thisDomainType + " : " + vs.toString());
+ }
+ }
+
+ public String getDomainName()
+ {
+ return _domainName;
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java
new file mode 100644
index 0000000000..0cd9d214bd
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainMap.java
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.PrintStream;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpDomainMap extends TreeMap<String, AmqpDomain> implements Printable, NodeAware
+{
+ private final LanguageConverter _converter;
+
+ public AmqpDomainMap(LanguageConverter converter)
+ {
+ _converter = converter;
+
+ }
+
+ public boolean addFromNode(Node n, int o, AmqpVersion v)
+ throws AmqpParseException, AmqpTypeMappingException
+ {
+ NodeList nl = n.getChildNodes();
+ for (int i = 0; i < nl.getLength(); i++)
+ {
+ Node c = nl.item(i);
+ // All versions 0.9 and greater use <domain> for all domains
+ if (c.getNodeName().compareTo(Utils.ELEMENT_DOMAIN) == 0)
+ {
+ String domainName = getConverter().prepareDomainName(Utils.getNamedAttribute(c, Utils.ATTRIBUTE_NAME));
+ String type = Utils.getNamedAttribute(c, Utils.ATTRIBUTE_TYPE);
+ AmqpDomain thisDomain = get(domainName);
+ if (thisDomain == null)
+ {
+ thisDomain = new AmqpDomain(domainName);
+ put(domainName, thisDomain);
+ }
+ thisDomain.addDomain(type, v);
+ }
+ // Version(s) 0.8 and earlier use <domain> for all complex domains and use
+ // attribute <field type=""...> for simple types. Add these simple types to
+ // domain list - but beware of duplicates!
+ else if (c.getNodeName().compareTo(Utils.ELEMENT_FIELD) == 0)
+ {
+ try
+ {
+ String type = getConverter().prepareDomainName(Utils.getNamedAttribute(c, Utils.ATTRIBUTE_TYPE));
+ AmqpDomain thisDomain = get(type);
+ if (thisDomain == null)
+ {
+ thisDomain = new AmqpDomain(type);
+ put(type, thisDomain);
+ }
+ if (!thisDomain.hasVersion(type, v))
+ {
+ thisDomain.addDomain(type, v);
+ }
+ }
+ catch (AmqpParseException e)
+ {
+ } // Ignore fields without type attribute
+ }
+ else if (c.getNodeName().compareTo(Utils.ELEMENT_CLASS) == 0 ||
+ c.getNodeName().compareTo(Utils.ELEMENT_METHOD) == 0)
+ {
+ addFromNode(c, 0, v);
+ }
+ }
+ return true;
+ }
+
+ public String getDomainType(String domainName, AmqpVersion version)
+ {
+ AmqpDomain domainType = get(domainName);
+ // For AMQP 8.0, primitive types were not described as domains, so
+ // return itself as the type.
+ if (domainType == null)
+ {
+ return domainName;
+ }
+ try
+ {
+ return domainType.getDomainType(version);
+ }
+ catch (AmqpTypeMappingException e)
+ {
+ throw new AmqpTypeMappingException("Unable to find domain type for domain \"" + domainName +
+ "\" version " + version + ".");
+ }
+ }
+
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ out.println(Utils.createSpaces(marginSize) + "Domain Map:");
+ for (String thisDomainName : keySet())
+ {
+ AmqpDomain domain = get(thisDomainName);
+ domain.print(out, marginSize + tabSize, tabSize);
+ }
+ }
+
+ public LanguageConverter getConverter()
+ {
+ return _converter;
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java
new file mode 100644
index 0000000000..e39550b96f
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpDomainVersionMap.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.util.ArrayList;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpDomainVersionMap extends TreeMap<String, AmqpVersionSet> implements VersionConsistencyCheck
+{
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (size() != 1)
+ {
+ return false;
+ }
+ return get(firstKey()).equals(globalVersionSet);
+ }
+
+ public boolean removeVersion(AmqpVersion version)
+ {
+ Boolean res = false;
+ ArrayList<String> removeList = new ArrayList<String>();
+ for (String domainName : keySet())
+ {
+ AmqpVersionSet versionSet = get(domainName);
+ if (versionSet.contains(version))
+ {
+ versionSet.remove(version);
+ if (versionSet.isEmpty())
+ {
+ removeList.add(domainName);
+ }
+ res = true;
+ }
+ }
+ // Get rid of domains no longer in use
+ for (String domainName : removeList)
+ {
+ remove(domainName);
+ }
+ return res;
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpField.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpField.java
new file mode 100644
index 0000000000..7c721cf913
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpField.java
@@ -0,0 +1,269 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class AmqpField implements Printable, NodeAware, VersionConsistencyCheck
+{
+
+ private final AmqpVersionSet _versionSet = new AmqpVersionSet();
+ private final AmqpDomainVersionMap _domainMap = new AmqpDomainVersionMap();
+ private final AmqpOrdinalVersionMap _ordinalMap = new AmqpOrdinalVersionMap();
+
+ private final String _name;
+ private final Generator _generator;
+
+ private final Map<AmqpVersion, String> _versionToDomainMap = new HashMap<AmqpVersion, String>();
+ private final Map<AmqpVersion, Integer> _versionToOrdinalMap = new HashMap<AmqpVersion, Integer>();
+
+
+ public AmqpField(String name, Generator generator)
+ {
+ _name = name;
+ _generator = generator;
+
+ }
+
+ public boolean addFromNode(Node fieldNode, int ordinal, AmqpVersion version)
+ throws AmqpParseException, AmqpTypeMappingException
+ {
+ _versionSet.add(version);
+ String domainType;
+ // Early versions of the spec (8.0) used the "type" attribute instead of "domain" for some fields.
+ try
+ {
+ domainType = _generator.prepareDomainName(Utils.getNamedAttribute(fieldNode, Utils.ATTRIBUTE_DOMAIN));
+ }
+ catch (AmqpParseException e)
+ {
+ domainType = _generator.prepareDomainName(Utils.getNamedAttribute(fieldNode, Utils.ATTRIBUTE_TYPE));
+ }
+ AmqpVersionSet thisVersionList = _domainMap.get(domainType);
+ if (thisVersionList == null) // First time, create new entry
+ {
+ thisVersionList = new AmqpVersionSet();
+ _domainMap.put(domainType, thisVersionList);
+ }
+
+ _versionToDomainMap.put(version, domainType);
+ _versionToOrdinalMap.put(version, ordinal);
+
+ thisVersionList.add(version);
+ thisVersionList = _ordinalMap.get(ordinal);
+ if (thisVersionList == null) // First time, create new entry
+ {
+ thisVersionList = new AmqpVersionSet();
+ _ordinalMap.put(ordinal, thisVersionList);
+ }
+ thisVersionList.add(version);
+ NodeList nList = fieldNode.getChildNodes();
+ for (int i = 0; i < nList.getLength(); i++)
+ {
+ Node child = nList.item(i);
+ if (child.getNodeName().compareTo(Utils.ELEMENT_CODEGEN) == 0)
+ {
+ String value = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_VALUE);
+ if (value.compareTo("no-gen") == 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void removeVersion(AmqpVersion version)
+ {
+ _domainMap.removeVersion(version);
+ _ordinalMap.removeVersion(version);
+ _versionSet.remove(version);
+ }
+
+ public boolean isCodeTypeConsistent(LanguageConverter converter)
+ throws AmqpTypeMappingException
+ {
+ if (_domainMap.size() == 1)
+ {
+ return true; // By definition
+ }
+ ArrayList<String> codeTypeList = new ArrayList<String>();
+ for (String thisDomainName : _domainMap.keySet())
+ {
+ AmqpVersionSet versionSet = _domainMap.get(thisDomainName);
+ String codeType = converter.getGeneratedType(thisDomainName, versionSet.first());
+ if (!codeTypeList.contains(codeType))
+ {
+ codeTypeList.add(codeType);
+ }
+ }
+ return codeTypeList.size() == 1;
+ }
+
+ public boolean isConsistent(Generator generator)
+ throws AmqpTypeMappingException
+ {
+ if (!isCodeTypeConsistent(generator))
+ {
+ return false;
+ }
+ if (_ordinalMap.size() != 1)
+ {
+ return false;
+ }
+ // Since the various doamin names map to the same code type, add the version occurrences
+ // across all domains to see we have all possible versions covered
+ int vCntr = 0;
+ for (String thisDomainName : _domainMap.keySet())
+ {
+ vCntr += _domainMap.get(thisDomainName).size();
+ }
+ return vCntr == generator.getVersionSet().size();
+ }
+
+ public boolean isTypeAndNameConsistent(Generator generator)
+ throws AmqpTypeMappingException
+ {
+ if (!isCodeTypeConsistent(generator))
+ {
+ return false;
+ }
+ // Since the various doamin names map to the same code type, add the version occurrences
+ // across all domains to see we have all possible versions covered
+ int vCntr = 0;
+ for (String thisDomainName : _domainMap.keySet())
+ {
+ vCntr += _domainMap.get(thisDomainName).size();
+ }
+ return vCntr == getVersionSet().size();
+ }
+
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ String margin = Utils.createSpaces(marginSize);
+ out.println(margin + "[F] " + _name + ": " + _versionSet);
+
+ for (Integer thisOrdinal : _ordinalMap.keySet())
+ {
+ AmqpVersionSet versionList = _ordinalMap.get(thisOrdinal);
+ out.println(margin + " [O] " + thisOrdinal + " : " + versionList.toString());
+ }
+
+ for (String thisDomainName : _domainMap.keySet())
+ {
+ AmqpVersionSet versionList = _domainMap.get(thisDomainName);
+ out.println(margin + " [D] " + thisDomainName + " : " + versionList.toString());
+ }
+ }
+
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (!_versionSet.equals(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_domainMap.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_ordinalMap.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ public boolean isVersionInterfaceConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (!_versionSet.equals(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_domainMap.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_ordinalMap.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public String getDomain(AmqpVersion version)
+ {
+ return _versionToDomainMap.get(version);
+ }
+
+ public String getConsistentNativeType()
+ {
+ return _generator.getNativeType(_generator.getDomainType(getDomain(_versionSet.first()),_versionSet.first()));
+ }
+
+ public int getOrdinal(AmqpVersion version)
+ {
+ return _versionToOrdinalMap.get(version);
+ }
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ public AmqpDomainVersionMap getDomainMap()
+ {
+ return _domainMap;
+ }
+
+ public AmqpOrdinalVersionMap getOrdinalMap()
+ {
+ return _ordinalMap;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public LanguageConverter getGenerator()
+ {
+ return _generator;
+ }
+
+ public Map<AmqpVersion, String> getVersionToDomainMap()
+ {
+ return _versionToDomainMap;
+ }
+
+ public Map<AmqpVersion, Integer> getVersionToOrdinalMap()
+ {
+ return _versionToOrdinalMap;
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java
new file mode 100644
index 0000000000..0bb5e03a61
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpFieldMap.java
@@ -0,0 +1,452 @@
+/*
+ *
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpFieldMap implements VersionConsistencyCheck
+{
+
+ private final TreeMap<String, AmqpField> _map = new TreeMap<String, AmqpField>();
+
+ private final AmqpVersionSet _versionSet = new AmqpVersionSet();
+
+ public void removeVersion(AmqpVersion version)
+ {
+ String[] fieldNameArray = new String[size()];
+ _map.keySet().toArray(fieldNameArray);
+ Iterator<Entry<String, AmqpField>> iter = _map.entrySet().iterator();
+
+ while (iter.hasNext())
+ {
+ Entry<String, AmqpField> entry = iter.next();
+ entry.getValue().removeVersion(version);
+ iter.remove();
+ }
+ }
+
+ public int size()
+ {
+ return _map.size();
+
+ }
+
+ public AmqpFieldMap getFieldMapForOrdinal(int ordinal)
+ {
+ AmqpFieldMap newMap = new AmqpFieldMap();
+ for (AmqpField field : _map.values())
+ {
+
+ TreeMap<Integer, AmqpVersionSet> ordinalMap = field.getOrdinalMap();
+ AmqpVersionSet ordinalVersions = ordinalMap.get(ordinal);
+ if (ordinalVersions != null)
+ {
+ newMap.add(field.getName(), field);
+ }
+ }
+ return newMap;
+ }
+
+ public void add(String name, AmqpField field)
+ {
+ _versionSet.addAll(field.getVersionSet());
+ _map.put(name, field);
+ }
+
+ public AmqpOrdinalFieldMap getMapForVersion(AmqpVersion version, boolean codeTypeFlag,
+ LanguageConverter converter)
+ {
+ // TODO: REVIEW THIS! There may be a bug here that affects C++ generation (only with >1 version)...
+ // If version == null (a common scenario) then the version map is built up on the
+ // basis of first found item, and ignores other version variations.
+ // This should probably be disallowed by throwing an NPE, as AmqpOrdinalFieldMap cannot
+ // represent these possibilities.
+ // *OR*
+ // Change the structure of AmqpOrdianlFieldMap to allow for the various combinations that
+ // will result from version variation - but that is what AmqpFieldMap is... :-$
+ AmqpOrdinalFieldMap ordinalFieldMap = new AmqpOrdinalFieldMap();
+ for (AmqpField field : _map.values())
+ {
+
+ if (version == null || field.getVersionSet().contains(version))
+ {
+ // 1. Search for domain name in field domain map with version that matches
+ String domain = "";
+ boolean dFound = false;
+ for (String thisDomainName : field.getDomainMap().keySet())
+ {
+ domain = thisDomainName;
+ AmqpVersionSet versionSet = field.getDomainMap().get(domain);
+ if (version == null || versionSet.contains(version))
+ {
+ if (codeTypeFlag)
+ {
+ domain = converter.getGeneratedType(domain, version);
+ }
+ dFound = true;
+ }
+ }
+
+ // 2. Search for ordinal in field ordianl map with version that matches
+ int ordinal = -1;
+ boolean oFound = false;
+ for (Integer thisOrdinal : field.getOrdinalMap().keySet())
+ {
+ ordinal = thisOrdinal;
+ AmqpVersionSet versionSet = field.getOrdinalMap().get(ordinal);
+ if (version == null || versionSet.contains(version))
+ {
+ oFound = true;
+ }
+ }
+
+ if (dFound && oFound)
+ {
+ String[] fieldDomainPair = {field.getName(), domain};
+ ordinalFieldMap.put(ordinal, fieldDomainPair);
+ }
+ }
+ }
+ return ordinalFieldMap;
+ }
+
+ public boolean isDomainConsistent(Generator generator, AmqpVersionSet versionSet)
+ throws AmqpTypeMappingException
+ {
+ if (size() != 1) // Only one field for this ordinal
+ {
+ return false;
+ }
+ return _map.get(_map.firstKey()).isConsistent(generator);
+ }
+
+ public int getNumFields(AmqpVersion version)
+ {
+ int fCntr = 0;
+ for (AmqpField field : _map.values())
+ {
+
+ if (field.getVersionSet().contains(version))
+ {
+ fCntr++;
+ }
+ }
+ return fCntr;
+ }
+
+ public String parseFieldMap(CommandGenerateMethod commonGenerateMethod, MangledGenerateMethod mangledGenerateMethod,
+ int indentSize, int tabSize, LanguageConverter converter)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String cr = Utils.LINE_SEPARATOR;
+ StringBuffer sb = new StringBuffer();
+
+ if (commonGenerateMethod == null)
+ {
+ // Generate warnings in code if required methods are null.
+ sb.append(indent + "/*********************************************************" + cr);
+ sb.append(indent + " * WARNING: Generated code could be missing." + cr);
+ sb.append(indent + " * In call to parseFieldMap(), generation method was null." + cr);
+ sb.append(indent + " * Check for NoSuchMethodException on startup." + cr);
+ sb.append(indent + " *********************************************************/" + cr);
+ }
+
+ Iterator<Entry<String, AmqpField>> itr = _map.entrySet().iterator();
+ while (itr.hasNext())
+ {
+ Entry<String, AmqpField> entry = itr.next();
+ String fieldName = entry.getKey();
+ AmqpField field = entry.getValue();
+ if (field.isCodeTypeConsistent(converter))
+ {
+ // All versions identical - Common declaration
+ String domainName = field.getDomainMap().firstKey();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ String codeType = converter.getGeneratedType(domainName, versionSet.first());
+ if (commonGenerateMethod != null)
+ {
+ sb.append(commonGenerateMethod.generate(codeType, field, versionSet,
+ indentSize, tabSize, itr.hasNext()));
+ }
+ }
+ else if (mangledGenerateMethod != null) // Version-mangled
+ {
+ sb.append(mangledGenerateMethod.generate(field, indentSize, tabSize,
+ itr.hasNext()));
+ }
+ }
+ return sb.toString();
+ }
+
+ public String parseFieldMapOrdinally(GenerateMethod generateMethod, BitFieldGenerateMethod bitGenerateMethod,
+ int indentSize, int tabSize, Generator codeGenerator)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String cr = Utils.LINE_SEPARATOR;
+ StringBuffer sb = new StringBuffer();
+
+ // Generate warnings in code if required methods are null.
+ if (generateMethod == null || bitGenerateMethod == null)
+ {
+ sb.append(indent + "/***********************************************" + cr);
+ sb.append(indent + " * WARNING: In call to parseFieldMapOrdinally():" + cr);
+ if (generateMethod == null)
+ {
+ sb.append(indent + " * => generateMethod is null." + cr);
+ }
+ if (bitGenerateMethod == null)
+ {
+ sb.append(indent + " * => bitGenerateMethod is null." + cr);
+ }
+ sb.append(indent + " * Generated code could be missing." + cr);
+ sb.append(indent + " * Check for NoSuchMethodException on startup." + cr);
+ sb.append(indent + " ***********************************************/" + cr);
+ }
+
+ /* We must process elements in ordinal order because adjacent booleans (bits)
+ * must be combined into a single byte (in groups of up to 8). Start with shared
+ * declarations until an ordinal divergence is found. (For most methods where
+ * there is no difference between versions, this will simplify the generated
+ * code. */
+
+ ArrayList<String> bitFieldList = new ArrayList<String>();
+ boolean ordinalDivergenceFlag = false;
+ int ordinal = 0;
+ while (ordinal < size() && !ordinalDivergenceFlag)
+ {
+ /* Since the getFieldMapOrdinal() function may map more than one Field to
+ * an ordinal, the number of ordinals may be less than the total number of
+ * fields in the fieldMap. Check for empty fieldmaps... */
+ AmqpFieldMap ordinalFieldMap = getFieldMapForOrdinal(ordinal);
+ if (ordinalFieldMap.size() > 0)
+ {
+ if (ordinalFieldMap.isDomainConsistent(codeGenerator, getVersionSet()))
+ {
+ String fieldName = ordinalFieldMap.getFirstFieldName();
+ String domain = ordinalFieldMap._map.get(fieldName).getDomainMap().firstKey();
+
+ String domainType = codeGenerator.getDomainType(domain,
+ codeGenerator.getVersionSet().first());
+
+ if (domainType.compareTo("bit") == 0)
+ {
+ bitFieldList.add(fieldName);
+ }
+ else if (bitFieldList.size() > 0)
+ {
+ // End of bit types - handle deferred bit type generation
+ if (bitGenerateMethod != null)
+ {
+ sb.append(bitGenerateMethod.generate(bitFieldList, ordinal,
+ indentSize, tabSize));
+ }
+ bitFieldList.clear();
+ }
+ if (!ordinalDivergenceFlag)
+ {
+ // Defer generation of bit types until all adjacent bits have been
+ // accounted for.
+ if (bitFieldList.size() == 0 && generateMethod != null)
+ {
+ sb.append(generateMethod.generate(domainType, fieldName, ordinal,
+ indentSize, tabSize));
+ }
+ }
+ ordinal++;
+ }
+ else
+ {
+ ordinalDivergenceFlag = true;
+ }
+ }
+ }
+
+ // Check if there is still more to do under a version-specific breakout
+ if (ordinalDivergenceFlag && ordinal < size())
+ {
+ // 1. Cycle through all versions in order, create outer if(version) structure
+ AmqpVersion[] versionArray = new AmqpVersion[getVersionSet().size()];
+ getVersionSet().toArray(versionArray);
+ for (int v = 0; v < versionArray.length; v++)
+ {
+ sb.append(indent);
+ if (v > 0)
+ {
+ sb.append("else ");
+ }
+ sb.append("if (major == " + versionArray[v].getMajor() + " && minor == " +
+ versionArray[v].getMinor() + ")" + cr);
+ sb.append(indent + "{" + cr);
+
+ // 2. Cycle though each ordinal from where we left off in the loop above.
+ ArrayList<String> bitFieldList2 = new ArrayList<String>(bitFieldList);
+ for (int o = ordinal; o < size(); o++)
+ {
+ AmqpFieldMap ordinalFieldMap = getFieldMapForOrdinal(o);
+ if (ordinalFieldMap.size() > 0)
+ {
+ // 3. Cycle through each of the fields that have this ordinal.
+ Iterator<Map.Entry<String, AmqpField>> i = ordinalFieldMap._map.entrySet().iterator();
+ while (i.hasNext())
+ {
+
+ Map.Entry<String, AmqpField> entry = i.next();
+ AmqpField field = entry.getValue();
+ String fieldName = entry.getKey();
+
+ // 4. Some fields may have more than one ordinal - match by both
+ // ordinal and version.
+ Iterator<Integer> j = field.getOrdinalMap().keySet().iterator();
+ while (j.hasNext())
+ {
+ int thisOrdinal = j.next();
+ AmqpVersionSet v1 = field.getOrdinalMap().get(thisOrdinal);
+ if (thisOrdinal == o && v1.contains(versionArray[v]))
+ {
+ // 5. Now get the domain for this version
+ int domainCntr = 0;
+ Iterator<String> k = field.getDomainMap().keySet().iterator();
+ while (k.hasNext())
+ {
+ // Mangle domain-divergent field names
+ String mangledFieldName = fieldName;
+ if (field.getDomainMap().size() > 1)
+ {
+ mangledFieldName += "_" + (domainCntr++);
+ }
+ String domainName = k.next();
+ AmqpVersionSet v2 = field.getDomainMap().get(domainName);
+ if (v2.contains(versionArray[v]))
+ {
+ // 6. (Finally!!) write the declaration
+ String domainType = codeGenerator.getDomainType(domainName,
+ versionArray[v]);
+ if (domainType.compareTo("bit") == 0)
+ {
+ bitFieldList2.add(mangledFieldName);
+ }
+ else if (bitFieldList2.size() > 0)
+ {
+ // End of bit types - handle deferred bit type generation
+ if (bitGenerateMethod != null)
+ {
+ sb.append(bitGenerateMethod.generate(
+ bitFieldList2, o, indentSize + tabSize,
+ tabSize));
+ }
+ bitFieldList2.clear();
+ }
+ // Defer generation of bit types until all adjacent bits have
+ // been accounted for.
+ if (bitFieldList2.size() == 0 && generateMethod != null)
+ {
+ sb.append(generateMethod.generate(domainType,
+ mangledFieldName, o, indentSize + tabSize, tabSize));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // Check for remaining deferred bits
+ if (bitFieldList2.size() > 0 && bitGenerateMethod != null)
+ {
+ sb.append(bitGenerateMethod.generate(bitFieldList2, size(),
+ indentSize + tabSize, tabSize));
+ }
+ sb.append(indent + "}" + cr);
+ }
+ }
+ // Check for remaining deferred bits
+ else if (bitFieldList.size() > 0 && bitGenerateMethod != null)
+ {
+ sb.append(bitGenerateMethod.generate(bitFieldList, size(),
+ indentSize, tabSize));
+ }
+ return sb.toString();
+ }
+
+ private String getFirstFieldName()
+ {
+ return _map.firstKey();
+ }
+
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ for (String thisFieldName : _map.keySet())
+ {
+ AmqpField field = _map.get(thisFieldName);
+ if (!field.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isVersionInterfaceConsistent(AmqpVersionSet globalVersionSet)
+ {
+ for (String thisFieldName : _map.keySet())
+ {
+ AmqpField field = _map.get(thisFieldName);
+ if (!field.isVersionInterfaceConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ public Collection<AmqpField> values()
+ {
+ return _map.values();
+ }
+
+ public AmqpField get(String fieldName)
+ {
+ return _map.get(fieldName);
+ }
+
+ public void remove(String fieldName)
+ {
+ _map.remove(fieldName);
+ }
+
+ public Set<String> keySet()
+ {
+ return _map.keySet();
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java
new file mode 100644
index 0000000000..5993a1b715
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpFlagMap.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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.util.ArrayList;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpFlagMap extends TreeMap<Boolean, AmqpVersionSet> implements VersionConsistencyCheck
+{
+ public boolean isSet()
+ {
+ return containsKey(true);
+ }
+
+ public String toString()
+ {
+ AmqpVersionSet versionSet = get(true);
+ if (versionSet != null)
+ {
+ return versionSet.toString();
+ }
+ return "";
+ }
+
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (size() != 1)
+ {
+ return false;
+ }
+ return get(firstKey()).equals(globalVersionSet);
+ }
+
+ public boolean removeVersion(AmqpVersion version)
+ {
+ Boolean res = false;
+ ArrayList<Boolean> removeList = new ArrayList<Boolean>();
+ for (Boolean flag : keySet())
+ {
+ AmqpVersionSet versionSet = get(flag);
+ if (versionSet.contains(version))
+ {
+ versionSet.remove(version);
+ if (versionSet.isEmpty())
+ {
+ removeList.add(flag);
+ }
+ res = true;
+ }
+ }
+ // Get rid of flags no longer in use
+ for (Boolean flag : removeList)
+ {
+ remove(flag);
+ }
+ return res;
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpMethod.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpMethod.java
new file mode 100644
index 0000000000..4ec39b209e
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpMethod.java
@@ -0,0 +1,351 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class AmqpMethod implements Printable, NodeAware, VersionConsistencyCheck
+{
+ private final AmqpVersionSet _versionSet = new AmqpVersionSet();
+ private final AmqpFieldMap _fieldMap = new AmqpFieldMap();
+
+ private final AmqpOrdinalVersionMap _indexMap = new AmqpOrdinalVersionMap();
+ private final AmqpFlagMap _clientMethodFlagMap = new AmqpFlagMap(); // Method called on client (<chassis name="server"> in XML)
+ private final AmqpFlagMap _serverMethodFlagMap = new AmqpFlagMap(); // Method called on server (<chassis name="client"> in XML)
+
+ private final Map<AmqpVersion, AmqpFieldMap> _versionToFieldsMap = new HashMap<AmqpVersion, AmqpFieldMap>();
+
+ private final Map<AmqpVersion, AtomicInteger> _versionToFieldCount = new HashMap<AmqpVersion, AtomicInteger>();
+
+ private final String _name;
+ private final Generator _generator;
+
+
+ public AmqpMethod(String name, Generator generator)
+ {
+ _name = name;
+ _generator = generator;
+ }
+
+ public boolean addFromNode(Node methodNode, int ordinal, AmqpVersion version)
+ throws AmqpParseException, AmqpTypeMappingException
+ {
+ _versionSet.add(version);
+ boolean serverChassisFlag = false;
+ boolean clientChassisFlag = false;
+ int index = Utils.getNamedIntegerAttribute(methodNode, "index");
+ AmqpVersionSet indexVersionSet = _indexMap.get(index);
+ if (indexVersionSet != null)
+ {
+ indexVersionSet.add(version);
+ }
+ else
+ {
+ indexVersionSet = new AmqpVersionSet();
+ indexVersionSet.add(version);
+ _indexMap.put(index, indexVersionSet);
+ }
+ NodeList nList = methodNode.getChildNodes();
+ AtomicInteger fieldCntr = _versionToFieldCount.get(version);
+ if(fieldCntr == null)
+ {
+ fieldCntr = new AtomicInteger(0);
+ _versionToFieldCount.put(version, fieldCntr);
+ }
+ for (int i = 0; i < nList.getLength(); i++)
+ {
+ Node child = nList.item(i);
+ if (child.getNodeName().compareTo(Utils.ELEMENT_FIELD) == 0)
+ {
+ String fieldName = _generator.prepareDomainName(Utils.getNamedAttribute(child,
+ Utils.ATTRIBUTE_NAME));
+ AmqpField thisField = _fieldMap.get(fieldName);
+ AmqpFieldMap versionSpecificFieldMap = _versionToFieldsMap.get(version);
+ if (versionSpecificFieldMap == null)
+ {
+ versionSpecificFieldMap = new AmqpFieldMap();
+ _versionToFieldsMap.put(version, versionSpecificFieldMap);
+ }
+
+
+ if (thisField == null)
+ {
+ thisField = new AmqpField(fieldName, _generator);
+ _fieldMap.add(fieldName, thisField);
+ }
+
+ AmqpField versionSpecificField = new AmqpField(fieldName, _generator);
+ versionSpecificFieldMap.add(fieldName, versionSpecificField);
+
+ versionSpecificField.addFromNode(child, fieldCntr.intValue(), version);
+
+ if (!thisField.addFromNode(child, fieldCntr.getAndIncrement(), version))
+ {
+ String className = _generator.prepareClassName(Utils.getNamedAttribute(methodNode.getParentNode(),
+ Utils.ATTRIBUTE_NAME));
+ String methodName = _generator.prepareMethodName(Utils.getNamedAttribute(methodNode,
+ Utils.ATTRIBUTE_NAME));
+ System.out.println("INFO: Generation supression tag found for field " +
+ className + "." + methodName + "." + fieldName + " - removing.");
+ thisField.removeVersion(version);
+ _fieldMap.remove(fieldName);
+ }
+ }
+ else if (child.getNodeName().compareTo(Utils.ELEMENT_CHASSIS) == 0)
+ {
+ String chassisName = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_NAME);
+ if (chassisName.compareTo("server") == 0)
+ {
+ serverChassisFlag = true;
+ }
+ else if (chassisName.compareTo("client") == 0)
+ {
+ clientChassisFlag = true;
+ }
+ }
+ else if (child.getNodeName().compareTo(Utils.ELEMENT_CODEGEN) == 0)
+ {
+ String value = Utils.getNamedAttribute(child, Utils.ATTRIBUTE_VALUE);
+ if (value.compareTo("no-gen") == 0)
+ {
+ return false;
+ }
+ }
+ }
+ processChassisFlags(serverChassisFlag, clientChassisFlag, version);
+ return true;
+ }
+
+ public void removeVersion(AmqpVersion version)
+ {
+ _clientMethodFlagMap.removeVersion(version);
+ _serverMethodFlagMap.removeVersion(version);
+ _indexMap.removeVersion(version);
+ _fieldMap.removeVersion(version);
+ _versionSet.remove(version);
+ }
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ String margin = Utils.createSpaces(marginSize);
+ String tab = Utils.createSpaces(tabSize);
+ out.println(margin + "[M] " + _name + " {" + (_serverMethodFlagMap.isSet() ? "S " +
+ _serverMethodFlagMap + (
+ _clientMethodFlagMap.isSet() ? ", " : "") : "") +
+ (_clientMethodFlagMap.isSet()
+ ? "C " + _clientMethodFlagMap : "") + "}" + ": " +
+ _versionSet);
+
+ for (Integer thisIndex : _indexMap.keySet())
+ {
+ AmqpVersionSet indexVersionSet = _indexMap.get(thisIndex);
+ out.println(margin + tab + "[I] " + thisIndex + indexVersionSet);
+ }
+
+ for (String thisFieldName : _fieldMap.keySet())
+ {
+ AmqpField thisField = _fieldMap.get(thisFieldName);
+ thisField.print(out, marginSize + tabSize, tabSize);
+ }
+ }
+
+ protected void processChassisFlags(boolean serverFlag, boolean clientFlag, AmqpVersion version)
+ {
+ AmqpVersionSet versionSet = _serverMethodFlagMap.get(serverFlag);
+ if (versionSet != null)
+ {
+ versionSet.add(version);
+ }
+ else
+ {
+ versionSet = new AmqpVersionSet();
+ versionSet.add(version);
+ _serverMethodFlagMap.put(serverFlag, versionSet);
+ }
+
+ versionSet = _clientMethodFlagMap.get(clientFlag);
+ if (versionSet != null)
+ {
+ versionSet.add(version);
+ }
+ else
+ {
+ versionSet = new AmqpVersionSet();
+ versionSet.add(version);
+ _clientMethodFlagMap.put(clientFlag, versionSet);
+ }
+ }
+
+ public AmqpOverloadedParameterMap getOverloadedParameterLists(AmqpVersionSet globalVersionSet,
+ Generator generator)
+ throws AmqpTypeMappingException
+ {
+ AmqpOverloadedParameterMap parameterVersionMap = new AmqpOverloadedParameterMap();
+ for (AmqpVersion thisVersion : globalVersionSet)
+ {
+ AmqpOrdinalFieldMap ordinalFieldMap = _fieldMap.getMapForVersion(thisVersion, true, generator);
+ AmqpVersionSet methodVersionSet = parameterVersionMap.get(ordinalFieldMap);
+ if (methodVersionSet == null)
+ {
+ methodVersionSet = new AmqpVersionSet();
+ methodVersionSet.add(thisVersion);
+ parameterVersionMap.put(ordinalFieldMap, methodVersionSet);
+ }
+ else
+ {
+ methodVersionSet.add(thisVersion);
+ }
+ }
+ return parameterVersionMap;
+ }
+
+ public boolean isVersionInterfaceConsistent()
+ {
+ return isVersionInterfaceConsistent(_generator.getVersionSet());
+ }
+
+ public boolean isVersionInterfaceConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (!_versionSet.equals(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_clientMethodFlagMap.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_serverMethodFlagMap.isVersionConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ if (!_fieldMap.isVersionInterfaceConsistent(globalVersionSet))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isVersionConsistent()
+ {
+ return isVersionConsistent(_generator.getVersionSet());
+ }
+
+
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ return isVersionInterfaceConsistent(globalVersionSet)
+ && _indexMap.isVersionConsistent(globalVersionSet)
+ && _fieldMap.isVersionConsistent(globalVersionSet);
+ }
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ public AmqpFieldMap getFieldMap()
+ {
+ return _fieldMap;
+ }
+
+ public AmqpOrdinalVersionMap getIndexMap()
+ {
+ return _indexMap;
+ }
+
+ public AmqpFlagMap getClientMethodFlagMap()
+ {
+ return _clientMethodFlagMap;
+ }
+
+ public AmqpFlagMap getServerMethodFlagMap()
+ {
+ return _serverMethodFlagMap;
+ }
+
+ public Map<AmqpVersion, AmqpFieldMap> getVersionToFieldsMap()
+ {
+ return _versionToFieldsMap;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public LanguageConverter getGenerator()
+ {
+ return _generator;
+ }
+
+ public SingleVersionMethod asSingleVersionMethod(AmqpVersion version)
+ {
+ return new SingleVersionMethod(this, version, _generator);
+ }
+
+ public Collection<AmqpField> getFields()
+ {
+ return _fieldMap.values();
+ }
+
+ public boolean isCommon(AmqpField field)
+ {
+ return field.getVersionSet().equals(getVersionSet()) && field.isTypeAndNameConsistent(_generator);
+ }
+
+ public boolean isConsistentServerMethod()
+ {
+ AmqpVersionSet serverVersions = _serverMethodFlagMap.get(true);
+ return (serverVersions != null) && serverVersions.containsAll(_generator.getVersionSet());
+ }
+
+
+ public boolean isConsistentClientMethod()
+ {
+ AmqpVersionSet clientVersions = _clientMethodFlagMap.get(true);
+ return (clientVersions != null) && clientVersions.containsAll(_generator.getVersionSet());
+ }
+
+ public boolean isServerMethod(AmqpVersion version)
+ {
+ AmqpVersionSet serverVersions = _serverMethodFlagMap.get(true);
+ return (serverVersions != null) && serverVersions.contains(version);
+ }
+
+
+ public boolean isClientMethod(AmqpVersion version)
+ {
+ AmqpVersionSet clientVersions = _clientMethodFlagMap.get(true);
+ return (clientVersions != null) && clientVersions.contains(version);
+ }
+
+ public boolean inAllVersions()
+ {
+ return _versionSet.containsAll(_generator.getVersionSet());
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java
new file mode 100644
index 0000000000..d98dab4a39
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpMethodMap.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpMethodMap extends TreeMap<String, AmqpMethod>
+{
+ public void removeVersion(AmqpVersion version)
+ {
+ for (String methodName : keySet())
+ {
+ get(methodName).removeVersion(version);
+ }
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpModel.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpModel.java
new file mode 100644
index 0000000000..45f0adb18d
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpModel.java
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Collection;
+
+public class AmqpModel implements Printable, NodeAware
+{
+ private final Generator _generator;
+ private final AmqpClassMap classMap = new AmqpClassMap();
+ private final AmqpVersionSet _versionSet = new AmqpVersionSet();
+
+ private final Map<AmqpVersion, AmqpClassMap> _versionToClassMapMap = new HashMap<AmqpVersion, AmqpClassMap>();
+
+ public AmqpModel(Generator generator)
+ {
+ _generator = generator;
+ }
+
+ public AmqpClassMap getAmqpClassMap(AmqpVersion version)
+ {
+ return _versionToClassMapMap.get(version);
+ }
+
+
+ public AmqpVersionSet getVersionSet()
+ {
+ return _versionSet;
+ }
+
+ public boolean addFromNode(Node n, int o, AmqpVersion version)
+ throws AmqpParseException, AmqpTypeMappingException
+ {
+ _versionSet.add(version);
+ NodeList nList = n.getChildNodes();
+
+ AmqpClassMap versionSpecificClassMap = _versionToClassMapMap.get(version);
+
+ if (versionSpecificClassMap == null)
+ {
+ versionSpecificClassMap = new AmqpClassMap();
+ _versionToClassMapMap.put(version, versionSpecificClassMap);
+ }
+
+ int eCntr = 0;
+ for (int i = 0; i < nList.getLength(); i++)
+ {
+ Node c = nList.item(i);
+ if (c.getNodeName().compareTo(Utils.ELEMENT_CLASS) == 0)
+ {
+ String className = _generator.prepareClassName(Utils.getNamedAttribute(c, Utils.ATTRIBUTE_NAME));
+ AmqpClass thisClass = classMap.get(className);
+ if (thisClass == null)
+ {
+ thisClass = new AmqpClass(className, _generator);
+ classMap.put(className, thisClass);
+ }
+
+ AmqpClass versionSpecificClass = new AmqpClass(className, _generator);
+ versionSpecificClassMap.put(className, versionSpecificClass);
+
+ versionSpecificClass.addFromNode(c, eCntr, version);
+
+ if (!thisClass.addFromNode(c, eCntr++, version))
+ {
+ System.out.println("INFO: Generation supression tag found for class " + className + " - removing.");
+ thisClass.removeVersion(version);
+ classMap.remove(className);
+ }
+ }
+ }
+ return true;
+ }
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ out.println(Utils.createSpaces(marginSize) +
+ "[C]=class; [M]=method; [F]=field; [D]=domain; [I]=index; [O]=ordinal" + Utils.LINE_SEPARATOR);
+ out.println(Utils.createSpaces(marginSize) + "Model:");
+
+ for (String thisClassName : classMap.keySet())
+ {
+ AmqpClass thisClass = classMap.get(thisClassName);
+ thisClass.print(out, marginSize + tabSize, tabSize);
+ }
+ }
+
+ public LanguageConverter getGenerator()
+ {
+ return _generator;
+ }
+
+ public AmqpClassMap getClassMap()
+ {
+ return classMap;
+ }
+
+
+ public Collection<AmqpClass> getClasses()
+ {
+ return classMap.values();
+ }
+
+ public SingleVersionModel asSingleVersionModel()
+ {
+ return new SingleVersionModel(this, getVersionSet().first(), _generator);
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java
new file mode 100644
index 0000000000..0633eff1e1
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalFieldMap.java
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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.util.Iterator;
+import java.util.Set;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpOrdinalFieldMap extends TreeMap<Integer, String[]> implements Comparable
+{
+
+
+ public int compareTo(Object obj)
+ {
+ AmqpOrdinalFieldMap o = (AmqpOrdinalFieldMap) obj;
+ Set<Integer> thisKeySet = keySet();
+ Set<Integer> oKeySet = o.keySet();
+ if (!thisKeySet.equals(oKeySet)) // Not equal, but why?
+ {
+ // Size difference
+ int sizeDiff = thisKeySet.size() - oKeySet.size(); // -ve if this < other
+ if (sizeDiff != 0)
+ {
+ return sizeDiff;
+ }
+ // Conetent difference
+ Iterator<Integer> itr = thisKeySet.iterator();
+ Iterator<Integer> oItr = oKeySet.iterator();
+ while (itr.hasNext() && oItr.hasNext())
+ {
+ int diff = itr.next() - oItr.next(); // -ve if this < other
+ if (diff != 0)
+ {
+ return diff;
+ }
+ }
+ // We should never get here...
+ System.err.println("AmqpOrdinalFieldMap.compareTo(): " +
+ "WARNING - unable to find cause of keySet difference.");
+ }
+ // Keys are equal, now check the String[]s
+ Iterator<Integer> itr = thisKeySet.iterator();
+ Iterator<Integer> oItr = oKeySet.iterator();
+ while (itr.hasNext() && oItr.hasNext())
+ {
+ String[] thisPair = get(itr.next());
+ String[] oPair = o.get(oItr.next());
+ // Size difference
+ int sizeDiff = thisPair.length - oPair.length; // -ve if this < other
+ if (sizeDiff != 0)
+ {
+ return sizeDiff;
+ }
+ // Conetent difference
+ for (int i = 0; i < thisPair.length; i++)
+ {
+ int diff = thisPair[i].compareTo(oPair[i]);
+ if (diff != 0)
+ {
+ return diff;
+ }
+ }
+ }
+ return 0;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ for (Integer thisOrdinal : keySet())
+ {
+ String[] pair = get(thisOrdinal);
+ sb.append("[" + thisOrdinal + "] " + pair[0] + " : " + pair[1] + Utils.LINE_SEPARATOR);
+ }
+ return sb.toString();
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java
new file mode 100644
index 0000000000..fede88631a
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpOrdinalVersionMap.java
@@ -0,0 +1,76 @@
+/*
+ *
+ * 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.util.ArrayList;
+import java.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpOrdinalVersionMap extends TreeMap<Integer, AmqpVersionSet> implements VersionConsistencyCheck
+{
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet)
+ {
+ if (size() != 1)
+ {
+ return false;
+ }
+ return get(firstKey()).equals(globalVersionSet);
+ }
+
+ public int getOrdinal(AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ for (Integer thisOrdinal : keySet())
+ {
+ AmqpVersionSet versionSet = get(thisOrdinal);
+ if (versionSet.contains(version))
+ {
+ return thisOrdinal;
+ }
+ }
+ throw new AmqpTypeMappingException("Unable to locate version " + version + " in ordianl version map.");
+ }
+
+ public boolean removeVersion(AmqpVersion version)
+ {
+ Boolean res = false;
+ ArrayList<Integer> removeList = new ArrayList<Integer>();
+ for (Integer ordinal : keySet())
+ {
+ AmqpVersionSet versionSet = get(ordinal);
+ if (versionSet.contains(version))
+ {
+ versionSet.remove(version);
+ if (versionSet.isEmpty())
+ {
+ removeList.add(ordinal);
+ }
+ res = true;
+ }
+ }
+ // Get rid of ordinals no longer in use
+ for (Integer ordinal : removeList)
+ {
+ remove(ordinal);
+ }
+ return res;
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java
new file mode 100644
index 0000000000..10978d0e4a
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpOverloadedParameterMap.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.util.TreeMap;
+
+@SuppressWarnings("serial")
+public class AmqpOverloadedParameterMap extends TreeMap<AmqpOrdinalFieldMap, AmqpVersionSet>
+{
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpParseException.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpParseException.java
new file mode 100644
index 0000000000..3f3d4611fc
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpParseException.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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;
+
+@SuppressWarnings("serial")
+public class AmqpParseException extends RuntimeException
+{
+ public AmqpParseException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java
new file mode 100644
index 0000000000..1ac09ea453
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpTemplateException.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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;
+
+@SuppressWarnings("serial")
+public class AmqpTemplateException extends RuntimeException
+{
+ public AmqpTemplateException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java
new file mode 100644
index 0000000000..127a8835b0
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpTypeMappingException.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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;
+
+@SuppressWarnings("serial")
+public class AmqpTypeMappingException extends RuntimeException
+{
+ public AmqpTypeMappingException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpVersion.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpVersion.java
new file mode 100644
index 0000000000..dbeef1b895
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpVersion.java
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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;
+
+public class AmqpVersion implements Comparable<AmqpVersion>
+{
+ private final int _major;
+ private final int _minor;
+
+ public AmqpVersion(int major, int minor)
+ {
+ _major = major;
+ _minor = minor;
+ }
+
+ public AmqpVersion(AmqpVersion version)
+ {
+ _major = version.getMajor();
+ _minor = version.getMinor();
+ }
+
+ public int getMajor()
+ {
+ return _major;
+ }
+
+ public int getMinor()
+ {
+ return _minor;
+ }
+
+ public int compareTo(AmqpVersion v)
+ {
+ if (_major != v.getMajor())
+ {
+ return _major - v.getMajor();
+ }
+ if (_minor != v.getMinor())
+ {
+ return _minor - v.getMinor();
+ }
+ return 0;
+ }
+
+ public String namespace()
+ {
+ return "ver_" + _major + "_" + _minor;
+ }
+
+ public String toString()
+ {
+ return _major + "-" + _minor;
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java b/java/common/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java
new file mode 100644
index 0000000000..6419e23a1e
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/AmqpVersionSet.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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.PrintStream;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+@SuppressWarnings("serial")
+public class AmqpVersionSet extends TreeSet<AmqpVersion> implements Printable, Comparable<AmqpVersionSet>
+{
+ public AmqpVersionSet()
+ {
+ super();
+ }
+
+ public AmqpVersionSet(AmqpVersion version)
+ {
+ super();
+ add(version);
+ }
+
+ public AmqpVersion find(AmqpVersion version)
+ {
+ for (AmqpVersion v : this)
+ {
+ if (v.compareTo(version) == 0)
+ {
+ return v;
+ }
+ }
+ return null;
+ }
+
+ public void print(PrintStream out, int marginSize, int tabSize)
+ {
+ out.print(Utils.createSpaces(marginSize) + "Version Set: " + toString() + Utils.LINE_SEPARATOR);
+ }
+
+ public int compareTo(AmqpVersionSet other)
+ {
+ int res = size() - other.size();
+ if (res != 0)
+ {
+ return res;
+ }
+ Iterator<AmqpVersion> vItr = iterator();
+ Iterator<AmqpVersion> oItr = other.iterator();
+ while (vItr.hasNext() && oItr.hasNext())
+ {
+ AmqpVersion version = vItr.next();
+ AmqpVersion oVersion = oItr.next();
+ res = version.compareTo(oVersion);
+ if (res != 0)
+ {
+ return res;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/BitFieldGenerateMethod.java b/java/common/gentools/src/org/apache/qpid/gentools/BitFieldGenerateMethod.java
new file mode 100644
index 0000000000..d85510ee98
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/BitFieldGenerateMethod.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.util.List;
+
+public interface BitFieldGenerateMethod
+{
+ String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize);
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/CommandGenerateMethod.java b/java/common/gentools/src/org/apache/qpid/gentools/CommandGenerateMethod.java
new file mode 100644
index 0000000000..641f50c3f8
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/CommandGenerateMethod.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * 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;
+
+public interface CommandGenerateMethod
+{
+ String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast);
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java b/java/common/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java
new file mode 100644
index 0000000000..9ab7eb178b
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/ConsolidatedField.java
@@ -0,0 +1,120 @@
+/*
+ *
+ * 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.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: U146758
+ * Date: 06-Mar-2007
+ * Time: 09:22:21
+ * To change this template use File | Settings | File Templates.
+ */
+public class ConsolidatedField
+{
+ private final String _name;
+ private final String _type;
+ private final List<String> _underlyingFields = new ArrayList<String>();
+ private final Generator _generator;
+ private boolean _isConsolidated;
+
+ public ConsolidatedField(Generator generator, String name, String type)
+ {
+ this(generator,name,type,name,false);
+ }
+
+ public ConsolidatedField(Generator generator, String name, String type, String firstField)
+ {
+ this(generator,name,type,firstField,true);
+ }
+
+ public ConsolidatedField(Generator generator, String name, String type, String firstField, boolean consolidated)
+ {
+
+ _generator = generator;
+ _name = name;
+ _type = type;
+ _isConsolidated = consolidated;
+ _underlyingFields.add(firstField);
+
+ }
+
+
+ public void setConsolidated(boolean consolidated)
+ {
+ _isConsolidated = consolidated;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String getType()
+ {
+ return _type;
+ }
+
+ public String getNativeType()
+ {
+ return _generator.getNativeType(_type);
+ }
+
+ public String getEncodingType()
+ {
+ return _generator.getEncodingType(_type);
+ }
+
+ public void add(String name)
+ {
+ _underlyingFields.add(name);
+ }
+
+ public Collection<String> getUnderlyingFields()
+ {
+ return Collections.unmodifiableCollection(_underlyingFields);
+ }
+
+ public int getPosition(String fieldName)
+ {
+ return _underlyingFields.indexOf(fieldName);
+ }
+
+ public boolean isConsolidated()
+ {
+ return _isConsolidated;
+ }
+
+ public boolean isFixedSize()
+ {
+ return _generator.isFixedSizeType( getType() );
+ }
+
+ public int getSize()
+ {
+ return _generator.getTypeSize( getType() );
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/CppGenerator.java b/java/common/gentools/src/org/apache/qpid/gentools/CppGenerator.java
new file mode 100644
index 0000000000..4f58cba34e
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/CppGenerator.java
@@ -0,0 +1,1716 @@
+/*
+ *
+ * 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.util.ArrayList;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+public class CppGenerator extends Generator
+{
+ protected static final String versionNamespaceStartToken = "${version_namespace_start}";
+ protected static final String versionNamespaceEndToken = "${version_namespace_end}";
+
+ // TODO: Move this to parent class
+ protected static final int FIELD_NAME = 0;
+ protected static final int FIELD_CODE_TYPE = 1;
+
+ /**
+ * A complete list of C++ reserved words. The names of varous XML elements within the AMQP
+ * specification file are used for C++ identifier names in the generated code. Each proposed
+ * name is checked against this list and is modified (by adding an '_' to the end of the
+ * name - see function parseForReservedWords()) if found to be present.
+ */
+ protected static final String[] cppReservedWords = {"and", "and_eq", "asm", "auto", "bitand",
+ "bitor", "bool", "break", "case", "catch", "char", "class", "compl", "const", "const_cast",
+ "continue", "default", "delete", "do", "DomainInfo", "double", "dynamic_cast", "else",
+ "enum", "explicit", "extern", "false", "float", "for", "friend", "goto", "if", "inline",
+ "int", "long", "mutable", "namespace", "new", "not", "not_eq", "operator", "or", "or_eq",
+ "private", "protected", "public", "register", "reinterpret_cast", "return", "short",
+ "signed", "sizeof", "static", "static_cast", "struct", "switch", "template", "this",
+ "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using",
+ "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"};
+
+ /**
+ * Although not reserved words, the following list of variable names that may cause compile
+ * problems within a C++ environment because they clash with common #includes. The names of
+ * varous XML elements within the AMQP specification file are used for C++ identifier names
+ * in the generated code. Each proposed name is checked against this list and is modified
+ * (by adding an '_' to the end of the name - see function parseForReservedWords()) if found
+ * to be present. This list is best added to on an as-needed basis.
+ */
+ protected static final String[] cppCommonDefines = {"string"};
+
+ // TODO: Move this to the Generator superclass?
+ protected boolean quietFlag; // Supress warning messages to the console
+
+ private class DomainInfo
+ {
+ public String type;
+ public String size;
+ public String encodeExpression;
+ public String decodeExpression;
+
+ public DomainInfo(String domain, String size, String encodeExpression,
+ String decodeExpression)
+ {
+ this.type = domain;
+ this.size = size;
+ this.encodeExpression = encodeExpression;
+ this.decodeExpression = decodeExpression;
+ }
+ }
+
+ private static TreeMap<String, DomainInfo> typeMap = new TreeMap<String, DomainInfo>();
+
+ public CppGenerator()
+ {
+ super();
+ quietFlag = true;
+ // Load C++ type and size maps.
+ // Adjust or add to these lists as new types are added/defined.
+ // The char '#' will be replaced by the field variable name (any type).
+ // The char '~' will be replaced by the compacted bit array size (type bit only).
+ typeMap.put("bit", new DomainInfo(
+ "bool", // type
+ "~", // size
+ "", // encodeExpression
+ "")); // decodeExpression
+ typeMap.put("content", new DomainInfo(
+ "Content", // type
+ "#.size()", // size
+ "buffer.putContent(#)", // encodeExpression
+ "buffer.getContent(#)")); // decodeExpression
+ typeMap.put("long", new DomainInfo(
+ "u_int32_t", // type
+ "4", // size
+ "buffer.putLong(#)", // encodeExpression
+ "# = buffer.getLong()")); // decodeExpression
+ typeMap.put("longlong", new DomainInfo(
+ "u_int64_t", // type
+ "8", // size
+ "buffer.putLongLong(#)", // encodeExpression
+ "# = buffer.getLongLong()")); // decodeExpression
+ typeMap.put("longstr", new DomainInfo(
+ "string", // type
+ "4 + #.length()", // size
+ "buffer.putLongString(#)", // encodeExpression
+ "buffer.getLongString(#)")); // decodeExpression
+ typeMap.put("octet", new DomainInfo(
+ "u_int8_t", // type
+ "1", // size
+ "buffer.putOctet(#)", // encodeExpression
+ "# = buffer.getOctet()")); // decodeExpression
+ typeMap.put("short", new DomainInfo(
+ "u_int16_t", // type
+ "2", // size
+ "buffer.putShort(#)", // encodeExpression
+ "# = buffer.getShort()")); // decodeExpression
+ typeMap.put("shortstr", new DomainInfo(
+ "string", // type
+ "1 + #.length()", // size
+ "buffer.putShortString(#)", // encodeExpression
+ "buffer.getShortString(#)")); // decodeExpression
+ typeMap.put("table", new DomainInfo(
+ "FieldTable", // type
+ "#.size()", // size
+ "buffer.putFieldTable(#)", // encodeExpression
+ "buffer.getFieldTable(#)")); // decodeExpression
+ typeMap.put("timestamp", new DomainInfo(
+ "u_int64_t", // type
+ "8", // size
+ "buffer.putLongLong(#)", // encodeExpression
+ "buffer.getLongLong(#)")); // decodeExpression
+ }
+
+
+ public boolean isQuietFlag()
+ {
+ return quietFlag;
+ }
+
+ public void setQuietFlag(boolean quietFlag)
+ {
+ this.quietFlag = quietFlag;
+ }
+
+ // === Start of methods for Interface LanguageConverter ===
+
+ public String prepareClassName(String className)
+ {
+ return camelCaseName(className, true);
+ }
+
+ public String prepareMethodName(String methodName)
+ {
+ return camelCaseName(methodName, false);
+ }
+
+ public String prepareDomainName(String domainName)
+ {
+ return camelCaseName(domainName, false);
+ }
+
+
+ public String getGeneratedType(String domainName, AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ String domainType = getDomainType(domainName, version);
+ if (domainType == null)
+ {
+ throw new AmqpTypeMappingException("Domain type \"" + domainName +
+ "\" not found in C++ typemap.");
+ }
+ DomainInfo info = typeMap.get(domainType);
+ if (info == null)
+ {
+ throw new AmqpTypeMappingException("Unknown domain: \"" + domainType + "\"");
+ }
+ return info.type;
+ }
+
+ // === Abstract methods from class Generator - C++-specific implementation ===
+
+ @Override
+ protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, AmqpVersion version)
+ {
+ StringBuffer sb = new StringBuffer(filenameTemplate);
+ if (thisClass != null)
+ {
+ replaceToken(sb, "${CLASS}", thisClass.getName());
+ }
+ if (method != null)
+ {
+ replaceToken(sb, "${METHOD}", method.getName());
+ }
+ if (field != null)
+ {
+ replaceToken(sb, "${FIELD}", field.getName());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ protected void processModelTemplate(NamedTemplate template)
+ {
+ processTemplate(template, null, null, null, null);
+ }
+
+ @Override
+ protected void processClassTemplate(NamedTemplate template, AmqpClass thisClass)
+ {
+ processTemplate(template, thisClass, null, null, null);
+ }
+
+ @Override
+ protected void processMethodTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method)
+ {
+ StringBuffer sb = new StringBuffer(template.getTemplate());
+ String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, null, null);
+ boolean templateProcessedFlag = false;
+
+ // If method is not version consistent, create a namespace for each version
+ // i.e. copy the bit between the versionNamespaceStartToken and versionNamespaceEndToken
+ // once for each namespace.
+ if (method != null)
+ {
+ if (!method.isVersionConsistent(getVersionSet()))
+ {
+ int namespaceStartIndex = sb.indexOf(versionNamespaceStartToken);
+ int namespaceEndIndex = sb.indexOf(versionNamespaceEndToken) +
+ versionNamespaceEndToken.length();
+ if (namespaceStartIndex >= 0 && namespaceEndIndex >= 0 &&
+ namespaceStartIndex <= namespaceEndIndex)
+ {
+ String namespaceSpan = sb.substring(namespaceStartIndex, namespaceEndIndex) + CR;
+ sb.delete(namespaceStartIndex, namespaceEndIndex);
+ for (AmqpVersion v : method.getVersionSet())
+ {
+ StringBuffer nssb = new StringBuffer(namespaceSpan);
+ processTemplate(nssb, thisClass, method, null, template.getName(), v);
+ sb.insert(namespaceStartIndex, nssb);
+ }
+ // Process all tokens *not* within the namespace span prior to inserting namespaces
+ processTemplate(sb, thisClass, method, null, template.getName(), null);
+ }
+ templateProcessedFlag = true;
+ }
+ }
+ // Remove any remaining namespace tags
+ int nsTokenIndex = sb.indexOf(versionNamespaceStartToken);
+ while (nsTokenIndex > 0)
+ {
+ sb.delete(nsTokenIndex, nsTokenIndex + versionNamespaceStartToken.length());
+ nsTokenIndex = sb.indexOf(versionNamespaceStartToken);
+ }
+ nsTokenIndex = sb.indexOf(versionNamespaceEndToken);
+ while (nsTokenIndex > 0)
+ {
+ sb.delete(nsTokenIndex, nsTokenIndex + versionNamespaceEndToken.length());
+ nsTokenIndex = sb.indexOf(versionNamespaceEndToken);
+ }
+
+ if (!templateProcessedFlag)
+ {
+ processTemplate(sb, thisClass, method, null, template.getName(), null);
+ }
+ writeTargetFile(sb, new File(getOutputDirectory() + Utils.FILE_SEPARATOR + filename));
+ generatedFileCounter++;
+ }
+
+ @Override
+ protected void processTemplate(NamedTemplate template, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, AmqpVersion version)
+ {
+ StringBuffer sb = new StringBuffer(template.getTemplate());
+ String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, field, version);
+ processTemplate(sb, thisClass, method, field, template.getName(), null);
+ writeTargetFile(sb, new File(getOutputDirectory() + Utils.FILE_SEPARATOR + filename));
+ generatedFileCounter++;
+ }
+
+ protected void processTemplate(StringBuffer sb, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, String templateFileName, AmqpVersion version)
+ {
+ try
+ {
+ processAllLists(sb, thisClass, method, version);
+ }
+ catch (AmqpTemplateException e)
+ {
+ System.out.println("ERROR: " + templateFileName + ": " + e.getMessage());
+ }
+ try
+ {
+ processAllTokens(sb, thisClass, method, field, version);
+ }
+ catch (AmqpTemplateException e)
+ {
+ System.out.println("ERROR: " + templateFileName + ": " + e.getMessage());
+ }
+ }
+
+ @Override
+ protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, AmqpField field,
+ AmqpVersion version)
+ {
+ if (token.compareTo("${GENERATOR}") == 0)
+ {
+ return GENERATOR_INFO;
+ }
+ if (token.compareTo("${CLASS}") == 0 && thisClass != null)
+ {
+ return thisClass.getName();
+ }
+ if (token.compareTo("${CLASS_ID_INIT}") == 0 && thisClass != null)
+ {
+ if (version == null)
+ {
+ return String.valueOf(thisClass.getIndexMap().firstKey());
+ }
+ return getIndex(thisClass.getIndexMap(), version);
+ }
+ if (token.compareTo("${METHOD}") == 0 && method != null)
+ {
+ return method.getName();
+ }
+ if (token.compareTo("${METHOD_ID_INIT}") == 0 && method != null)
+ {
+ if (version == null)
+ {
+ return String.valueOf(method.getIndexMap().firstKey());
+ }
+ return getIndex(method.getIndexMap(), version);
+ }
+ if (token.compareTo("${FIELD}") == 0 && field != null)
+ {
+ return field.getName();
+ }
+ if (token.compareTo(versionNamespaceStartToken) == 0 && version != null)
+ {
+ return "namespace " + version.namespace() + CR + "{";
+ }
+ if (token.compareTo(versionNamespaceEndToken) == 0 && version != null)
+ {
+ return "} // namespace " + version.namespace();
+ }
+ if (token.compareTo("${mb_constructor_with_initializers}") == 0)
+ {
+ return generateConstructor(thisClass, method, version, 4, 4);
+ }
+ if (token.compareTo("${mb_server_operation_invoke}") == 0)
+ {
+ return generateServerOperationsInvoke(thisClass, method, version, 4, 4);
+ }
+ if (token.compareTo("${mb_buffer_param}") == 0)
+ {
+ return method.getFieldMap().size() > 0 ? " buffer" : "";
+ }
+ if (token.compareTo("${hv_latest_major}") == 0)
+ {
+ return String.valueOf(getVersionSet().last().getMajor());
+ }
+ if (token.compareTo("${hv_latest_minor}") == 0)
+ {
+ return String.valueOf(getVersionSet().last().getMinor());
+ }
+
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+
+ @Override
+ protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpModel model, AmqpVersion version)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokxStart = tline.indexOf('$');
+ String token = tline.substring(tokxStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ // ClientOperations.h
+ if (token.compareTo("${coh_method_handler_get_method}") == 0)
+ {
+ codeSnippet = generateOpsMethodHandlerGetMethods(model, false, 4);
+ }
+ else if (token.compareTo("${coh_inner_class}") == 0)
+ {
+ codeSnippet = generateOpsInnerClasses(model, false, 4, 4);
+ }
+
+ // ServerOperations.h
+ else if (token.compareTo("${soh_method_handler_get_method}") == 0)
+ {
+ codeSnippet = generateOpsMethodHandlerGetMethods(model, true, 4);
+ }
+ else if (token.compareTo("${soh_inner_class}") == 0)
+ {
+ codeSnippet = generateOpsInnerClasses(model, true, 4, 4);
+ }
+
+ // ClientProxy.h/cpp
+ else if (token.compareTo("${cph_inner_class_instance}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassInstances(model, false, 4);
+ }
+ else if (token.compareTo("${cph_inner_class_get_method}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassGetMethodDecls(model, false, 4);
+ }
+ else if (token.compareTo("${cph_inner_class_defn}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassDefinitions(model, false, 4, 4);
+ }
+ else if (token.compareTo("${cpc_constructor_initializer}") == 0)
+ {
+ codeSnippet = generateProxyConstructorInitializers(model, false, 4);
+ }
+ else if (token.compareTo("${cpc_inner_class_get_method}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassGetMethodImpls(model, false, 0, 4);
+ }
+ else if (token.compareTo("${cpc_inner_class_impl}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassImpl(model, false, 0, 4);
+ }
+ else if (token.compareTo("${cph_handler_pointer_defn}") == 0)
+ {
+ codeSnippet = generateHandlerPointerDefinitions(model, false, 4);
+ }
+ else if (token.compareTo("${cph_handler_pointer_get_method}") == 0)
+ {
+ codeSnippet = generateHandlerPointerGetMethods(model, false, 4);
+ }
+
+ // SerrverProxy.h/cpp
+ else if (token.compareTo("${sph_inner_class_instance}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassInstances(model, true, 4);
+ }
+ else if (token.compareTo("${sph_inner_class_get_method}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassGetMethodDecls(model, true, 4);
+ }
+ else if (token.compareTo("${sph_inner_class_defn}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassDefinitions(model, true, 4, 4);
+ }
+ else if (token.compareTo("${spc_constructor_initializer}") == 0)
+ {
+ codeSnippet = generateProxyConstructorInitializers(model, true, 4);
+ }
+ else if (token.compareTo("${spc_inner_class_get_method}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassGetMethodImpls(model, true, 0, 4);
+ }
+ else if (token.compareTo("${spc_inner_class_impl}") == 0)
+ {
+ codeSnippet = generateProxyInnerClassImpl(model, true, 0, 4);
+ }
+ else if (token.compareTo("${sph_handler_pointer_defn}") == 0)
+ {
+ codeSnippet = generateHandlerPointerDefinitions(model, true, 4);
+ }
+ else if (token.compareTo("${sph_handler_pointer_get_method}") == 0)
+ {
+ codeSnippet = generateHandlerPointerGetMethods(model, true, 4);
+ }
+
+ // amqp_methods.h/cpp
+ else if (token.compareTo("${mh_method_body_class_indlude}") == 0)
+ {
+ codeSnippet = generateMethodBodyIncludeList(model, 0);
+ }
+ else if (token.compareTo("${mh_method_body_class_instance}") == 0)
+ {
+ codeSnippet = generateMethodBodyInstances(model, 0);
+ }
+ else if (token.compareTo("${mc_create_method_body_map_entry}") == 0)
+ {
+ codeSnippet = generateMethodBodyMapEntry(model, 4);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token \"" + token + "\" unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpClass thisClass)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokxStart = tline.indexOf('$');
+ String token = tline.substring(tokxStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ if (token.compareTo("${cpc_method_body_include}") == 0)
+ {
+ codeSnippet = generateMethodBodyIncludes(thisClass, 0);
+ }
+ else if (token.compareTo("${spc_method_body_include}") == 0)
+ {
+ codeSnippet = generateMethodBodyIncludes(thisClass, 0);
+ }
+ else if (token.compareTo("${mc_method_body_include}") == 0)
+ {
+ codeSnippet = generateMethodBodyIncludes(thisClass, 0);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpFieldMap fieldMap, AmqpVersion version)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokxStart = tline.indexOf('$');
+ String token = tline.substring(tokxStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ if (token.compareTo("${mb_field_declaration}") == 0)
+ {
+ codeSnippet = generateFieldDeclarations(fieldMap, version, 4);
+ }
+ else if (token.compareTo("${mb_field_get_method}") == 0)
+ {
+ codeSnippet = generateFieldGetMethods(fieldMap, version, 4);
+ }
+ else if (token.compareTo("${mb_field_print}") == 0)
+ {
+ codeSnippet = generatePrintMethodContents(fieldMap, version, 8);
+ }
+ else if (token.compareTo("${mb_body_size}") == 0)
+ {
+ codeSnippet = generateBodySizeMethodContents(fieldMap, version, 8);
+ }
+ else if (token.compareTo("${mb_encode}") == 0)
+ {
+ codeSnippet = generateEncodeMethodContents(fieldMap, version, 8);
+ }
+ else if (token.compareTo("${mb_decode}") == 0)
+ {
+ codeSnippet = generateDecodeMethodContents(fieldMap, version, 8);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpConstantSet constantSet)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokxStart = tline.indexOf('$');
+ String token = tline.substring(tokxStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ if (token.compareTo("${ch_get_value_method}") == 0)
+ {
+ codeSnippet = generateConstantGetMethods(constantSet, 4, 4);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ // === Protected and private helper functions unique to C++ implementation ===
+
+ // Methods for generation of code snippets for AMQP_Constants.h file
+
+ protected String generateConstantGetMethods(AmqpConstantSet constantSet,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ for (AmqpConstant thisConstant : constantSet.getContstants())
+ {
+ if (thisConstant.isVersionConsistent(getVersionSet()))
+ {
+ // return a constant
+ String value = thisConstant.firstKey();
+ sb.append(indent + "static const char* " + thisConstant.getName() + "() { return \"" +
+ thisConstant.firstKey() + "\"; }" + CR);
+ if (Utils.containsOnlyDigits(value))
+ {
+ sb.append(indent + "static int " + thisConstant.getName() + "AsInt() { return " +
+ thisConstant.firstKey() + "; }" + CR);
+ }
+ if (Utils.containsOnlyDigitsAndDecimal(value))
+ {
+ sb.append(indent + "static double " + thisConstant.getName() + "AsDouble() { return (double)" +
+ thisConstant.firstKey() + "; }" + CR);
+ }
+ sb.append(CR);
+ }
+ else
+ {
+ // Return version-specific constant
+ sb.append(generateVersionDependentGet(thisConstant, "const char*", "", "\"", "\"", indentSize, tabSize));
+ sb.append(generateVersionDependentGet(thisConstant, "int", "AsInt", "", "", indentSize, tabSize));
+ sb.append(generateVersionDependentGet(thisConstant, "double", "AsDouble", "(double)", "", indentSize, tabSize));
+ sb.append(CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateVersionDependentGet(AmqpConstant constant, String methodReturnType,
+ String methodNameSuffix, String returnPrefix, String returnPostfix, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + methodReturnType + " " + constant.getName() + methodNameSuffix +
+ "() const" + CR);
+ sb.append(indent + "{" + CR);
+ boolean first = true;
+ for (String thisValue : constant.keySet())
+ {
+ AmqpVersionSet versionSet = constant.get(thisValue);
+ sb.append(indent + tab + (first ? "" : "else ") + "if (" + generateVersionCheck(versionSet) +
+ ")" + CR);
+ sb.append(indent + tab + "{" + CR);
+ if (methodReturnType.compareTo("int") == 0 && !Utils.containsOnlyDigits(thisValue))
+ {
+ sb.append(generateConstantDeclarationException(constant.getName(), methodReturnType,
+ indentSize + (2 * tabSize), tabSize));
+ }
+ else if (methodReturnType.compareTo("double") == 0 && !Utils.containsOnlyDigitsAndDecimal(thisValue))
+ {
+ sb.append(generateConstantDeclarationException(constant.getName(), methodReturnType,
+ indentSize + (2 * tabSize), tabSize));
+ }
+ else
+ {
+ sb.append(indent + tab + tab + "return " + returnPrefix + thisValue + returnPostfix + ";" + CR);
+ }
+ sb.append(indent + tab + "}" + CR);
+ first = false;
+ }
+ sb.append(indent + tab + "else" + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "std::stringstream ss;" + CR);
+ sb.append(indent + tab + tab + "ss << \"Constant \\\"" + constant.getName() +
+ "\\\" is undefined for AMQP version \" <<" + CR);
+ sb.append(indent + tab + tab + tab + "version.toString() << \".\";" + CR);
+ sb.append(indent + tab + tab + "throw ProtocolVersionException(ss.str());" + CR);
+ sb.append(indent + tab + "}" + CR);
+ sb.append(indent + "}" + CR);
+ return sb.toString();
+ }
+
+ protected String generateConstantDeclarationException(String name, String methodReturnType,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "std::stringstream ss;" + CR);
+ sb.append(indent + "ss << \"Constant \\\"" + name + "\\\" cannot be converted to type " +
+ methodReturnType + " for AMQP version \" <<" + CR);
+ sb.append(indent + tab + "version.toString() << \".\";" + CR);
+ sb.append(indent + "throw ProtocolVersionException(ss.str());" + CR);
+ return sb.toString();
+ }
+
+ // Methods used for generation of code snippets for Server/ClientOperations class generation
+
+ protected String generateOpsMethodHandlerGetMethods(AmqpModel model, boolean serverFlag, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ // Only generate for this class if there is at least one method of the
+ // required chassis (server/client flag).
+ boolean chassisFoundFlag = false;
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ boolean clientChassisFlag = method.getClientMethodFlagMap().isSet();
+ boolean serverChassisFlag = method.getServerMethodFlagMap().isSet();
+ if ((serverFlag && serverChassisFlag) || (!serverFlag && clientChassisFlag))
+ {
+ chassisFoundFlag = true;
+ }
+ }
+ if (chassisFoundFlag)
+ {
+ sb.append(indent + "virtual AMQP_" + (serverFlag ? "Server" : "Client") + "Operations::" +
+ thisClass.getName() + "Handler* get" + thisClass.getName() + "Handler() = 0;" + CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateOpsInnerClasses(AmqpModel model, boolean serverFlag, int indentSize, int tabSize)
+ {
+
+ String proxyClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ boolean first = true;
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ String handlerClassName = thisClass.getName() + "Handler";
+ if (!first)
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "// ==================== class " + handlerClassName +
+ " ====================" + CR);
+ sb.append(indent + "class " + handlerClassName);
+ if (thisClass.getVersionSet().size() != getVersionSet().size())
+ {
+ sb.append(" // AMQP Version(s) " + thisClass.getVersionSet() + CR);
+ }
+ else
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "{" + CR);
+ sb.append(indent + "private:" + CR);
+ sb.append(indent + tab + proxyClassName + "* parent;" + CR);
+ sb.append(CR);
+ sb.append(indent + tab + "// Constructors and destructors" + CR);
+ sb.append(CR);
+ sb.append(indent + "protected:" + CR);
+ sb.append(indent + tab + handlerClassName + "() {}" + CR);
+ sb.append(indent + "public:" + CR);
+ sb.append(indent + tab + handlerClassName +
+ "(" + proxyClassName + "* _parent) {parent = _parent;}" + CR);
+ sb.append(indent + tab + "virtual ~" + handlerClassName + "() {}" + CR);
+ sb.append(CR);
+ sb.append(indent + tab + "// Protocol methods" + CR);
+ sb.append(CR);
+ sb.append(generateInnerClassMethods(thisClass, serverFlag, true, indentSize + tabSize, tabSize));
+ sb.append(indent + "}; // class " + handlerClassName + CR);
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ protected String generateInnerClassMethods(AmqpClass thisClass, boolean serverFlag,
+ boolean abstractMethodFlag, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + (abstractMethodFlag ? "Operations"
+ : "Proxy");
+ boolean first = true;
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ boolean clientChassisFlag = method.getClientMethodFlagMap().isSet();
+ boolean serverChassisFlag = method.getServerMethodFlagMap().isSet();
+ if ((serverFlag && serverChassisFlag) || (!serverFlag && clientChassisFlag))
+ {
+ String methodName = parseForReservedWords(method.getName(), outerClassName + "." + thisClass.getName());
+ AmqpOverloadedParameterMap overloadededParameterMap =
+ method.getOverloadedParameterLists(thisClass.getVersionSet(), this);
+ for (AmqpOrdinalFieldMap thisFieldMap : overloadededParameterMap.keySet())
+ {
+ AmqpVersionSet versionSet = overloadededParameterMap.get(thisFieldMap);
+ if (!first)
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "virtual void " + methodName + "( u_int16_t channel");
+ sb.append(generateMethodParameterList(thisFieldMap, indentSize + (5 * tabSize), true, true, true));
+ sb.append(" )");
+ if (abstractMethodFlag)
+ {
+ sb.append(" = 0");
+ }
+ sb.append(";");
+ if (versionSet.size() != getVersionSet().size())
+ {
+ sb.append(" // AMQP Version(s) " + versionSet);
+ }
+ sb.append(CR);
+ first = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ // Methods used for generation of code snippets for Server/ClientProxy class generation
+
+ protected String generateHandlerPointerDefinitions(AmqpModel model, boolean serverFlag,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Operations";
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ sb.append(indent + outerClassName + "::" + thisClass.getName() + "Handler* " +
+ thisClass.getName() + "HandlerPtr;" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateHandlerPointerGetMethods(AmqpModel model, boolean serverFlag,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Operations";
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ sb.append(indent + "virtual inline " + outerClassName + "::" + thisClass.getName() + "Handler* get" +
+ thisClass.getName() + "Handler() { return &" + Utils.firstLower(thisClass.getName()) + ";}" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateProxyInnerClassInstances(AmqpModel model, boolean serverFlag,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ String instanceName = parseForReservedWords(Utils.firstLower(thisClass.getName()), outerClassName);
+ String className = parseForReservedWords(thisClass.getName(), null);
+ sb.append(indent + className + " " + instanceName + ";");
+ if (thisClass.getVersionSet().size() != getVersionSet().size())
+ {
+ sb.append(" // AMQP Version(s) " + thisClass.getVersionSet() + CR);
+ }
+ else
+ {
+ sb.append(CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateProxyInnerClassGetMethodDecls(AmqpModel model, boolean serverFlag,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ String className = parseForReservedWords(thisClass.getName(), outerClassName);
+ sb.append(indent + className + "& get" + className + "();");
+ if (thisClass.getVersionSet().size() != getVersionSet().size())
+ {
+ sb.append(" // AMQP Version(s) " + thisClass.getVersionSet() + CR);
+ }
+ else
+ {
+ sb.append(CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateProxyInnerClassDefinitions(AmqpModel model, boolean serverFlag,
+ int indentSize, int tabSize)
+ {
+ String proxyClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ boolean first = true;
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ String className = thisClass.getName();
+ String superclassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Operations::" +
+ thisClass.getName() + "Handler";
+ if (!first)
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "// ==================== class " + className +
+ " ====================" + CR);
+ sb.append(indent + "class " + className + " : virtual public " + superclassName);
+ if (thisClass.getVersionSet().size() != getVersionSet().size())
+ {
+ sb.append(" // AMQP Version(s) " + thisClass.getVersionSet() + CR);
+ }
+ else
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "{" + CR);
+ sb.append(indent + "private:" + CR);
+ sb.append(indent + tab + "OutputHandler* out;" + CR);
+ sb.append(indent + tab + proxyClassName + "* parent;" + CR);
+ sb.append(CR);
+ sb.append(indent + "public:" + CR);
+ sb.append(indent + tab + "// Constructors and destructors" + CR);
+ sb.append(CR);
+ sb.append(indent + tab + className + "(OutputHandler* out, " + proxyClassName + "* _parent) : " + CR);
+ sb.append(indent + tab + tab + "out(out) {parent = _parent;}" + CR);
+ sb.append(indent + tab + "virtual ~" + className + "() {}" + CR);
+ sb.append(CR);
+ sb.append(indent + tab + "// Protocol methods" + CR);
+ sb.append(CR);
+ sb.append(generateInnerClassMethods(thisClass, serverFlag, false, indentSize + tabSize, tabSize));
+ sb.append(indent + "}; // class " + className + CR);
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ protected String generateProxyConstructorInitializers(AmqpModel model, boolean serverFlag,
+ int indentSize)
+ {
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ String superclassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Operations";
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer(indent + superclassName + "(major, minor)," + CR);
+ sb.append(indent + "version(major, minor)," + CR);
+ sb.append(indent + "out(out)");
+ Iterator<String> cItr = model.getClassMap().keySet().iterator();
+ while (cItr.hasNext())
+ {
+ AmqpClass thisClass = model.getClassMap().get(cItr.next());
+ String instanceName = parseForReservedWords(Utils.firstLower(thisClass.getName()), outerClassName);
+ sb.append("," + CR);
+ sb.append(indent + instanceName + "(out, this)");
+ if (!cItr.hasNext())
+ {
+ sb.append(CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateProxyInnerClassGetMethodImpls(AmqpModel model, boolean serverFlag,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ String outerClassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ Iterator<String> cItr = model.getClassMap().keySet().iterator();
+ while (cItr.hasNext())
+ {
+ AmqpClass thisClass = model.getClassMap().get(cItr.next());
+ String className = thisClass.getName();
+ String instanceName = parseForReservedWords(Utils.firstLower(thisClass.getName()), outerClassName);
+ sb.append(indent + outerClassName + "::" + className + "& " +
+ outerClassName + "::get" + className + "()" + CR);
+ sb.append(indent + "{" + CR);
+ if (thisClass.getVersionSet().size() != getVersionSet().size())
+ {
+ sb.append(indent + tab + "if (!" + generateVersionCheck(thisClass.getVersionSet()) + ")" + CR);
+ sb.append(indent + tab + tab + "throw new ProtocolVersionException();" + CR);
+ }
+ sb.append(indent + tab + "return " + instanceName + ";" + CR);
+ sb.append(indent + "}" + CR);
+ if (cItr.hasNext())
+ {
+ sb.append(CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateProxyInnerClassImpl(AmqpModel model, boolean serverFlag,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ boolean firstClassFlag = true;
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ String className = thisClass.getName();
+ if (!firstClassFlag)
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "// ==================== class " + className +
+ " ====================" + CR);
+ sb.append(generateInnerClassMethodImpls(thisClass, serverFlag, indentSize, tabSize));
+ firstClassFlag = false;
+ }
+ return sb.toString();
+ }
+
+ protected String generateInnerClassMethodImpls(AmqpClass thisClass, boolean serverFlag,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String outerclassName = "AMQP_" + (serverFlag ? "Server" : "Client") + "Proxy";
+ boolean first = true;
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ String methodBodyClassName = thisClass.getName() + Utils.firstUpper(method.getName()) + "Body";
+ boolean clientChassisFlag = method.getClientMethodFlagMap().isSet();
+ boolean serverChassisFlag = method.getServerMethodFlagMap().isSet();
+ boolean versionConsistentFlag = method.isVersionConsistent(getVersionSet());
+ if ((serverFlag && serverChassisFlag) || (!serverFlag && clientChassisFlag))
+ {
+ String methodName = parseForReservedWords(method.getName(), outerclassName + "." + thisClass.getName());
+ AmqpOverloadedParameterMap overloadededParameterMap =
+ method.getOverloadedParameterLists(thisClass.getVersionSet(), this);
+ for (AmqpOrdinalFieldMap thisFieldMap : overloadededParameterMap.keySet())
+ {
+ AmqpVersionSet versionSet = overloadededParameterMap.get(thisFieldMap);
+ if (!first)
+ {
+ sb.append(CR);
+ }
+ sb.append(indent + "void " + outerclassName + "::" + thisClass.getName() + "::" +
+ methodName + "( u_int16_t channel");
+ sb.append(generateMethodParameterList(thisFieldMap, indentSize + (5 * tabSize), true, true, true));
+ sb.append(" )");
+ if (versionSet.size() != getVersionSet().size())
+ {
+ sb.append(" // AMQP Version(s) " + versionSet);
+ }
+ sb.append(CR);
+ sb.append(indent + "{" + CR);
+ sb.append(generateMethodBodyCallContext(thisFieldMap, outerclassName, methodBodyClassName,
+ versionConsistentFlag, versionSet, indentSize + tabSize, tabSize));
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ first = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateMethodBodyCallContext(AmqpOrdinalFieldMap fieldMap, String outerclassName,
+ String methodBodyClassName, boolean versionConsistentFlag, AmqpVersionSet versionSet,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ if (versionConsistentFlag)
+ {
+ sb.append(generateMethodBodyCall(fieldMap, methodBodyClassName, null, indentSize, tabSize));
+ }
+ else
+ {
+ boolean firstOverloadedMethodFlag = true;
+ for (AmqpVersion thisVersion : versionSet)
+ {
+ sb.append(indent);
+ if (!firstOverloadedMethodFlag)
+ {
+ sb.append("else ");
+ }
+ sb.append("if (" + generateVersionCheck(thisVersion) + ")" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(generateMethodBodyCall(fieldMap, methodBodyClassName, thisVersion,
+ indentSize + tabSize, tabSize));
+ sb.append(indent + "}" + CR);
+ firstOverloadedMethodFlag = false;
+ }
+ sb.append(indent + "else" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "std::stringstream ss;" + CR);
+ sb.append(indent + tab + "ss << \"Call to " + outerclassName + "::" + methodBodyClassName +
+ "(u_int16_t" + generateMethodParameterList(fieldMap, 0, true, true, false) + ")\"" + CR);
+ sb.append(indent + tab + tab + "<< \" is invalid for AMQP version \" << version.toString() << \".\";" + CR);
+ sb.append(indent + tab + "throw new ProtocolVersionException(ss.str());" + CR);
+ sb.append(indent + "}" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateMethodBodyCall(AmqpOrdinalFieldMap fieldMap, String methodBodyClassName,
+ AmqpVersion version, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ String namespace = version != null ? version.namespace() + "::" : "";
+ StringBuffer sb = new StringBuffer(indent + "out->send( new AMQFrame(parent->getProtocolVersion(), channel," + CR);
+ sb.append(indent + tab + "new " + namespace + methodBodyClassName + "( parent->getProtocolVersion()");
+ sb.append(generateMethodParameterList(fieldMap, indentSize + (5 * tabSize), true, false, true));
+ sb.append(" )));" + CR);
+ return sb.toString();
+ }
+
+ protected String generateMethodBodyIncludes(AmqpClass thisClass, int indentSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ if (thisClass != null)
+ {
+ sb.append(generateClassMethodBodyInclude(thisClass, indentSize));
+ }
+ else
+ {
+ for (String thisClassName : getModel().getClassMap().keySet())
+ {
+ thisClass = getModel().getClassMap().get(thisClassName);
+ sb.append(generateClassMethodBodyInclude(thisClass, indentSize));
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateClassMethodBodyInclude(AmqpClass thisClass, int indentSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ String indent = Utils.createSpaces(indentSize);
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ sb.append(indent + "#include <" + thisClass.getName() +
+ Utils.firstUpper(method.getName()) + "Body.h>" + CR);
+ }
+ return sb.toString();
+ }
+
+ // Methods used for generation of code snippets for MethodBody class generation
+
+ protected String getIndex(AmqpOrdinalVersionMap indexMap, AmqpVersion version)
+ {
+ for (Integer thisIndex : indexMap.keySet())
+ {
+ AmqpVersionSet versionSet = indexMap.get(thisIndex);
+ if (versionSet.contains(version))
+ {
+ return String.valueOf(thisIndex);
+ }
+ }
+ throw new AmqpTemplateException("Unable to find index for version " + version);
+ }
+
+ protected String generateFieldDeclarations(AmqpFieldMap fieldMap, AmqpVersion version, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ if (version == null)
+ {
+ version = getVersionSet().first();
+ }
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this);
+ for (Integer thisOrdinal : ordinalFieldMap.keySet())
+ {
+ String[] fieldDomainPair = ordinalFieldMap.get(thisOrdinal);
+ sb.append(indent + fieldDomainPair[FIELD_CODE_TYPE] + " " + fieldDomainPair[FIELD_NAME] + ";" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateFieldGetMethods(AmqpFieldMap fieldMap, AmqpVersion version, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ if (version == null)
+ {
+ version = getVersionSet().first();
+ }
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this);
+ for (Integer thisOrdinal : ordinalFieldMap.keySet())
+ {
+ String[] fieldDomainPair = ordinalFieldMap.get(thisOrdinal);
+ sb.append(indent + "inline " + setRef(fieldDomainPair[FIELD_CODE_TYPE]) + " get" +
+ Utils.firstUpper(fieldDomainPair[FIELD_NAME]) + "() { return " +
+ fieldDomainPair[FIELD_NAME] + "; }" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generatePrintMethodContents(AmqpFieldMap fieldMap, AmqpVersion version, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ if (version == null)
+ {
+ version = getVersionSet().first();
+ }
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this);
+ boolean firstFlag = true;
+ for (Integer thisOrdinal : ordinalFieldMap.keySet())
+ {
+ String[] fieldDomainPair = ordinalFieldMap.get(thisOrdinal);
+ String cast = fieldDomainPair[FIELD_CODE_TYPE].compareTo("u_int8_t") == 0 ? "(int)" : "";
+ sb.append(indent + "out << \"");
+ if (!firstFlag)
+ {
+ sb.append("; ");
+ }
+ sb.append(fieldDomainPair[FIELD_NAME] + "=\" << " + cast + fieldDomainPair[FIELD_NAME] + ";" + CR);
+ firstFlag = false;
+ }
+ return sb.toString();
+ }
+
+ protected String generateBodySizeMethodContents(AmqpFieldMap fieldMap, AmqpVersion version,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ ArrayList<String> bitFieldList = new ArrayList<String>();
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, false, this);
+ Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator();
+ int ordinal = 0;
+ while (oItr.hasNext())
+ {
+ ordinal = oItr.next();
+ String[] fieldDomainPair = ordinalFieldMap.get(ordinal);
+ AmqpVersion thisVersion = version == null ? getVersionSet().first() : version;
+ String domainType = getDomainType(fieldDomainPair[FIELD_CODE_TYPE], thisVersion);
+
+ // Defer bit types by adding them to an array. When the first subsequent non-bit
+ // type is encountered, then handle the bits. This allows consecutive bits to be
+ // placed into the same byte(s) - 8 bits to the byte.
+ if (domainType.compareTo("bit") == 0)
+ {
+ bitFieldList.add(fieldDomainPair[FIELD_NAME]);
+ }
+ else
+ {
+ if (bitFieldList.size() > 0) // Handle accumulated bit types (if any)
+ {
+ sb.append(generateBitArrayBodySizeMethodContents(bitFieldList, ordinal, indentSize));
+ }
+ sb.append(indent + "size += " +
+ typeMap.get(domainType).size.replaceAll("#", fieldDomainPair[FIELD_NAME]) +
+ "; /* " + fieldDomainPair[FIELD_NAME] + ": " +
+ domainType + " */" + CR);
+ }
+ }
+ if (bitFieldList.size() > 0) // Handle any remaining accumulated bit types
+ {
+ sb.append(generateBitArrayBodySizeMethodContents(bitFieldList, ordinal, indentSize));
+ }
+ return sb.toString();
+ }
+
+ protected String generateBitArrayBodySizeMethodContents(ArrayList<String> bitFieldList,
+ int ordinal, int indentSize)
+ {
+ int numBytes = ((bitFieldList.size() - 1) / 8) + 1;
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ String comment = bitFieldList.size() == 1 ?
+ bitFieldList.get(0) + ": bit" :
+ "Combinded bits: " + bitFieldList;
+ sb.append(indent + "size += " +
+ typeMap.get("bit").size.replaceAll("~", String.valueOf(numBytes)) +
+ "; /* " + comment + " */" + CR);
+ bitFieldList.clear();
+ return sb.toString();
+ }
+
+ protected String generateEncodeMethodContents(AmqpFieldMap fieldMap, AmqpVersion version,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ ArrayList<String> bitFieldList = new ArrayList<String>();
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, false, this);
+ Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator();
+ int ordinal = 0;
+ while (oItr.hasNext())
+ {
+ ordinal = oItr.next();
+ String[] fieldDomainPair = ordinalFieldMap.get(ordinal);
+ AmqpVersion thisVersion = version == null ? getVersionSet().first() : version;
+ String domainType = getDomainType(fieldDomainPair[FIELD_CODE_TYPE], thisVersion);
+
+ // Defer bit types by adding them to an array. When the first subsequent non-bit
+ // type is encountered, then handle the bits. This allows consecutive bits to be
+ // placed into the same byte(s) - 8 bits to the byte.
+ if (domainType.compareTo("bit") == 0)
+ {
+ bitFieldList.add(fieldDomainPair[FIELD_NAME]);
+ }
+ else
+ {
+ if (bitFieldList.size() > 0) // Handle accumulated bit types (if any)
+ {
+ sb.append(generateBitEncodeMethodContents(bitFieldList, ordinal, indentSize));
+ }
+ sb.append(indent +
+ typeMap.get(domainType).encodeExpression.replaceAll("#", fieldDomainPair[FIELD_NAME]) +
+ "; /* " + fieldDomainPair[FIELD_NAME] + ": " + domainType + " */" + CR);
+ }
+ }
+ if (bitFieldList.size() > 0) // Handle any remaining accumulated bit types
+ {
+ sb.append(generateBitEncodeMethodContents(bitFieldList, ordinal, indentSize));
+ }
+
+ return sb.toString();
+ }
+
+ protected String generateBitEncodeMethodContents(ArrayList<String> bitFieldList, int ordinal,
+ int indentSize)
+ {
+ int numBytes = ((bitFieldList.size() - 1) / 8) + 1;
+ String indent = Utils.createSpaces(indentSize);
+ String bitArrayName = "flags_" + ordinal;
+ StringBuffer sb = new StringBuffer(indent + "u_int8_t " + bitArrayName +
+ "[" + numBytes + "] = {0};" +
+ (numBytes != 1 ? " /* All array elements will be initialized to 0 */" : "") +
+ CR);
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ int bitIndex = i % 8;
+ int byteIndex = i / 8;
+ sb.append(indent + bitArrayName + "[" + byteIndex + "] |= " + bitFieldList.get(i) +
+ " << " + bitIndex + "; /* " + bitFieldList.get(i) + ": bit */" + CR);
+ }
+ for (int i = 0; i < numBytes; i++)
+ {
+ sb.append(indent + "buffer.putOctet(" + bitArrayName + "[" + i + "]);" + CR);
+ }
+ bitFieldList.clear();
+ return sb.toString();
+ }
+
+ protected String generateDecodeMethodContents(AmqpFieldMap fieldMap, AmqpVersion version,
+ int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ ArrayList<String> bitFieldList = new ArrayList<String>();
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, false, this);
+ Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator();
+ int ordinal = 0;
+ while (oItr.hasNext())
+ {
+ ordinal = oItr.next();
+ String[] fieldDomainPair = ordinalFieldMap.get(ordinal);
+ AmqpVersion thisVersion = version == null ? getVersionSet().first() : version;
+ String domainType = getDomainType(fieldDomainPair[FIELD_CODE_TYPE], thisVersion);
+
+ // Defer bit types by adding them to an array. When the first subsequent non-bit
+ // type is encountered, then handle the bits. This allows consecutive bits to be
+ // placed into the same byte(s) - 8 bits to the byte.
+ if (domainType.compareTo("bit") == 0)
+ {
+ bitFieldList.add(fieldDomainPair[FIELD_NAME]);
+ }
+ else
+ {
+ if (bitFieldList.size() > 0) // Handle accumulated bit types (if any)
+ {
+ sb.append(generateBitDecodeMethodContents(bitFieldList, ordinal, indentSize));
+ }
+ sb.append(indent +
+ typeMap.get(domainType).decodeExpression.replaceAll("#", fieldDomainPair[FIELD_NAME]) +
+ "; /* " + fieldDomainPair[FIELD_NAME] + ": " + domainType + " */" + CR);
+ }
+ }
+ if (bitFieldList.size() > 0) // Handle any remaining accumulated bit types
+ {
+ sb.append(generateBitDecodeMethodContents(bitFieldList, ordinal, indentSize));
+ }
+
+ return sb.toString();
+ }
+
+ protected String generateBitDecodeMethodContents(ArrayList<String> bitFieldList, int ordinal,
+ int indentSize)
+ {
+ int numBytes = ((bitFieldList.size() - 1) / 8) + 1;
+ String indent = Utils.createSpaces(indentSize);
+ String bitArrayName = "flags_" + ordinal;
+ StringBuffer sb = new StringBuffer(indent + "u_int8_t " + bitArrayName +
+ "[" + numBytes + "];" + CR);
+ for (int i = 0; i < numBytes; i++)
+ {
+ sb.append(indent + bitArrayName + "[" + i + "] = buffer.getOctet();" + CR);
+ }
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ int bitIndex = i % 8;
+ int byteIndex = i / 8;
+ sb.append(indent + bitFieldList.get(i) + " = (1 << " + bitIndex + ") & " +
+ bitArrayName + "[" + byteIndex + "]; /* " + bitFieldList.get(i) +
+ ": bit */" + CR);
+ }
+ bitFieldList.clear();
+ return sb.toString();
+ }
+
+ protected String generateFieldList(AmqpFieldMap fieldMap, AmqpVersion version, boolean defineFlag,
+ boolean initializerFlag, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ AmqpOrdinalFieldMap ordinalFieldMap = fieldMap.getMapForVersion(version, true, this);
+ Iterator<Integer> oItr = ordinalFieldMap.keySet().iterator();
+ while (oItr.hasNext())
+ {
+ int ordinal = oItr.next();
+ String[] fieldDomainPair = ordinalFieldMap.get(ordinal);
+ sb.append(indent + (defineFlag ? setRef(fieldDomainPair[FIELD_CODE_TYPE]) + " " : "") +
+ fieldDomainPair[FIELD_NAME] + (initializerFlag ? "(" + fieldDomainPair[FIELD_NAME] + ")" : "") +
+ (oItr.hasNext() ? "," : "") + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateMethodParameterList(AmqpOrdinalFieldMap fieldMap, int indentSize,
+ boolean leadingCommaFlag, boolean fieldTypeFlag, boolean fieldNameFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ boolean first = true;
+ Iterator<Integer> pItr = fieldMap.keySet().iterator();
+ while (pItr.hasNext())
+ {
+ String[] field = fieldMap.get(pItr.next());
+ if (first && leadingCommaFlag)
+ {
+ sb.append("," + (fieldNameFlag ? CR : " "));
+ }
+ if (!first || leadingCommaFlag)
+ {
+ sb.append(indent);
+ }
+ sb.append(
+ (fieldTypeFlag ? setRef(field[FIELD_CODE_TYPE]) : "") +
+ (fieldNameFlag ? " " + field[FIELD_NAME] : "") +
+ (pItr.hasNext() ? "," + (fieldNameFlag ? CR : " ") : ""));
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ protected String generateConstructor(AmqpClass thisClass, AmqpMethod method,
+ AmqpVersion version, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ if (method.getFieldMap().size() > 0)
+ {
+ sb.append(indent + thisClass.getName() + Utils.firstUpper(method.getName()) + "Body(ProtocolVersion& version," + CR);
+ sb.append(generateFieldList(method.getFieldMap(), version, true, false, 8));
+ sb.append(indent + tab + ") :" + CR);
+ sb.append(indent + tab + "AMQMethodBody(version)," + CR);
+ sb.append(generateFieldList(method.getFieldMap(), version, false, true, 8));
+ sb.append(indent + "{ }" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateServerOperationsInvoke(AmqpClass thisClass, AmqpMethod method,
+ AmqpVersion version, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+
+ if (method.getServerMethodFlagMap().size() > 0) // At least one AMQP version defines this method as a server method
+ {
+ Iterator<Boolean> bItr = method.getServerMethodFlagMap().keySet().iterator();
+ while (bItr.hasNext())
+ {
+ if (bItr.next()) // This is a server operation
+ {
+ boolean fieldMapNotEmptyFlag = method.getFieldMap().size() > 0;
+ sb.append(indent + "inline void invoke(AMQP_ServerOperations& target, u_int16_t channel)" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "target.get" + thisClass.getName() + "Handler()->" +
+ parseForReservedWords(Utils.firstLower(method.getName()),
+ thisClass.getName() + Utils.firstUpper(method.getName()) + "Body.invoke()") + "(channel");
+ if (fieldMapNotEmptyFlag)
+ {
+ sb.append("," + CR);
+ sb.append(generateFieldList(method.getFieldMap(), version, false, false, indentSize + 4 * tabSize));
+ sb.append(indent + tab + tab + tab + tab);
+ }
+ sb.append(");" + CR);
+ sb.append(indent + "}" + CR);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ // Methods for generation of code snippets for amqp_methods.h/cpp files
+
+ protected String generateMethodBodyIncludeList(AmqpModel model, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ sb.append(indent + "#include \"" + thisClass.getName() + Utils.firstUpper(method.getName()) + "Body.h\"" + CR);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ protected String generateMethodBodyInstances(AmqpModel model, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ sb.append(indent + "const " + thisClass.getName() + Utils.firstUpper(method.getName()) + "Body " +
+ Utils.firstLower(thisClass.getName()) + "_" + method.getName() + ";" + CR);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ protected String generateMethodBodyMapEntry(AmqpModel model, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ for (AmqpVersion version : getVersionSet())
+ {
+ for (String thisClassName : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(thisClassName);
+ for (String thisMethodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(thisMethodName);
+ String namespace = method.isVersionConsistent(getVersionSet()) ? "" : version.namespace() + "::";
+ try
+ {
+ int classOrdinal = thisClass.getIndexMap().getOrdinal(version);
+ int methodOrdinal = method.getIndexMap().getOrdinal(version);
+ String methodModyClassName = namespace + thisClass.getName() + Utils.firstUpper(method.getName()) + "Body";
+ sb.append(indent + "insert(std::make_pair(createMapKey(" + classOrdinal + ", " +
+ methodOrdinal + ", " + version.getMajor() + ", " + version.getMinor() +
+ "), &createMethodBodyFn<" + methodModyClassName + ">));" + CR);
+ }
+ catch (AmqpTypeMappingException e)
+ {
+ } // ignore
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ // Helper functions
+
+ private String generateVersionCheck(AmqpVersion version)
+ {
+ return "version.equals(" + version.getMajor() + ", " + version.getMinor() + ")";
+ }
+
+ private String generateVersionCheck(AmqpVersionSet versionSet)
+ {
+ StringBuffer sb = new StringBuffer();
+ for (AmqpVersion v : versionSet)
+ {
+ if (!v.equals(versionSet.first()))
+ {
+ sb.append(" || ");
+ }
+ if (versionSet.size() > 1)
+ {
+ sb.append("(");
+ }
+ sb.append("version.equals(" + v.getMajor() + ", " + v.getMinor() + ")");
+ if (versionSet.size() > 1)
+ {
+ sb.append(")");
+ }
+ }
+ return sb.toString();
+ }
+
+ private String parseForReservedWords(String name, String context)
+ {
+ for (String cppReservedWord : cppReservedWords)
+ {
+ if (name.compareTo(cppReservedWord) == 0)
+ {
+ if (!quietFlag)
+ {
+ System.out.println("WARNING: " + (context == null ? "" : context + ": ") +
+ "Found XML method \"" + name + "\", which is a C++ reserved word. " +
+ "Changing generated name to \"" + name + "_\".");
+ }
+ return name + "_";
+ }
+ }
+
+ for (String cppCommonDefine : cppCommonDefines)
+ {
+ if (name.compareTo(cppCommonDefine) == 0)
+ {
+ if (!quietFlag)
+ {
+ System.out.println("WARNING: " + (context == null ? "" : context + ": ") +
+ "Found XML method \"" + name + "\", which may clash with commonly used defines within C++. " +
+ "Changing generated name to \"" + name + "_\".");
+ }
+ return name + "_";
+ }
+ }
+
+ return name;
+ }
+
+ private String setRef(String codeType)
+ {
+ if (codeType.compareTo("string") == 0 ||
+ codeType.compareTo("FieldTable") == 0)
+ {
+ return "const " + codeType + "&";
+ }
+ return codeType;
+ }
+
+ private String camelCaseName(String name, boolean upperFirstFlag)
+ {
+ StringBuffer ccn = new StringBuffer();
+ String[] toks = name.split("[-_.\\ ]");
+ for (int i = 0; i < toks.length; i++)
+ {
+ StringBuffer b = new StringBuffer(toks[i]);
+ if (upperFirstFlag || i > 0)
+ {
+ b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0)));
+ }
+ ccn.append(b);
+ }
+ return ccn.toString();
+ }
+
+ public static Factory<CppGenerator> _factoryInstance = new Factory<CppGenerator>()
+ {
+
+ public CppGenerator newInstance()
+ {
+ return new CppGenerator();
+ }
+ };
+
+ public static Factory<CppGenerator> getFactory()
+ {
+ return _factoryInstance;
+ }
+
+ void processModelTemplate(NamedTemplate template, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ public String getNativeType(String type)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getEncodingType(String type)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java b/java/common/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java
new file mode 100644
index 0000000000..9fc81dd428
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/DotnetGenerator.java
@@ -0,0 +1,382 @@
+/*
+ *
+ * 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.util.TreeMap;
+
+public class DotnetGenerator extends Generator
+{
+ private class DomainInfo
+ {
+ public String type;
+ public String size;
+ public String encodeExpression;
+ public String decodeExpression;
+
+ public DomainInfo(String domain, String size, String encodeExpression, String decodeExpression)
+ {
+ this.type = domain;
+ this.size = size;
+ this.encodeExpression = encodeExpression;
+ this.decodeExpression = decodeExpression;
+ }
+ }
+
+ private static TreeMap<String, DomainInfo> typeMap = new TreeMap<String, DomainInfo>();
+
+ public String getNativeType(String type)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getEncodingType(String type)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public DotnetGenerator()
+ {
+ super();
+ // Load .NET type and size maps.
+ // Adjust or add to these lists as new types are added/defined.
+ // The char '#' will be replaced by the field variable name (any type).
+ // The char '~' will be replaced by the compacted bit array size (type bit only).
+ // TODO: I have left a copy of the Java typeMap here - replace with appropriate .NET values.
+ typeMap.put("bit", new DomainInfo(
+ "boolean", // .NET code type
+ "~", // size
+ "EncodingUtils.writeBooleans(buffer, #)", // encode expression
+ "# = EncodingUtils.readBooleans(buffer)")); // decode expression
+ typeMap.put("content", new DomainInfo(
+ "Content", // .NET code type
+ "EncodingUtils.encodedContentLength(#)", // size
+ "EncodingUtils.writeContentBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readContent(buffer)")); // decode expression
+ typeMap.put("long", new DomainInfo(
+ "long", // .NET code type
+ "4", // size
+ "EncodingUtils.writeUnsignedInteger(buffer, #)", // encode expression
+ "# = buffer.getUnsignedInt()")); // decode expression
+ typeMap.put("longlong", new DomainInfo(
+ "long", // .NET code type
+ "8", // size
+ "buffer.putLong(#)", // encode expression
+ "# = buffer.getLong()")); // decode expression
+ typeMap.put("longstr", new DomainInfo(
+ "byte[]", // .NET code type
+ "EncodingUtils.encodedLongstrLength(#)", // size
+ "EncodingUtils.writeLongStringBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readLongstr(buffer)")); // decode expression
+ typeMap.put("octet", new DomainInfo(
+ "short", // .NET code type
+ "1", // size
+ "EncodingUtils.writeUnsignedByte(buffer, #)", // encode expression
+ "# = buffer.getUnsigned()")); // decode expression
+ typeMap.put("short", new DomainInfo(
+ "int", // .NET code type
+ "2", // size
+ "EncodingUtils.writeUnsignedShort(buffer, #)", // encode expression
+ "# = buffer.getUnsignedShort()")); // decode expression
+ typeMap.put("shortstr", new DomainInfo(
+ "AMQShortString", // .NET code type
+ "EncodingUtils.encodedShortStringLength(#)", // size
+ "EncodingUtils.writeShortStringBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readAMQShortString(buffer)")); // decode expression
+ typeMap.put("table", new DomainInfo(
+ "FieldTable", // .NET code type
+ "EncodingUtils.encodedFieldTableLength(#)", // size
+ "EncodingUtils.writeFieldTableBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readFieldTable(buffer)")); // decode expression
+ typeMap.put("timestamp", new DomainInfo(
+ "long", // .NET code type
+ "8", // size
+ "EncodingUtils.writeTimestamp(buffer, #)", // encode expression
+ "# = EncodingUtils.readTimestamp(buffer)")); // decode expression
+ }
+
+ void processModelTemplate(NamedTemplate template, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ void processClassTemplate(NamedTemplate template, AmqpClass amqpClass, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ void processMethodTemplate(NamedTemplate template, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ void processFieldTemplate(NamedTemplate template, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpField amqpField, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ protected String prepareFilename(String filenameTemplate,
+ AmqpClass thisClass, AmqpMethod method, AmqpField field, AmqpVersion version)
+ {
+ StringBuffer sb = new StringBuffer(filenameTemplate);
+ if (thisClass != null)
+ {
+ replaceToken(sb, "${CLASS}", thisClass.getName());
+ }
+ if (method != null)
+ {
+ replaceToken(sb, "${METHOD}", method.getName());
+ }
+ if (field != null)
+ {
+ replaceToken(sb, "${FIELD}", field.getName());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ protected void processClassList(StringBuffer sb, int listMarkerStartIndex,
+ int listMarkerEndIndex, AmqpModel model, AmqpVersion version)
+ throws AmqpTemplateException, AmqpTypeMappingException
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ // TODO: Add in tokens and calls to their corresponding generator methods here...
+ if (token.compareTo("${??????????}") == 0)
+ {
+ codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present.
+// codeSnippet = generateRegistry(model, 8, 4);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processConstantList(StringBuffer sb,
+ int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpConstantSet constantSet) throws AmqpTemplateException,
+ AmqpTypeMappingException
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ // TODO: Add in tokens and calls to their corresponding generator methods here...
+ if (token.compareTo("${??????????}") == 0)
+ {
+ codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present.
+// codeSnippet = generateConstantGetMethods(constantSet, 4, 4);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processFieldList(StringBuffer sb, int listMarkerStartIndex,
+ int listMarkerEndIndex, AmqpFieldMap fieldMap, AmqpVersion version)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ // TODO: Add in tokens and calls to their corresponding generator methods here...
+ if (token.compareTo("${??????????}") == 0)
+ {
+ codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present.
+// codeSnippet = fieldMap.parseFieldMap(declarationGenerateMethod,
+// mangledDeclarationGenerateMethod, 4, 4, this);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processMethodList(StringBuffer sb, int listMarkerStartIndex,
+ int listMarkerEndIndex, AmqpClass thisClass)
+ throws AmqpTemplateException, AmqpTypeMappingException
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ // TODO: Add in tokens and calls to their corresponding generator methods here...
+ if (token.compareTo("${??????????}") == 0)
+ {
+ codeSnippet = token; // This is a stub to get the compile working - remove when gen method is present.
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processModelTemplate(NamedTemplate template)
+ {
+ // I've put in the Java model here - this can be changed if a different pattern is required.
+ processTemplate(template, null, null, null, null);
+ }
+
+ @Override
+ protected void processClassTemplate(NamedTemplate template, AmqpClass thisClass)
+ {
+ // I've put in the Java model here - this can be changed if a different pattern is required.
+ processTemplate(template, thisClass, null, null, null);
+ }
+
+ @Override
+ protected void processMethodTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method)
+ {
+ // I've put in the Java model here - this can be changed if a different pattern is required.
+ processTemplate(template, thisClass, method, null, null);
+ }
+
+ @Override
+ protected void processTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method, AmqpField field, AmqpVersion version)
+ {
+ // I've put in the Java model here - this can be changed if a different pattern is required.
+ StringBuffer sb = new StringBuffer(template.getTemplate());
+ String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, field, version);
+ try
+ {
+ processAllLists(sb, thisClass, method, null);
+ }
+ catch (AmqpTemplateException e)
+ {
+ System.out.println("WARNING: " + template.getName() + ": " + e.getMessage());
+ }
+ try
+ {
+ processAllTokens(sb, thisClass, method, field, null);
+ }
+ catch (AmqpTemplateException e)
+ {
+ System.out.println("WARNING: " + template.getName() + ": " + e.getMessage());
+ }
+ writeTargetFile(sb, new File(getOutputDirectory() + Utils.FILE_SEPARATOR + filename));
+ generatedFileCounter++;
+ }
+
+ @Override
+ protected String processToken(String token, AmqpClass thisClass,
+ AmqpMethod method, AmqpField field, AmqpVersion version)
+ throws AmqpTemplateException, AmqpTypeMappingException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getGeneratedType(String domainName, AmqpVersion version)
+ throws AmqpTypeMappingException
+ {
+ String domainType = getDomainType(domainName, version);
+ if (domainType == null)
+ {
+ throw new AmqpTypeMappingException("Domain type \"" + domainName +
+ "\" not found in Java typemap.");
+ }
+ DomainInfo info = typeMap.get(domainType);
+ if (info == null)
+ {
+ throw new AmqpTypeMappingException("Unknown domain: \"" + domainType + "\"");
+ }
+ return info.type;
+ }
+
+ public String prepareClassName(String className)
+ {
+ return camelCaseName(className, true);
+ }
+
+ public String prepareDomainName(String domainName)
+ {
+ return camelCaseName(domainName, false);
+ }
+
+ public String prepareMethodName(String methodName)
+ {
+ return camelCaseName(methodName, false);
+ }
+
+ private String camelCaseName(String name, boolean upperFirstFlag)
+ {
+ StringBuffer ccn = new StringBuffer();
+ String[] toks = name.split("[-_.\\ ]");
+ for (int i = 0; i < toks.length; i++)
+ {
+ StringBuffer b = new StringBuffer(toks[i]);
+ if (upperFirstFlag || i > 0)
+ {
+ b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0)));
+ }
+ ccn.append(b);
+ }
+ return ccn.toString();
+ }
+
+
+ public static Factory<DotnetGenerator> _factoryInstance = new Factory<DotnetGenerator>()
+ {
+
+ public DotnetGenerator newInstance()
+ {
+ return new DotnetGenerator();
+ }
+ };
+
+ public static Factory<DotnetGenerator> getFactory()
+ {
+ return _factoryInstance;
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/GenerateMethod.java b/java/common/gentools/src/org/apache/qpid/gentools/GenerateMethod.java
new file mode 100644
index 0000000000..8b0bb99b41
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/GenerateMethod.java
@@ -0,0 +1,27 @@
+/*
+ *
+ * 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;
+
+
+public interface GenerateMethod
+{
+ String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize);
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/Generator.java b/java/common/gentools/src/org/apache/qpid/gentools/Generator.java
new file mode 100644
index 0000000000..5d6e7be527
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/Generator.java
@@ -0,0 +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");
+
+ 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);
+
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/JavaGenerator.java b/java/common/gentools/src/org/apache/qpid/gentools/JavaGenerator.java
new file mode 100644
index 0000000000..7730fca1bd
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/JavaGenerator.java
@@ -0,0 +1,1826 @@
+/*
+ *
+ * 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.util.Iterator;
+import java.util.List;
+import java.util.TreeMap;
+
+public class JavaGenerator extends Generator
+{
+ // TODO: Move this to parent class
+ protected static final int FIELD_NAME = 0;
+ protected static final int FIELD_CODE_TYPE = 1;
+
+ private class DomainInfo
+ {
+ final public String type;
+ final public String size;
+ final public String encodingType;
+ final public String encodeExpression;
+ final public String decodeExpression;
+
+ public DomainInfo(String domain, String size, String encodingType, String encodeExpression, String decodeExpression)
+ {
+ this.type = domain;
+ this.size = size;
+ this.encodeExpression = encodeExpression;
+ this.decodeExpression = decodeExpression;
+ this.encodingType = encodingType;
+ }
+ }
+
+ private static TreeMap<String, DomainInfo> typeMap = new TreeMap<String, DomainInfo>();
+
+ // Methods used for generation of code snippets called from the field map parsers
+
+ // Common methods
+ private final CommandGenerateMethod declarationGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateFieldDeclaration(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+
+ private MangledGenerateMethod mangledDeclarationGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMangledFieldDeclaration(field, indentSize, tabSize, notLast);
+ }
+ };
+
+ // Methods for MessageBody classes
+ private CommandGenerateMethod mbGetGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbGetMethod(codeType, field, versionSet, indentSize, tabSize, notLast); //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+
+ private MangledGenerateMethod mbMangledGetGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbMangledGetMethod(field, indentSize, tabSize, notLast);
+ }
+ };
+ private CommandGenerateMethod mbParamListGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbParamList(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+ private CommandGenerateMethod mbPassedParamListGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbPassedParamList(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+ private MangledGenerateMethod mbMangledParamListGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbMangledParamList(field, indentSize, tabSize, notLast);
+ }
+ };
+ private MangledGenerateMethod mbMangledPassedParamListGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbMangledPassedParamList(field, indentSize, tabSize, notLast);
+ }
+ };
+ private CommandGenerateMethod mbBodyInitGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbBodyInit(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+ private MangledGenerateMethod mbMangledBodyInitGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generateMbMangledBodyInit(field, indentSize, tabSize, notLast);
+ }
+ };
+ private GenerateMethod mbSizeGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbFieldSize(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod mbBitSizeGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbBitArrayFieldSize(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod mbEncodeGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbFieldEncode(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod mbBitEncodeGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbBitFieldEncode(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod mbDecodeGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbFieldDecode(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod mbBitDecodeGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbBitFieldDecode(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod mbToStringGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbFieldToString(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod mbBitToStringGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generateMbBitFieldToString(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+
+ // Methods for PropertyContentHeader classes
+ private CommandGenerateMethod pchClearGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generatePchClearMethod(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+ private MangledGenerateMethod pchMangledClearGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generatePchMangledClearMethod(field, indentSize, tabSize, notLast);
+ }
+ };
+ private CommandGenerateMethod pchGetGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generatePchGetMethod(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+ private MangledGenerateMethod pchMangledGetGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generatePchMangledGetMethod(field, indentSize, tabSize, notLast);
+ }
+ };
+ private CommandGenerateMethod pchSetGenerateMethod = new CommandGenerateMethod()
+ {
+ public String generate(String codeType, AmqpField field, AmqpVersionSet versionSet, int indentSize, int tabSize, boolean notLast)
+ {
+ return generatePchSetMethod(codeType, field, versionSet, indentSize, tabSize, notLast);
+ }
+ };
+ private MangledGenerateMethod pchMangledSetGenerateMethod = new MangledGenerateMethod()
+ {
+ public String generate(AmqpField field, int indentSize, int tabSize, boolean notLast)
+ {
+ return generatePchMangledSetMethod(field, indentSize, tabSize, notLast);
+ }
+ };
+ private GenerateMethod pchSizeGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchFieldSize(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod pchBitSizeGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchBitArrayFieldSize(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod pchEncodeGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchFieldEncode(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod pchBitEncodeGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchBitFieldEncode(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod pchDecodeGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchFieldDecode(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod pchBitDecodeGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchBitFieldDecode(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod pchGetPropertyFlagsGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchGetPropertyFlags(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod pchBitGetPropertyFlagsGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchBitGetPropertyFlags(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+ private GenerateMethod pchSetPropertyFlagsGenerateMethod = new GenerateMethod()
+ {
+ public String generate(String domainType, String fieldName, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchSetPropertyFlags(domainType, fieldName, ordinal, indentSize, tabSize);
+ }
+ };
+ private BitFieldGenerateMethod pchBitSetPropertyFlagsGenerateMethod = new BitFieldGenerateMethod()
+ {
+ public String generate(List<String> bitFieldList, int ordinal, int indentSize, int tabSize)
+ {
+ return generatePchBitSetPropertyFlags(bitFieldList, ordinal, indentSize, tabSize);
+ }
+ };
+
+
+ public String getNativeType(String type)
+ {
+ return typeMap.get(type).type;
+ }
+
+ public String getEncodingType(String type)
+ {
+ return typeMap.get(type).encodingType;
+ }
+
+
+ public JavaGenerator()
+ {
+ super();
+ // Load Java type and size maps.
+ // Adjust or add to these lists as new types are added/defined.
+ // The char '#' will be replaced by the field variable name (any type).
+ // The char '~' will be replaced by the compacted bit array size (type bit only).
+ typeMap.put("bit", new DomainInfo(
+ "boolean", // Java code type
+ "~", // size
+ "Boolean", // Java code type
+ "EncodingUtils.writeBooleans(buffer, #)", // encode expression
+ "# = EncodingUtils.readBooleans(buffer)")); // decode expression
+ typeMap.put("bitfield", new DomainInfo(
+ "byte", // Java code type
+ "~", // size
+ "Bitfield",
+ "EncodingUtils.writeBooleans(buffer, #)", // encode expression
+ "# = EncodingUtils.readBooleans(buffer)")); // decode expression
+
+ typeMap.put("content", new DomainInfo(
+ "Content", // Java code type
+ "EncodingUtils.encodedContentLength(#)", // size
+ "Content", // Java code type
+ "EncodingUtils.writeContentBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readContent(buffer)")); // decode expression
+ typeMap.put("long", new DomainInfo(
+ "long", // Java code type
+ "4", // size
+ "UnsignedInteger", // Java code type
+ "EncodingUtils.writeUnsignedInteger(buffer, #)", // encode expression
+ "# = buffer.getUnsignedInt()")); // decode expression
+ typeMap.put("longlong", new DomainInfo(
+ "long", // Java code type
+ "8", // size
+ "Long",
+ "buffer.putLong(#)", // encode expression
+ "# = buffer.getLong()")); // decode expression
+ typeMap.put("longstr", new DomainInfo(
+ "byte[]", // Java code type
+ "EncodingUtils.encodedLongstrLength(#)", // size
+ "Bytes",
+ "EncodingUtils.writeLongStringBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readLongstr(buffer)")); // decode expression
+ typeMap.put("octet", new DomainInfo(
+ "short", // Java code type
+ "1", // size
+ "UnsignedByte",
+ "EncodingUtils.writeUnsignedByte(buffer, #)", // encode expression
+ "# = buffer.getUnsigned()")); // decode expression
+ typeMap.put("short", new DomainInfo(
+ "int", // Java code type
+ "2", // size
+ "UnsignedShort",
+ "EncodingUtils.writeUnsignedShort(buffer, #)", // encode expression
+ "# = buffer.getUnsignedShort()")); // decode expression
+ typeMap.put("shortstr", new DomainInfo(
+ "AMQShortString", // Java code type
+ "EncodingUtils.encodedShortStringLength(#)", // size
+ "AMQShortString", // Java code type
+ "EncodingUtils.writeShortStringBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readAMQShortString(buffer)")); // decode expression
+ typeMap.put("table", new DomainInfo(
+ "FieldTable", // Java code type
+ "EncodingUtils.encodedFieldTableLength(#)", // size
+ "FieldTable", // Java code type
+ "EncodingUtils.writeFieldTableBytes(buffer, #)", // encode expression
+ "# = EncodingUtils.readFieldTable(buffer)")); // decode expression
+ typeMap.put("timestamp", new DomainInfo(
+ "long", // Java code type
+ "8", // size
+ "Timestamp",
+ "EncodingUtils.writeTimestamp(buffer, #)", // encode expression
+ "# = EncodingUtils.readTimestamp(buffer)")); // decode expression
+ }
+
+ // === Start of methods for Interface LanguageConverter ===
+
+ public String prepareClassName(String className)
+ {
+ return camelCaseName(className, true);
+ }
+
+ public String prepareMethodName(String methodName)
+ {
+ return camelCaseName(methodName, false);
+ }
+
+ public String prepareDomainName(String domainName)
+ {
+ return camelCaseName(domainName, false);
+ }
+
+
+ public String getGeneratedType(String domainName, AmqpVersion version)
+ {
+ String domainType = getDomainType(domainName, version);
+ if (domainType == null)
+ {
+ throw new AmqpTypeMappingException("Domain type \"" + domainName +
+ "\" not found in Java typemap.");
+ }
+ DomainInfo info = typeMap.get(domainType);
+ if (info == null)
+ {
+ throw new AmqpTypeMappingException("Unknown domain: \"" + domainType + "\"");
+ }
+ return info.type;
+ }
+
+ // === Abstract methods from class Generator - Java-specific implementations ===
+
+ @Override
+ protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, AmqpVersion version)
+ {
+ StringBuffer sb = new StringBuffer(filenameTemplate);
+ if (thisClass != null)
+ {
+ replaceToken(sb, "${CLASS}", thisClass.getName());
+ }
+ if (method != null)
+ {
+ replaceToken(sb, "${METHOD}", method.getName());
+ }
+ if (field != null)
+ {
+ replaceToken(sb, "${FIELD}", field.getName());
+ }
+ if (version != null)
+ {
+ replaceToken(sb, "${MAJOR}", String.valueOf(version.getMajor()));
+ replaceToken(sb, "${MINOR}", String.valueOf(version.getMinor()));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ protected void processModelTemplate(NamedTemplate template)
+ {
+ processTemplate(template, null, null, null, null);
+ }
+
+ @Override
+ protected void processClassTemplate(NamedTemplate template, AmqpClass thisClass)
+ {
+ processTemplate(template, thisClass, null, null,
+ thisClass.getVersionSet().size() == 1 ? thisClass.getVersionSet().first() : null);
+ }
+
+ @Override
+ protected void processMethodTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method)
+ {
+ processTemplate(template, thisClass, method, null,
+ thisClass.getVersionSet().size() == 1 ? thisClass.getVersionSet().first() : null);
+ }
+
+ protected void processFieldTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method, AmqpField field)
+ {
+ processTemplate(template, thisClass, method, field,
+ thisClass.getVersionSet().size() == 1 ? thisClass.getVersionSet().first() : null);
+ }
+
+ @Override
+ protected void processTemplate(NamedTemplate template, AmqpClass thisClass,
+ AmqpMethod method, AmqpField field, AmqpVersion version)
+ {
+ StringBuffer sb = new StringBuffer(template.getTemplate());
+ String filename = prepareFilename(getTemplateFileName(sb), thisClass, method, field, version);
+ processTemplate(sb, thisClass, method, field, template.getName(), version);
+ writeTargetFile(sb, new File(getOutputDirectory() + Utils.FILE_SEPARATOR + filename));
+ generatedFileCounter++;
+ }
+
+ protected void processTemplate(StringBuffer sb, AmqpClass thisClass, AmqpMethod method,
+ AmqpField field, String templateFileName, AmqpVersion version)
+ {
+ try
+ {
+ processAllLists(sb, thisClass, method, version);
+ }
+ catch (AmqpTemplateException e)
+ {
+ System.out.println("WARNING: " + templateFileName + ": " + e.getMessage());
+ }
+ try
+ {
+ processAllTokens(sb, thisClass, method, field, version);
+ }
+ catch (AmqpTemplateException e)
+ {
+ System.out.println("WARNING: " + templateFileName + ": " + e.getMessage());
+ }
+ }
+
+ @Override
+ protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, AmqpField field,
+ AmqpVersion version)
+ {
+ if (token.compareTo("${GENERATOR}") == 0)
+ {
+ return GENERATOR_INFO;
+ }
+ if (token.compareTo("${CLASS}") == 0 && thisClass != null)
+ {
+ return thisClass.getName();
+ }
+ if (token.compareTo("${CLASS_ID_INIT}") == 0 && thisClass != null)
+ {
+ return generateIndexInitializer("registerClassId", thisClass.getIndexMap(), 8);
+ }
+ if (token.compareTo("${METHOD}") == 0 && method != null)
+ {
+ return method.getName();
+ }
+ if (token.compareTo("${METHOD_ID_INIT}") == 0 && method != null)
+ {
+ return generateIndexInitializer("registerMethodId", method.getIndexMap(), 8);
+ }
+ if (token.compareTo("${FIELD}") == 0 && field != null)
+ {
+ return field.getName();
+ }
+
+ // This token is used only with class or method-level templates
+ if (token.compareTo("${pch_property_flags_declare}") == 0)
+ {
+ return generatePchPropertyFlagsDeclare();
+ }
+ else if (token.compareTo("${pch_property_flags_initializer}") == 0)
+ {
+ int mapSize = method == null ? thisClass.getFieldMap().size() : method.getFieldMap().size();
+ return generatePchPropertyFlagsInitializer(mapSize);
+ }
+ else if (token.compareTo("${pch_compact_property_flags_initializer}") == 0)
+ {
+ return generatePchCompactPropertyFlagsInitializer(thisClass, 8, 4);
+ }
+ else if (token.compareTo("${pch_compact_property_flags_check}") == 0)
+ {
+ return generatePchCompactPropertyFlagsCheck(thisClass, 8, 4);
+ }
+
+ // Oops!
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+
+ @Override
+ protected void processClassList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpModel model, AmqpVersion version)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ if (token.compareTo("${reg_map_put_method}") == 0)
+ {
+ codeSnippet = generateRegistry(model, 8, 4);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processMethodList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpClass thisClass)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ //TODO - we don't have any cases of this (yet).
+ if (token.compareTo("${???}") == 0)
+ {
+ codeSnippet = token;
+ }
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpFieldMap fieldMap, AmqpVersion version)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ // Field declarations - common to MethodBody and PropertyContentHeader classes
+ if (token.compareTo("${field_declaration}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMap(declarationGenerateMethod,
+ mangledDeclarationGenerateMethod, 4, 4, this);
+ }
+
+ // MethodBody classes
+ else if (token.compareTo("${mb_field_get_method}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMap(mbGetGenerateMethod,
+ mbMangledGetGenerateMethod, 4, 4, this);
+ }
+ else if (token.compareTo("${mb_field_parameter_list}") == 0)
+ {
+ // <cringe> The code generated by this is ugly... It puts a comma on a line by itself!
+ // TODO: Find a more elegant solution here sometime...
+ codeSnippet = fieldMap.size() > 0 ? Utils.createSpaces(42) + "," + CR : "";
+ // </cringe>
+ codeSnippet += fieldMap.parseFieldMap(mbParamListGenerateMethod,
+ mbMangledParamListGenerateMethod, 42, 4, this);
+ }
+
+ else if (token.compareTo("${mb_field_passed_parameter_list}") == 0)
+ {
+ // <cringe> The code generated by this is ugly... It puts a comma on a line by itself!
+ // TODO: Find a more elegant solution here sometime...
+ codeSnippet = fieldMap.size() > 0 ? Utils.createSpaces(42) + "," + CR : "";
+ // </cringe>
+ codeSnippet += fieldMap.parseFieldMap(mbPassedParamListGenerateMethod,
+ mbMangledPassedParamListGenerateMethod, 42, 4, this);
+ }
+ else if (token.compareTo("${mb_field_body_initialize}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMap(mbBodyInitGenerateMethod,
+ mbMangledBodyInitGenerateMethod, 8, 4, this);
+ }
+ else if (token.compareTo("${mb_field_size}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(mbSizeGenerateMethod,
+ mbBitSizeGenerateMethod, 8, 4, this);
+ }
+ else if (token.compareTo("${mb_field_encode}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(mbEncodeGenerateMethod,
+ mbBitEncodeGenerateMethod, 8, 4, this);
+ }
+ else if (token.compareTo("${mb_field_decode}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(mbDecodeGenerateMethod,
+ mbBitDecodeGenerateMethod, 8, 4, this);
+ }
+ else if (token.compareTo("${mb_field_to_string}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(mbToStringGenerateMethod,
+ mbBitToStringGenerateMethod, 8, 4, this);
+ }
+
+ // PropertyContentHeader classes
+ else if (token.compareTo("${pch_field_list_size}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(pchSizeGenerateMethod,
+ pchBitSizeGenerateMethod, 12, 4, this);
+ }
+ else if (token.compareTo("${pch_field_list_payload}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(pchEncodeGenerateMethod,
+ pchBitEncodeGenerateMethod, 12, 4, this);
+ }
+ else if (token.compareTo("${pch_field_list_decode}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(pchDecodeGenerateMethod,
+ pchBitDecodeGenerateMethod, 12, 4, this);
+ }
+ else if (token.compareTo("${pch_get_compact_property_flags}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(pchGetPropertyFlagsGenerateMethod,
+ pchBitGetPropertyFlagsGenerateMethod, 8, 4, this);
+ }
+ else if (token.compareTo("${pch_set_compact_property_flags}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMapOrdinally(pchSetPropertyFlagsGenerateMethod,
+ pchBitSetPropertyFlagsGenerateMethod, 8, 4, this);
+ }
+ else if (token.compareTo("${pch_field_clear_methods}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMap(pchClearGenerateMethod,
+ pchMangledClearGenerateMethod, 4, 4, this);
+ }
+ else if (token.compareTo("${pch_field_get_methods}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMap(pchGetGenerateMethod,
+ pchMangledGetGenerateMethod, 4, 4, this);
+ }
+ else if (token.compareTo("${pch_field_set_methods}") == 0)
+ {
+ codeSnippet = fieldMap.parseFieldMap(pchSetGenerateMethod,
+ pchMangledSetGenerateMethod, 4, 4, this);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ @Override
+ protected void processConstantList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex,
+ AmqpConstantSet constantSet)
+ {
+ String codeSnippet;
+ int lend = sb.indexOf(CR, listMarkerStartIndex) + 1; // Include cr at end of line
+ String tline = sb.substring(listMarkerEndIndex, lend); // Line excluding line marker, including cr
+ int tokStart = tline.indexOf('$');
+ String token = tline.substring(tokStart).trim();
+ sb.delete(listMarkerStartIndex, lend);
+
+ if (token.compareTo("${const_get_method}") == 0)
+ {
+ codeSnippet = generateConstantGetMethods(constantSet, 4, 4);
+ }
+
+ else // Oops!
+ {
+ throw new AmqpTemplateException("Template token " + token + " unknown.");
+ }
+
+ sb.insert(listMarkerStartIndex, codeSnippet);
+ }
+
+ // === Protected and private helper functions unique to Java implementation ===
+
+ // Methods used for generation of code snippets called from the field map parsers
+
+ // Common methods
+
+ protected String generateFieldDeclaration(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ return Utils.createSpaces(indentSize) + "public " + codeType + " " + field.getName() +
+ "; // AMQP version(s): " + versionSet + CR;
+ }
+
+ protected String generateMangledFieldDeclaration(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ StringBuffer sb = new StringBuffer();
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ String domainName = dItr.next();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ String codeType = getGeneratedType(domainName, versionSet.first());
+ sb.append(Utils.createSpaces(indentSize) + "public " + codeType + " " +
+ field.getName() + "_" + (domainCntr++) + "; // AMQP Version(s): " + versionSet +
+ CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateIndexInitializer(String mapName, AmqpOrdinalVersionMap indexMap, int indentSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ Iterator<Integer> iItr = indexMap.keySet().iterator();
+ while (iItr.hasNext())
+ {
+ int index = iItr.next();
+ AmqpVersionSet versionSet = indexMap.get(index);
+ Iterator<AmqpVersion> vItr = versionSet.iterator();
+ while (vItr.hasNext())
+ {
+ AmqpVersion version = vItr.next();
+ sb.append(indent + mapName + "( (byte) " + version.getMajor() + ", (byte) " + version.getMinor() + ", " + index + ");" + CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateRegistry(AmqpModel model, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+
+ for (String className : model.getClassMap().keySet())
+ {
+ AmqpClass thisClass = model.getClassMap().get(className);
+ for (String methodName : thisClass.getMethodMap().keySet())
+ {
+ AmqpMethod method = thisClass.getMethodMap().get(methodName);
+ for (AmqpVersion version : model.getVersionSet())
+ {
+ // Find class and method index for this version (if it exists)
+ try
+ {
+ int classIndex = findIndex(thisClass.getIndexMap(), version);
+ int methodIndex = findIndex(method.getIndexMap(), version);
+ sb.append(indent + "registerMethod(" + CR);
+ sb.append(indent + tab + "(short)" + classIndex +
+ ", (short)" + methodIndex + ", (byte)" + version.getMajor() +
+ ", (byte)" + version.getMinor() + ", " + CR);
+ sb.append(indent + tab + Utils.firstUpper(thisClass.getName()) +
+ Utils.firstUpper(method.getName()) + "Body.getFactory());" + CR);
+ }
+ catch (Exception e)
+ {
+ } // Ignore
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ protected int findIndex(TreeMap<Integer, AmqpVersionSet> map, AmqpVersion version)
+ {
+ Iterator<Integer> iItr = map.keySet().iterator();
+ while (iItr.hasNext())
+ {
+ int index = iItr.next();
+ AmqpVersionSet versionSet = map.get(index);
+ if (versionSet.contains(version))
+ {
+ return index;
+ }
+ }
+ throw new IllegalArgumentException("Index not found");
+ }
+
+ // Methods for AmqpConstants class
+
+
+ public String prepareConstantName(String constantName)
+ {
+ return upperCaseName(constantName);
+ }
+
+
+ protected String generateConstantGetMethods(AmqpConstantSet constantSet,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+
+ for (AmqpConstant constant : constantSet.getContstants())
+ {
+
+ if (constant.isVersionConsistent(constantSet.getVersionSet()))
+ {
+ // return a constant
+ String value = constant.firstKey();
+ if (Utils.containsOnlyDigits(value))
+ {
+ sb.append(indent + "public static final int " + constant.getName() + " = " +
+ constant.firstKey() + ";" + CR);
+ }
+ else if (Utils.containsOnlyDigitsAndDecimal(value))
+ {
+ sb.append(indent + "public static double " + constant.getName() + " = " +
+ constant.firstKey() + "; " + CR);
+ }
+ else
+ {
+ sb.append(indent + "public static String " + constant.getName() + " = " +
+ constant.firstKey() + "\"; " + CR);
+
+ }
+ sb.append(CR);
+ }
+ else
+ {
+ // Return version-specific constant
+ sb.append(generateVersionDependentGet(constant, "String", "", "\"", "\"", indentSize, tabSize));
+ sb.append(generateVersionDependentGet(constant, "int", "AsInt", "", "", indentSize, tabSize));
+ sb.append(generateVersionDependentGet(constant, "double", "AsDouble", "(double)", "", indentSize, tabSize));
+ sb.append(CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateVersionDependentGet(AmqpConstant constant,
+ String methodReturnType, String methodNameSuffix, String returnPrefix, String returnPostfix,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "public static " + methodReturnType + " " + constant.getName() +
+ methodNameSuffix + "(byte major, byte minor) throws AMQProtocolVersionException" + CR);
+ sb.append(indent + "{" + CR);
+ boolean first = true;
+ Iterator<String> sItr = constant.keySet().iterator();
+ while (sItr.hasNext())
+ {
+ String value = sItr.next();
+ AmqpVersionSet versionSet = constant.get(value);
+ sb.append(indent + tab + (first ? "" : "else ") + "if (" + generateVersionCheck(versionSet) +
+ ")" + CR);
+ sb.append(indent + tab + "{" + CR);
+ if (methodReturnType.compareTo("int") == 0 && !Utils.containsOnlyDigits(value))
+ {
+ sb.append(generateConstantDeclarationException(constant.getName(), methodReturnType,
+ indentSize + (2 * tabSize), tabSize));
+ }
+ else if (methodReturnType.compareTo("double") == 0 && !Utils.containsOnlyDigitsAndDecimal(value))
+ {
+ sb.append(generateConstantDeclarationException(constant.getName(), methodReturnType,
+ indentSize + (2 * tabSize), tabSize));
+ }
+ else
+ {
+ sb.append(indent + tab + tab + "return " + returnPrefix + value + returnPostfix + ";" + CR);
+ }
+ sb.append(indent + tab + "}" + CR);
+ first = false;
+ }
+ sb.append(indent + tab + "else" + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "throw new AMQProtocolVersionException(\"Constant \\\"" +
+ constant.getName() + "\\\" \" +" + CR);
+ sb.append(indent + tab + tab + tab +
+ "\"is undefined for AMQP version \" + major + \"-\" + minor + \".\");" + CR);
+ sb.append(indent + tab + "}" + CR);
+ sb.append(indent + "}" + CR);
+ return sb.toString();
+ }
+
+ protected String generateConstantDeclarationException(String name, String methodReturnType,
+ int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "throw new AMQProtocolVersionException(\"Constant \\\"" +
+ name + "\\\" \" +" + CR);
+ sb.append(indent + tab + "\"cannot be converted to type " + methodReturnType +
+ " for AMQP version \" + major + \"-\" + minor + \".\");" + CR);
+ return sb.toString();
+ }
+
+ // Methods for MessageBody classes
+ protected String generateMbGetMethod(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ return Utils.createSpaces(indentSize) + "public " + codeType + " get" +
+ Utils.firstUpper(field.getName()) + "() { return " + field.getName() + "; }" +
+ CR;
+ }
+
+ protected String generateMbMangledGetMethod(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer(CR);
+ sb.append(indent + "public <T> T get" + Utils.firstUpper(field.getName()) +
+ "(Class<T> classObj) throws AMQProtocolVersionException" + CR);
+ sb.append(indent + "{" + CR);
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ String domainName = dItr.next();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ String codeType = getGeneratedType(domainName, versionSet.first());
+ sb.append(indent + tab + "if (classObj.equals(" + codeType +
+ ".class)) // AMQP Version(s): " + versionSet + CR);
+ sb.append(indent + tab + tab + "return (T)(Object)" + field.getName() + "_" +
+ (domainCntr++) + ";" + CR);
+ }
+ sb.append(indent + tab +
+ "throw new AMQProtocolVersionException(\"None of the AMQP versions defines \" +" +
+ CR + " \"field \\\"" + field.getName() +
+ "\\\" as domain \\\"\" + classObj.getName() + \"\\\".\");" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generateMbParamList(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ return Utils.createSpaces(indentSize) + codeType + " " + field.getName() +
+ (nextFlag ? "," : "") + " // AMQP version(s): " + versionSet + CR;
+ }
+
+
+ protected String generateMbPassedParamList(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ return Utils.createSpaces(indentSize) + field.getName() +
+ (nextFlag ? "," : "") + " // AMQP version(s): " + versionSet + CR;
+ }
+
+
+ protected String generateMbMangledParamList(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ StringBuffer sb = new StringBuffer();
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ String domainName = dItr.next();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ String codeType = getGeneratedType(domainName, versionSet.first());
+ sb.append(Utils.createSpaces(indentSize) + codeType + " " + field.getName() + "_" +
+ (domainCntr++) + (nextFlag ? "," : "") + " // AMQP version(s): " +
+ versionSet + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateMbMangledPassedParamList(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ StringBuffer sb = new StringBuffer();
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ String domainName = dItr.next();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ sb.append(Utils.createSpaces(indentSize) + field.getName() + "_" +
+ (domainCntr++) + (nextFlag ? "," : "") + " // AMQP version(s): " +
+ versionSet + CR);
+ }
+ return sb.toString();
+ }
+
+
+ protected String generateMbBodyInit(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ return Utils.createSpaces(indentSize) + "this." + field.getName() + " = " + field.getName() +
+ ";" + CR;
+ }
+
+ protected String generateMbMangledBodyInit(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ StringBuffer sb = new StringBuffer();
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ dItr.next();
+ sb.append(Utils.createSpaces(indentSize) + "this." + field.getName() + "_" + domainCntr +
+ " = " + field.getName() + "_" + (domainCntr++) + ";" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateMbFieldSize(String domainType, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Utils.createSpaces(indentSize) + "size += " +
+ typeMap.get(domainType).size.replaceAll("#", fieldName) +
+ "; // " + fieldName + ": " + domainType + CR);
+ return sb.toString();
+ }
+
+ protected String generateMbBitArrayFieldSize(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ int numBytes = ((bitFieldList.size() - 1) / 8) + 1;
+ String comment = bitFieldList.size() == 1 ?
+ bitFieldList.get(0) + ": bit" :
+ "Combinded bits: " + bitFieldList;
+ sb.append(Utils.createSpaces(indentSize) + "size += " +
+ typeMap.get("bit").size.replaceAll("~", String.valueOf(numBytes)) +
+ "; // " + comment + CR);
+ return sb.toString();
+ }
+
+ protected String generateMbFieldEncode(String domain, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Utils.createSpaces(indentSize) +
+ typeMap.get(domain).encodeExpression.replaceAll("#", fieldName) +
+ "; // " + fieldName + ": " + domain + CR);
+ return sb.toString();
+ }
+
+ protected String generateMbBitFieldEncode(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ while (i < bitFieldList.size())
+ {
+
+ StringBuilder line = new StringBuilder();
+
+ for (int j = 0; i < bitFieldList.size() && j < 8; i++, j++)
+ {
+ if (j != 0)
+ {
+ line.append(", ");
+ }
+ line.append(bitFieldList.get(i));
+ }
+
+ sb.append(indent +
+ typeMap.get("bit").encodeExpression.replaceAll("#", line.toString()) + ";" + CR);
+ }
+ return sb.toString();
+ }
+
+ protected String generateMbFieldDecode(String domain, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Utils.createSpaces(indentSize) +
+ typeMap.get(domain).decodeExpression.replaceAll("#", fieldName) +
+ "; // " + fieldName + ": " + domain + CR);
+ return sb.toString();
+ }
+
+ protected String generateMbBitFieldDecode(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+
+ StringBuilder sb = new StringBuilder(indent);
+ sb.append("byte packedValue;");
+ sb.append(CR);
+
+ // RG HERE!
+
+ int i = 0;
+ while (i < bitFieldList.size())
+ {
+ sb.append(indent + "packedValue = EncodingUtils.readByte(buffer);" + CR);
+
+ for (int j = 0; i < bitFieldList.size() && j < 8; i++, j++)
+ {
+ sb.append(indent + bitFieldList.get(i) + " = ( packedValue & (byte) (1 << " + j + ") ) != 0;" + CR);
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generateMbFieldToString(String domain, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Utils.createSpaces(indentSize) +
+ "buf.append(\" " + fieldName + ": \" + " + fieldName + ");" + CR);
+ return sb.toString();
+ }
+
+ protected String generateMbBitFieldToString(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ String bitFieldName = bitFieldList.get(i);
+ sb.append(indent + "buf.append(\" " + bitFieldName + ": \" + " + bitFieldName +
+ ");" + CR);
+ }
+ return sb.toString();
+ }
+
+ // Methods for PropertyContentHeader classes
+
+ protected String generatePchClearMethod(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ // This is one case where the ordinal info is the only significant factor,
+ // the domain info plays no part. Defer to the mangled version; the code would be
+ // identical anyway...
+ return generatePchMangledClearMethod(field, indentSize, tabSize, nextFlag);
+ }
+
+ protected String generatePchMangledClearMethod(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "public void clear" + Utils.firstUpper(field.getName()) +
+ "()" + CR);
+ sb.append(indent + "{" + CR);
+
+ // If there is more than one ordinal for this field or the ordinal does not
+ // apply to all known versions, then we need to generate version checks so
+ // we know which fieldProperty to clear.
+ if (field.getOrdinalMap().size() == 1 &&
+ field.getOrdinalMap().get(field.getOrdinalMap().firstKey()).size() == field.getVersionSet().size())
+ {
+ int ordinal = field.getOrdinalMap().firstKey();
+ sb.append(indent + tab + "clearEncodedForm();" + CR);
+ sb.append(indent + tab + "propertyFlags[" + ordinal + "] = false;" + CR);
+ }
+ else
+ {
+ Iterator<Integer> oItr = field.getOrdinalMap().keySet().iterator();
+ while (oItr.hasNext())
+ {
+ int ordinal = oItr.next();
+ AmqpVersionSet versionSet = field.getOrdinalMap().get(ordinal);
+ sb.append(indent + tab);
+ if (ordinal != field.getOrdinalMap().firstKey())
+ {
+ sb.append("else ");
+ }
+ sb.append("if (");
+ sb.append(generateVersionCheck(versionSet));
+ sb.append(")" + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "clearEncodedForm();" + CR);
+ sb.append(indent + tab + tab + "propertyFlags[" + ordinal + "] = false;" + CR);
+ sb.append(indent + tab + "}" + CR);
+ }
+ }
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchGetMethod(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer(indent + "public " + codeType + " get" +
+ Utils.firstUpper(field.getName()) + "()" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "decodeIfNecessary();" + CR);
+ sb.append(indent + tab + "return " + field.getName() + ";" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchMangledGetMethod(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer(indent + "public <T> T get" +
+ Utils.firstUpper(field.getName()) +
+ "(Class<T> classObj) throws AMQProtocolVersionException" + CR);
+ sb.append(indent + "{" + CR);
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ String domainName = dItr.next();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ String codeType = getGeneratedType(domainName, versionSet.first());
+ sb.append(indent + tab + "if (classObj.equals(" + codeType +
+ ".class)) // AMQP Version(s): " + versionSet + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "decodeIfNecessary();" + CR);
+ sb.append(indent + tab + tab + "return (T)(Object)" + field.getName() + "_" +
+ (domainCntr++) + ";" + CR);
+ sb.append(indent + tab + "}" + CR);
+ }
+ sb.append(indent + tab +
+ "throw new AMQProtocolVersionException(\"None of the AMQP versions defines \" +" +
+ CR + " \"field \\\"" + field.getName() +
+ "\\\" as domain \\\"\" + classObj.getName() + \"\\\".\");" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchSetMethod(String codeType, AmqpField field,
+ AmqpVersionSet versionSet, int indentSize, int tabSize, boolean nextFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "public void set" + Utils.firstUpper(field.getName()) +
+ "(" + codeType + " " + field.getName() + ")" + CR);
+ sb.append(indent + "{" + CR);
+
+ // If there is more than one ordinal for this field or the ordinal does not
+ // apply to all known versions, then we need to generate version checks so
+ // we know which fieldProperty to clear.
+ if (field.getOrdinalMap().size() == 1 &&
+ field.getOrdinalMap().get(field.getOrdinalMap().firstKey()).size() == field.getVersionSet().size())
+ {
+ int ordinal = field.getOrdinalMap().firstKey();
+ sb.append(indent + tab + "clearEncodedForm();" + CR);
+ sb.append(indent + tab + "propertyFlags[" + ordinal + "] = true;" + CR);
+ sb.append(indent + tab + "this." + field.getName() + " = " + field.getName() + ";" + CR);
+ }
+ else
+ {
+ Iterator<Integer> oItr = field.getOrdinalMap().keySet().iterator();
+ while (oItr.hasNext())
+ {
+ int ordinal = oItr.next();
+ AmqpVersionSet oVersionSet = field.getOrdinalMap().get(ordinal);
+ sb.append(indent + tab);
+ if (ordinal != field.getOrdinalMap().firstKey())
+ {
+ sb.append("else ");
+ }
+ sb.append("if (");
+ sb.append(generateVersionCheck(oVersionSet));
+ sb.append(")" + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "clearEncodedForm();" + CR);
+ sb.append(indent + tab + tab + "propertyFlags[" + ordinal + "] = true;" + CR);
+ sb.append(indent + tab + tab + "this." + field.getName() + " = " + field.getName() + ";" + CR);
+ sb.append(indent + tab + "}" + CR);
+ }
+ }
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchMangledSetMethod(AmqpField field, int indentSize,
+ int tabSize, boolean nextFlag)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+
+ Iterator<String> dItr = field.getDomainMap().keySet().iterator();
+ int domainCntr = 0;
+ while (dItr.hasNext())
+ {
+ String domainName = dItr.next();
+ AmqpVersionSet versionSet = field.getDomainMap().get(domainName);
+ String codeType = getGeneratedType(domainName, versionSet.first());
+
+ // Find ordinal with matching version
+ AmqpVersionSet commonVersionSet = new AmqpVersionSet();
+ Iterator<Integer> oItr = field.getOrdinalMap().keySet().iterator();
+ while (oItr.hasNext())
+ {
+ int ordinal = oItr.next();
+ AmqpVersionSet oVersionSet = field.getOrdinalMap().get(ordinal);
+ Iterator<AmqpVersion> vItr = oVersionSet.iterator();
+ boolean first = true;
+ while (vItr.hasNext())
+ {
+ AmqpVersion thisVersion = vItr.next();
+ if (versionSet.contains(thisVersion))
+ {
+ commonVersionSet.add(thisVersion);
+ }
+ }
+ if (!commonVersionSet.isEmpty())
+ {
+ sb.append(indent + "public void set" + Utils.firstUpper(field.getName()) +
+ "(" + codeType + " " + field.getName() + ")" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab);
+ if (!first)
+ {
+ sb.append("else ");
+ }
+ sb.append("if (");
+ sb.append(generateVersionCheck(commonVersionSet));
+ sb.append(")" + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "clearEncodedForm();" + CR);
+ sb.append(indent + tab + tab + "propertyFlags[" + ordinal + "] = true;" + CR);
+ sb.append(indent + tab + tab + "this." + field.getName() + "_" + (domainCntr++) +
+ " = " + field.getName() + ";" + CR);
+ sb.append(indent + tab + "}" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(CR);
+ first = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ protected String generatePchFieldSize(String domainType, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer(indent + "if (propertyFlags[" + ordinal + "]) // " +
+ fieldName + ": " + domainType + CR);
+ sb.append(indent + Utils.createSpaces(tabSize) + "size += " +
+ typeMap.get(domainType).size.replaceAll("#", fieldName) + ";" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchBitArrayFieldSize(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ String comment = bitFieldList.size() == 1 ?
+ bitFieldList.get(0) + ": bit" :
+ "Combinded bits: " + bitFieldList;
+ StringBuffer sb = new StringBuffer();
+
+ if (bitFieldList.size() == 1) // single bit
+ {
+ sb.append(indent + "if (propertyFlags[" + (ordinal - 1) + "]) // " + comment + CR);
+ sb.append(indent + tab + "size += " +
+ typeMap.get("bit").size.replaceAll("~", "1") + ";" + CR);
+ }
+ else // multiple bits - up to 8 are combined into one byte
+ {
+ String bitCntrName = "bitCntr_" + ordinal;
+ int startOrdinal = ordinal - bitFieldList.size();
+ sb.append(indent + "// " + comment + CR);
+ sb.append(indent + "int " + bitCntrName + " = 0;" + CR);
+ sb.append(indent + "for (int i=" + startOrdinal + "; i<" + ordinal + "; i++)" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "if (propertyFlags[i])" + CR);
+ sb.append(indent + tab + tab + bitCntrName + "++;" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(indent + "size += " +
+ typeMap.get("bit").size.replaceAll("~", bitCntrName +
+ " > 0 ? ((" + bitCntrName + " - 1) / 8) + 1 : 0") + ";" + CR);
+ }
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchFieldEncode(String domainType, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "if (propertyFlags[" + ordinal + "]) // " + fieldName + ": " +
+ domainType + CR);
+ sb.append(indent + Utils.createSpaces(tabSize) +
+ typeMap.get(domainType).encodeExpression.replaceAll("#", fieldName) + ";" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchBitFieldEncode(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ String comment = bitFieldList.size() == 1 ?
+ bitFieldList.get(0) + ": bit" :
+ "Combinded bits: " + bitFieldList;
+ StringBuffer sb = new StringBuffer();
+
+ if (bitFieldList.size() == 1) // single bit
+ {
+ sb.append(indent + "if (propertyFlags[" + (ordinal - 1) + "]) // " +
+ bitFieldList.get(0) + ": bit" + CR);
+ sb.append(indent + tab + typeMap.get("bit").encodeExpression.replaceAll("#",
+ "new boolean[] {" + bitFieldList.get(0) + "}") + ";" + CR);
+ }
+ else // multiple bits - up to 8 are combined into one byte
+ {
+ int startOrdinal = ordinal - bitFieldList.size();
+ String bitCntrName = "bitCntr" + startOrdinal;
+ sb.append(indent + "// " + comment + CR);
+ sb.append(indent + "int " + bitCntrName + " = 0;" + CR);
+ sb.append(indent + "for (int i=" + startOrdinal + "; i<=" + (ordinal - 1) + "; i++)" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "if (propertyFlags[i])" + CR);
+ sb.append(indent + tab + tab + bitCntrName + "++;" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(indent + "if (" + bitCntrName + " > 0) // Are any of the property bits set?" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "boolean[] fullBitArray = new boolean[] { ");
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ if (i != 0)
+ {
+ sb.append(", ");
+ }
+ sb.append(bitFieldList.get(i));
+ }
+ sb.append(" };" + CR);
+ sb.append(indent + tab + "boolean[] flaggedBitArray = new boolean[" + bitCntrName +
+ "];" + CR);
+ sb.append(indent + tab + bitCntrName + " = 0;" + CR);
+ sb.append(indent + tab + "for (int i=" + startOrdinal + "; i<=" + (ordinal - 1) +
+ "; i++)" + CR);
+ sb.append(indent + tab + "{" + CR);
+ sb.append(indent + tab + tab + "if (propertyFlags[i])" + CR);
+ sb.append(indent + tab + tab + tab + "flaggedBitArray[" + bitCntrName +
+ "++] = fullBitArray[i];" + CR);
+ sb.append(indent + tab + "}" + CR);
+ sb.append(indent + tab + typeMap.get("bit").encodeExpression.replaceAll("#",
+ "flaggedBitArray") + ";" + CR);
+ sb.append(indent + "}" + CR);
+ }
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchFieldDecode(String domainType, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ sb.append(indent + "if (propertyFlags[" + ordinal + "]) // " + fieldName + ": " +
+ domainType + CR);
+ sb.append(indent + Utils.createSpaces(tabSize) +
+ typeMap.get(domainType).decodeExpression.replaceAll("#", fieldName) + ";" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchBitFieldDecode(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ String comment = bitFieldList.size() == 1 ?
+ bitFieldList.get(0) + ": bit" :
+ "Combinded bits: " + bitFieldList;
+ StringBuffer sb = new StringBuffer();
+
+ if (bitFieldList.size() == 1) // single bit
+ {
+ sb.append(indent + "if (propertyFlags[" + (ordinal - 1) + "]) // " +
+ bitFieldList.get(0) + ": bit" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + typeMap.get("bit").decodeExpression.replaceAll("#",
+ "boolean[] flaggedBitArray") + ";" + CR);
+ sb.append(indent + tab + bitFieldList.get(0) + " = flaggedBitArray[0];" + CR);
+ sb.append(indent + "}" + CR);
+ }
+ else // multiple bits - up to 8 are combined into one byte
+ {
+ int startOrdinal = ordinal - bitFieldList.size();
+ String bitCntr = "bitCntr" + startOrdinal;
+ sb.append(indent + "// " + comment + CR);
+ sb.append(indent + "int " + bitCntr + " = 0;" + CR);
+ sb.append(indent + "for (int i=" + startOrdinal + "; i<=" + (ordinal - 1) + "; i++)" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + "if (propertyFlags[i])" + CR);
+ sb.append(indent + tab + tab + bitCntr + "++;" + CR);
+ sb.append(indent + "}" + CR);
+ sb.append(indent + "if (" + bitCntr + " > 0) // Are any of the property bits set?" + CR);
+ sb.append(indent + "{" + CR);
+ sb.append(indent + tab + typeMap.get("bit").decodeExpression.replaceAll("#",
+ "boolean[] flaggedBitArray") + ";" + CR);
+ sb.append(indent + tab + bitCntr + " = 0;" + CR);
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ sb.append(indent + tab + "if (propertyFlags[" + (startOrdinal + i) + "])" + CR);
+ sb.append(indent + tab + tab + bitFieldList.get(i) + " = flaggedBitArray[" +
+ bitCntr + "++];" + CR);
+ }
+ sb.append(indent + "}" + CR);
+ }
+
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchGetPropertyFlags(String domainType, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ int word = ordinal / 15;
+ int bit = 15 - (ordinal % 15);
+ sb.append(indent + "if (propertyFlags[" + ordinal + "]) // " + fieldName + ": " +
+ domainType + CR);
+ sb.append(indent + tab + "compactPropertyFlags[" + word + "] |= (1 << " +
+ bit + ");" + CR);
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchBitGetPropertyFlags(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ int startOrdinal = ordinal - bitFieldList.size();
+
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ int thisOrdinal = startOrdinal + i;
+ int word = thisOrdinal / 15;
+ int bit = 15 - (thisOrdinal % 15);
+ sb.append(indent + "if (propertyFlags[" + thisOrdinal + "])" + CR);
+ sb.append(indent + tab + "compactPropertyFlags[" + word +
+ "] |= (1 << " + bit + ");" + CR);
+ }
+
+ sb.append(CR);
+ return sb.toString();
+ }
+
+ protected String generatePchSetPropertyFlags(String domainType, String fieldName,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ int word = ordinal / 15;
+ int bit = 15 - (ordinal % 15);
+ sb.append(indent + "propertyFlags[" + ordinal + "] = (compactPropertyFlags[" +
+ word + "] & (1 << " + bit + ")) > 0;" + CR);
+ return sb.toString();
+ }
+
+ protected String generatePchBitSetPropertyFlags(List<String> bitFieldList,
+ int ordinal, int indentSize, int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ StringBuffer sb = new StringBuffer();
+ int startOrdinal = ordinal - bitFieldList.size();
+
+ for (int i = 0; i < bitFieldList.size(); i++)
+ {
+ int thisOrdinal = startOrdinal + i;
+ int word = thisOrdinal / 15;
+ int bit = 15 - (thisOrdinal % 15);
+ sb.append(indent + "propertyFlags[" + thisOrdinal + "] = (compactPropertyFlags[" +
+ word + "] & (1 << " + bit + ")) > 0;" + CR);
+ }
+ return sb.toString();
+ }
+
+ private String generatePchPropertyFlagsDeclare()
+ {
+ return "private boolean[] propertyFlags;";
+ }
+
+ private String generatePchPropertyFlagsInitializer(int totNumFields)
+ {
+ return "propertyFlags = new boolean[" + totNumFields + "];";
+ }
+
+ private String generatePchCompactPropertyFlagsInitializer(AmqpClass thisClass, int indentSize,
+ int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ Iterator<AmqpVersion> vItr = thisClass.getVersionSet().iterator();
+ while (vItr.hasNext())
+ {
+ AmqpVersion version = vItr.next();
+ int numBytes = ((thisClass.getFieldMap().getNumFields(version) - 1) / 15) + 1;
+
+ sb.append(indent);
+ if (!version.equals(thisClass.getVersionSet().first()))
+ {
+ sb.append("else ");
+ }
+ sb.append("if ( major == " + version.getMajor() + " && minor == " +
+ version.getMinor() + " )" + CR);
+ sb.append(indent + tab + "compactPropertyFlags = new int[] { ");
+ for (int i = 0; i < numBytes; i++)
+ {
+ if (i != 0)
+ {
+ sb.append(", ");
+ }
+ sb.append(i < numBytes - 1 ? "1" : "0"); // Set the "continue" flag where required
+ }
+ sb.append(" };" + CR);
+ }
+ return sb.toString();
+ }
+
+ private String generatePchCompactPropertyFlagsCheck(AmqpClass thisClass, int indentSize,
+ int tabSize)
+ {
+ String indent = Utils.createSpaces(indentSize);
+ String tab = Utils.createSpaces(tabSize);
+ StringBuffer sb = new StringBuffer();
+ Iterator<AmqpVersion> vItr = thisClass.getVersionSet().iterator();
+ while (vItr.hasNext())
+ {
+ AmqpVersion version = vItr.next();
+ int numFields = thisClass.getFieldMap().getNumFields(version);
+ int numBytes = ((numFields - 1) / 15) + 1;
+
+ sb.append(indent);
+ if (!version.equals(thisClass.getVersionSet().first()))
+ {
+ sb.append("else ");
+ }
+ sb.append("if ( major == " + version.getMajor() + " && minor == " +
+ version.getMinor() + " && compactPropertyFlags.length != " + numBytes + " )" + CR);
+ sb.append(indent + tab +
+ "throw new AMQProtocolVersionException(\"Property flag array size mismatch:\" +" + CR);
+ sb.append(indent + tab + tab + "\"(Size found: \" + compactPropertyFlags.length +" + CR);
+ sb.append(indent + tab + tab + "\") Version " + version + " has " + numFields +
+ " fields which requires an int array of size " + numBytes + ".\");" + CR);
+ }
+ return sb.toString();
+ }
+
+ private String generateVersionCheck(AmqpVersionSet v)
+ {
+ StringBuffer sb = new StringBuffer();
+ AmqpVersion[] versionArray = new AmqpVersion[v.size()];
+ v.toArray(versionArray);
+ for (int i = 0; i < versionArray.length; i++)
+ {
+ if (i != 0)
+ {
+ sb.append(" || ");
+ }
+ if (versionArray.length > 1)
+ {
+ sb.append("(");
+ }
+ sb.append("major == (byte)" + versionArray[i].getMajor() + " && minor == (byte)" +
+ versionArray[i].getMinor());
+ if (versionArray.length > 1)
+ {
+ sb.append(")");
+ }
+ }
+ return sb.toString();
+ }
+
+ private String camelCaseName(String name, boolean upperFirstFlag)
+ {
+ StringBuffer ccn = new StringBuffer();
+ String[] toks = name.split("[-_.\\ ]");
+ for (int i = 0; i < toks.length; i++)
+ {
+ StringBuffer b = new StringBuffer(toks[i]);
+ if (upperFirstFlag || i > 0)
+ {
+ b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0)));
+ }
+ ccn.append(b);
+ }
+ return ccn.toString();
+ }
+
+
+ private String upperCaseName(String name)
+ {
+ StringBuffer ccn = new StringBuffer();
+ String[] toks = name.split("[-_.\\ ]");
+ for (int i = 0; i < toks.length; i++)
+ {
+ if (i != 0)
+ {
+ ccn.append('_');
+ }
+ ccn.append(toks[i].toUpperCase());
+
+
+ }
+ return ccn.toString();
+ }
+
+
+ public static Factory<JavaGenerator> _factoryInstance = new Factory<JavaGenerator>()
+ {
+
+ public JavaGenerator newInstance()
+ {
+ return new JavaGenerator();
+ }
+ };
+
+ public static Factory<JavaGenerator> getFactory()
+ {
+ return _factoryInstance;
+ }
+
+
+ void processModelTemplate(NamedTemplate template, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ void processClassTemplate(NamedTemplate template, AmqpClass amqpClass, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ void processMethodTemplate(NamedTemplate template, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ void processFieldTemplate(NamedTemplate template, AmqpClass amqpClass, AmqpMethod amqpMethod, AmqpField amqpField, AmqpVersion version)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/LanguageConverter.java b/java/common/gentools/src/org/apache/qpid/gentools/LanguageConverter.java
new file mode 100644
index 0000000000..5e692d86e7
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/LanguageConverter.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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;
+
+public interface LanguageConverter
+{
+
+// public AmqpDomainMap getDomainMap();
+// public AmqpConstantSet getConstantSet();
+// public AmqpModel getModel();
+
+ //
+ public String prepareClassName(String className);
+
+ public String prepareMethodName(String methodName);
+
+ public String prepareDomainName(String domainName);
+
+ public String getDomainType(String domainName, AmqpVersion version);
+
+ public String getGeneratedType(String domainName, AmqpVersion version);
+
+ public String prepareConstantName(String constantName);
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/Main.java b/java/common/gentools/src/org/apache/qpid/gentools/Main.java
new file mode 100644
index 0000000000..c0584f7ca7
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/Main.java
@@ -0,0 +1,301 @@
+/*
+ *
+ * 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.app.Velocity;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Properties;
+
+public class Main
+{
+ private static final String DEFAULT_OUTPUT_DIR = ".." + Utils.FILE_SEPARATOR + "gen";
+ private static final String DEFAULT_TEMPLATE_DIR_BASE = ".." + Utils.FILE_SEPARATOR;
+
+ private enum GeneratedLanguage
+ {
+ CPP(".cpp", CppGenerator.getFactory()),
+ DOTNET(".net", DotnetGenerator.getFactory()),
+ JAVA(".java", JavaGenerator.getFactory());
+
+ private final String _suffix;
+ private final Generator.Factory _factory;
+
+
+ private final String _defaultTemplateDirectory;
+
+ GeneratedLanguage(String suffix, Generator.Factory factory)
+ {
+ _suffix = suffix;
+ _factory = factory;
+ _defaultTemplateDirectory = DEFAULT_TEMPLATE_DIR_BASE + "templ" + _suffix;
+ }
+
+ public String getSuffix()
+ {
+ return _suffix;
+ }
+
+ public Generator newGenerator()
+ {
+ return _factory.newInstance();
+ }
+
+ public String getDefaultTemplateDirectory()
+ {
+ return _defaultTemplateDirectory;
+ }
+ }
+
+ private Generator generator;
+
+ private String outDir;
+ private String tmplDir;
+ private GeneratedLanguage _generatorLang;
+ private ArrayList<String> xmlFiles;
+
+ public Main()
+ {
+ xmlFiles = new ArrayList<String>();
+ }
+
+ public void run(String[] args)
+ throws Exception,
+ SAXException,
+ AmqpParseException,
+ AmqpTypeMappingException,
+ AmqpTemplateException,
+ TargetDirectoryException,
+ IllegalAccessException,
+ InvocationTargetException, ParserConfigurationException
+ {
+
+ // 0. Initialize
+ outDir = DEFAULT_OUTPUT_DIR;
+ tmplDir = null;
+ _generatorLang = GeneratedLanguage.CPP; // Default generation language
+ xmlFiles.clear();
+ processArgs(args);
+
+ if (tmplDir == null)
+ {
+ tmplDir = _generatorLang.getDefaultTemplateDirectory();
+ }
+
+
+ generator = _generatorLang.newGenerator();
+ generator.setTemplateDirectory(tmplDir);
+ generator.setOutputDirectory(outDir);
+
+ // 1. Suck in all the XML spec files provided on the command line
+ analyzeXML();
+
+ Properties p = new Properties();
+ p.setProperty("file.resource.loader.path", tmplDir);
+
+ Velocity.init(p);
+
+ // 2. Load up all templates
+ generator.initializeTemplates();
+
+ // 3. Generate output
+ generator.generate();
+
+ System.out.println("Files generated: " + generator.getNumberGeneratedFiles());
+ System.out.println("Done.");
+ }
+
+ private void processArgs(String[] args)
+ {
+ // Crude but simple...
+ for (int i = 0; i < args.length; i++)
+ {
+ String arg = args[i];
+ if (arg.charAt(0) == '-')
+ {
+ switch (arg.charAt(1))
+ {
+ case'c':
+ case'C':
+ _generatorLang = GeneratedLanguage.CPP;
+ break;
+ case'j':
+ case'J':
+ _generatorLang = GeneratedLanguage.JAVA;
+ break;
+ case'n':
+ case'N':
+ _generatorLang = GeneratedLanguage.DOTNET;
+ break;
+ case'o':
+ case'O':
+ if (++i < args.length)
+ {
+ outDir = args[i];
+ }
+ break;
+ case't':
+ case'T':
+ if (++i < args.length)
+ {
+ tmplDir = args[i];
+ }
+ break;
+ }
+ }
+ else
+ {
+ xmlFiles.add(args[i]);
+ }
+ }
+ }
+
+ private void analyzeXML()
+ throws IOException, SAXException, AmqpParseException, AmqpTypeMappingException, ParserConfigurationException
+ {
+ DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+
+ System.out.println("XML files: " + xmlFiles);
+ for (String filename : xmlFiles)
+ {
+ File f = new File(filename);
+ if (f.exists())
+ {
+ // 1a. Initialize dom
+ System.out.print(" \"" + filename + "\":");
+ Document doc = docBuilder.parse(new File(filename));
+ Node amqpNode = Utils.findChild(doc, Utils.ELEMENT_AMQP);
+
+ // 1b. Extract version (major and minor) from the XML file
+ int major = Utils.getNamedIntegerAttribute(amqpNode, Utils.ATTRIBUTE_MAJOR);
+ int minor = Utils.getNamedIntegerAttribute(amqpNode, Utils.ATTRIBUTE_MINOR);
+ AmqpVersion version = new AmqpVersion(major, minor);
+ System.out.println(" Found version " + version.toString() + ".");
+ generator.addVersion(version);
+ generator.addFromNode(amqpNode, version);
+
+
+ }
+ else
+ {
+ System.err.println("ERROR: AMQP XML file \"" + filename + "\" not found.");
+ }
+ }
+// *** DEBUG INFO *** Uncomment bits from this block to see lots of stuff....
+// System.out.println();
+// System.out.println("*** Debug output ***");
+// System.out.println();
+// versionSet.print(System.out, 0, 2); // List of loaded versions
+// System.out.println();
+// constants.print(System.out, 0, 2); // List of constants
+// System.out.println();
+// domainMap.print(System.out, 0, 2); // List of domains
+// System.out.println();
+// model.print(System.out, 0, 2); // Internal version map model
+// System.out.println();
+// System.out.println("*** End debug output ***");
+// System.out.println();
+ }
+
+ public static void main(String[] args)
+ {
+ int exitCode = 1;
+ // TODO: This is a simple and klunky way of hangling command-line args, and could be improved upon.
+ if (args.length < 2)
+ {
+ usage();
+ }
+ else
+ {
+ try
+ {
+ new Main().run(args);
+ exitCode = 0;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ catch (ParserConfigurationException e)
+ {
+ e.printStackTrace();
+ }
+ catch (SAXException e)
+ {
+ e.printStackTrace();
+ }
+ catch (AmqpParseException e)
+ {
+ e.printStackTrace();
+ }
+ catch (AmqpTypeMappingException e)
+ {
+ e.printStackTrace();
+ }
+ catch (AmqpTemplateException e)
+ {
+ e.printStackTrace();
+ }
+ catch (TargetDirectoryException e)
+ {
+ e.printStackTrace();
+ }
+ catch (IllegalAccessException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InvocationTargetException e)
+ {
+ e.printStackTrace();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ System.exit(exitCode);
+ }
+
+ public static void usage()
+ {
+ System.out.println("AMQP XML generator v.0.0");
+ System.out.println("Usage: Main -c|-j [-o outDir] [-t tmplDir] XMLfile [XMLfile ...]");
+ System.out.println(" where -c: Generate C++.");
+ System.out.println(" -j: Generate Java.");
+ System.out.println(" -n: Generate .NET.");
+ System.out.println(" -o outDir: Use outDir as the output dir (default=\"" + DEFAULT_OUTPUT_DIR + "\").");
+ System.out.println(" -t tmplDir: Find templates in tmplDir.");
+ System.out.println(" Defaults: \"" + GeneratedLanguage.CPP.getDefaultTemplateDirectory() + "\" for C++;");
+ System.out.println(" \"" + GeneratedLanguage.JAVA.getDefaultTemplateDirectory() + "\" for java.;");
+ System.out.println(" \"" + GeneratedLanguage.DOTNET.getDefaultTemplateDirectory() + "\" for .NET.");
+ System.out.println(" XMLfile is a space-separated list of AMQP XML files to be parsed.");
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/MangledGenerateMethod.java b/java/common/gentools/src/org/apache/qpid/gentools/MangledGenerateMethod.java
new file mode 100644
index 0000000000..ffeefed900
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/MangledGenerateMethod.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * 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;
+
+public interface MangledGenerateMethod
+{
+ String generate(AmqpField field, int indentSize, int tabSize, boolean notLast);
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/NodeAware.java b/java/common/gentools/src/org/apache/qpid/gentools/NodeAware.java
new file mode 100644
index 0000000000..f832da75ad
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/NodeAware.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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.w3c.dom.Node;
+
+/**
+ * @author kpvdr
+ * Interface allowing the addition of elements from a node in the
+ * DOM of the AMQP specification. It is used by each of the model
+ * elements in a recursive fashion to build the model.
+ */
+public interface NodeAware
+{
+ /**
+ * Add a model element from the current DOM node. All model elements must implement
+ * this interface. If the node contains children that are also a part of the model,
+ * then this method is called on new instances of those model elements.
+ *
+ * @param n Node from which the current model element is to be added.
+ * @param o Ordinal value of the current model elemet.
+ * @param v Verion of the DOM from which the node comes.
+ * @throws AmqpParseException
+ * @throws AmqpTypeMappingException
+ * @returns true if a node was added, false if not
+ */
+ public boolean addFromNode(Node n, int o, AmqpVersion v)
+ throws AmqpParseException, AmqpTypeMappingException;
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/Printable.java b/java/common/gentools/src/org/apache/qpid/gentools/Printable.java
new file mode 100644
index 0000000000..aa13df7b68
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/Printable.java
@@ -0,0 +1,28 @@
+/*
+ *
+ * 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.PrintStream;
+
+public interface Printable
+{
+ public void print(PrintStream out, int marginSize, int tabSize);
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionClass.java b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionClass.java
new file mode 100644
index 0000000000..8e1af1c551
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionClass.java
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Map.Entry;
+
+
+public class SingleVersionClass
+{
+ private final int _classId;
+
+
+ private final AmqpClass _amqpClass;
+ private final AmqpVersion _amqpVersion;
+ private final Generator _generator;
+ private final List<SingleVersionMethod> _methodList = new ArrayList<SingleVersionMethod>();
+
+ public SingleVersionClass(AmqpClass amqpClass, AmqpVersion amqpVersion, Generator generator)
+ {
+ _amqpClass = amqpClass;
+ _amqpVersion = amqpVersion;
+ _generator = generator;
+
+ AmqpOrdinalVersionMap indexMap = amqpClass.getIndexMap();
+ int classId = 0;
+ for(Entry<Integer, AmqpVersionSet> entry : indexMap.entrySet())
+ {
+ if(entry.getValue().contains(_amqpVersion))
+ {
+ classId = entry.getKey();
+ break;
+ }
+ }
+ _classId = classId;
+
+
+ Collection<AmqpMethod> methods = _amqpClass.getMethodMap().values();
+
+ for(AmqpMethod amqpMethod : methods)
+ {
+ _methodList.add(new SingleVersionMethod(amqpMethod, _amqpVersion, _generator));
+
+ }
+
+ Collections.sort(_methodList, new Comparator<SingleVersionMethod>(){
+ public int compare(SingleVersionMethod method1, SingleVersionMethod method2)
+ {
+ return method1.getMethodId() - method2.getMethodId();
+ }
+ });
+
+
+ }
+
+ public int getClassId()
+ {
+ return _classId;
+ }
+
+ public String getName()
+ {
+ return _amqpClass.getName();
+ }
+
+
+
+
+
+ public List<SingleVersionMethod> getMethodList()
+ {
+ return _methodList;
+ }
+
+
+ public int getMaximumMethodId()
+ {
+ return _methodList.get(_methodList.size()-1).getMethodId();
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionField.java b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionField.java
new file mode 100644
index 0000000000..b795663d15
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionField.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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;
+
+
+public class SingleVersionField
+{
+ private final AmqpField _field;
+ private final AmqpVersion _amqpVersion;
+ private final Generator _generator;
+
+ public SingleVersionField(AmqpField field, AmqpVersion amqpVersion, Generator generator)
+ {
+ _field = field;
+ _amqpVersion = amqpVersion;
+ _generator = generator;
+ }
+
+ public String getName()
+ {
+ return _field.getName();
+ }
+
+ public String getDomain()
+ {
+ return _field.getDomain(_amqpVersion);
+ }
+
+
+ public String getDomainType()
+ {
+ return _generator.getDomainType(_field.getDomain(_amqpVersion),_amqpVersion);
+ }
+
+ public String getNativeType()
+ {
+ return _generator.getNativeType(getDomainType());
+ }
+
+ public String getEncodingType()
+ {
+ return _generator.getEncodingType(getDomainType());
+ }
+
+
+ public int getPosition()
+ {
+ return _field.getOrdinal(_amqpVersion);
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java
new file mode 100644
index 0000000000..59a6d9e28a
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionMethod.java
@@ -0,0 +1,154 @@
+/*
+ *
+ * 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.util.Map.Entry;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+public class SingleVersionMethod
+{
+ private final AmqpMethod _amqpMethod;
+ private final AmqpVersion _amqpVersion;
+ private final int _methodId;
+ private final List<SingleVersionField> _fieldList = new ArrayList<SingleVersionField>();
+ private final Generator _generator;
+ private final List<ConsolidatedField> _consolidatedFields = new ArrayList<ConsolidatedField>();
+ private final Map<String, ConsolidatedField> _fieldNameToConsolidatedFieldMap = new HashMap<String, ConsolidatedField>();
+
+
+ public SingleVersionMethod(AmqpMethod amqpMethod, AmqpVersion amqpVersion, Generator generator)
+ {
+ _amqpMethod = amqpMethod;
+ _amqpVersion = amqpVersion;
+ _generator = generator;
+
+ AmqpOrdinalVersionMap indexMap = amqpMethod.getIndexMap();
+ int methodId = 0;
+ for(Entry<Integer, AmqpVersionSet> entry : indexMap.entrySet())
+ {
+ if(entry.getValue().contains(_amqpVersion))
+ {
+ methodId = entry.getKey();
+ break;
+ }
+ }
+ _methodId = methodId;
+
+ Collection<AmqpField> fields = _amqpMethod.getFieldMap().values();
+
+ for(AmqpField field : fields)
+ {
+ _fieldList.add(new SingleVersionField(field, _amqpVersion, _generator));
+
+ }
+
+ Collections.sort(_fieldList, new Comparator<SingleVersionField>(){
+ public int compare(SingleVersionField field1, SingleVersionField field2)
+ {
+ return field1.getPosition() - field2.getPosition();
+ }
+ });
+
+
+
+ ConsolidatedField lastField = null;
+ int bitfieldNum = 0;
+ for(SingleVersionField field : _fieldList)
+ {
+ String domainType = field.getDomainType();
+ if(!domainType.equals("bit"))
+ {
+ lastField = new ConsolidatedField(_generator,
+ field.getName(),
+ field.getDomainType());
+ _consolidatedFields.add(lastField);
+ }
+ else if(lastField == null || !lastField.getType().equals("bitfield"))
+ {
+ lastField = new ConsolidatedField(_generator,
+ domainType.equals("bit") ? "bitfield"+bitfieldNum++ : field.getName(),
+ domainType.equals("bit") ? "bitfield" : field.getDomainType(),
+ field.getName());
+ _consolidatedFields.add(lastField);
+ }
+ else
+ {
+ lastField.add(field.getName());
+ }
+ _fieldNameToConsolidatedFieldMap.put(field.getName(), lastField);
+
+ }
+ }
+
+ public int getMethodId()
+ {
+ return _methodId;
+ }
+
+ public String getName()
+ {
+ return _amqpMethod.getName();
+ }
+
+ public Collection<SingleVersionField> getFieldList()
+ {
+ return Collections.unmodifiableCollection(_fieldList);
+ }
+
+ public List<ConsolidatedField> getConsolidatedFields()
+ {
+ return _consolidatedFields;
+ }
+
+ public String getConsolidatedFieldName(String fieldName)
+ {
+ return _fieldNameToConsolidatedFieldMap.get(fieldName).getName();
+ }
+
+ public boolean isConsolidated(String fieldName)
+ {
+ return _fieldNameToConsolidatedFieldMap.get(fieldName).isConsolidated();
+ }
+
+ public int getPositionInBitField(String fieldName)
+ {
+ return _fieldNameToConsolidatedFieldMap.get(fieldName).getPosition(fieldName);
+ }
+
+
+ public boolean isServerMethod()
+ {
+ return _amqpMethod.isServerMethod(_amqpVersion);
+ }
+
+
+ public boolean isClientMethod()
+ {
+ return _amqpMethod.isClientMethod(_amqpVersion);
+ }
+
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionModel.java b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionModel.java
new file mode 100644
index 0000000000..22b416e45a
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/SingleVersionModel.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+
+public class SingleVersionModel
+{
+ private final AmqpModel _amqpModel;
+ private final AmqpVersion _amqpVersion;
+ private final Generator _generator;
+ private final List<SingleVersionClass> _classList = new ArrayList<SingleVersionClass>();
+
+ public SingleVersionModel(AmqpModel amqpModel, AmqpVersion amqpVersion, Generator generator)
+ {
+ _amqpModel = amqpModel;
+ _amqpVersion = amqpVersion;
+ _generator = generator;
+
+
+ Collection<AmqpClass> originalClasses = _amqpModel.getClassMap().values();
+
+ for(AmqpClass amqpClass : originalClasses)
+ {
+ _classList.add(new SingleVersionClass(amqpClass, _amqpVersion, _generator));
+
+ }
+
+ Collections.sort(_classList, new Comparator<SingleVersionClass>(){
+ public int compare(SingleVersionClass amqpClass1, SingleVersionClass amqpClass2)
+ {
+ return amqpClass1.getClassId() - amqpClass2.getClassId();
+ }
+ });
+
+
+ }
+
+ public Collection<SingleVersionClass> getClassList()
+ {
+ return Collections.unmodifiableCollection(_classList);
+ }
+
+ public int getMaximumClassId()
+ {
+ return _classList.get(_classList.size()-1).getClassId();
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java b/java/common/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java
new file mode 100644
index 0000000000..39ce666288
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/TargetDirectoryException.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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;
+
+@SuppressWarnings("serial")
+public class TargetDirectoryException extends RuntimeException
+{
+ public TargetDirectoryException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/Utils.java b/java/common/gentools/src/org/apache/qpid/gentools/Utils.java
new file mode 100644
index 0000000000..1cedaeea12
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/Utils.java
@@ -0,0 +1,159 @@
+/*
+ *
+ * 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.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class Utils
+{
+ public final static String FILE_SEPARATOR = System.getProperty("file.separator");
+ public final static String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ public final static String ATTRIBUTE_NAME = "name";
+ public final static String ATTRIBUTE_MAJOR = "major";
+ public final static String ATTRIBUTE_MINOR = "minor";
+ public final static String ATTRIBUTE_INDEX = "index";
+ public final static String ATTRIBUTE_LABEL = "label";
+ public final static String ATTRIBUTE_SYNCHRONOUS = "synchronous";
+ public final static String ATTRIBUTE_CONTENT = "content";
+ public final static String ATTRIBUTE_HANDLER = "handler";
+ public final static String ATTRIBUTE_DOMAIN = "domain";
+ public final static String ATTRIBUTE_VALUE = "value";
+ public final static String ATTRIBUTE_TYPE = "type"; // For compatibility with AMQP 8.0
+
+ public final static String ELEMENT_AMQP = "amqp";
+ public final static String ELEMENT_CHASSIS = "chassis";
+ public final static String ELEMENT_CLASS = "class";
+ public final static String ELEMENT_CODEGEN = "codegen";
+ public final static String ELEMENT_CONSTANT = "constant";
+ public final static String ELEMENT_DOMAIN = "domain";
+ public final static String ELEMENT_METHOD = "method";
+ public final static String ELEMENT_FIELD = "field";
+ public final static String ELEMENT_VERSION = "version";
+
+ // Attribute functions
+
+ public static String getNamedAttribute(Node n, String attrName) throws AmqpParseException
+ {
+ NamedNodeMap nnm = n.getAttributes();
+ if (nnm == null)
+ {
+ throw new AmqpParseException("Node \"" + n.getNodeName() + "\" has no attributes.");
+ }
+ Attr a = (Attr) nnm.getNamedItem(attrName);
+ if (a == null)
+ {
+ throw new AmqpParseException("Node \"" + n.getNodeName() + "\" has no attribute \"" + attrName + "\".");
+ }
+ return a.getNodeValue();
+ }
+
+ public static int getNamedIntegerAttribute(Node n, String attrName) throws AmqpParseException
+ {
+ return Integer.parseInt(getNamedAttribute(n, attrName));
+ }
+
+ // Element functions
+
+ public static Node findChild(Node n, String eltName) throws AmqpParseException
+ {
+ NodeList nl = n.getChildNodes();
+ for (int i = 0; i < nl.getLength(); i++)
+ {
+ Node cn = nl.item(i);
+ if (cn.getNodeName().compareTo(eltName) == 0)
+ {
+ return cn;
+ }
+ }
+ throw new AmqpParseException("Node \"" + n.getNodeName() +
+ "\" does not contain child element \"" + eltName + "\".");
+ }
+
+ // String functions
+
+ public static String firstUpper(String str)
+ {
+ if (!Character.isLetter(str.charAt(0)) || !Character.isLowerCase(str.charAt(0)))
+ {
+ return str;
+ }
+ StringBuffer sb = new StringBuffer(str);
+ sb.setCharAt(0, Character.toUpperCase(str.charAt(0)));
+ return sb.toString();
+ }
+
+ public static String firstLower(String str)
+ {
+ if (!Character.isUpperCase(str.charAt(0)))
+ {
+ return str;
+ }
+ StringBuffer sb = new StringBuffer(str);
+ sb.setCharAt(0, Character.toLowerCase(str.charAt(0)));
+ return sb.toString();
+ }
+
+ public static String createSpaces(int cnt)
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < cnt; i++)
+ {
+ sb.append(' ');
+ }
+ return sb.toString();
+ }
+
+ public static boolean containsOnlyDigits(String str)
+ {
+ boolean foundNonDigit = false;
+ for (int i = 0; i < str.length() && !foundNonDigit; i++)
+ {
+ if (!Character.isDigit(str.charAt(i)))
+ {
+ foundNonDigit = true;
+ }
+ }
+ return !foundNonDigit;
+ }
+
+ public static boolean containsOnlyDigitsAndDecimal(String str)
+ {
+ boolean foundNonDigit = false;
+ int decimalCntr = 0;
+ for (int i = 0; i < str.length() && !foundNonDigit && decimalCntr < 2; i++)
+ {
+ char ch = str.charAt(i);
+ if (!(Character.isDigit(ch) || ch == '.'))
+ {
+ foundNonDigit = true;
+ }
+ else if (ch == '.')
+ {
+ decimalCntr++;
+ }
+ }
+ return !foundNonDigit && decimalCntr < 2;
+ }
+}
diff --git a/java/common/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java b/java/common/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java
new file mode 100644
index 0000000000..a9cdd56e88
--- /dev/null
+++ b/java/common/gentools/src/org/apache/qpid/gentools/VersionConsistencyCheck.java
@@ -0,0 +1,26 @@
+/*
+ *
+ * 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;
+
+public interface VersionConsistencyCheck
+{
+ public boolean isVersionConsistent(AmqpVersionSet globalVersionSet);
+}
diff --git a/java/common/protocol-version.xml b/java/common/protocol-version.xml
deleted file mode 100644
index 5435a0a582..0000000000
--- a/java/common/protocol-version.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<!--
- -
- - 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.
- -
- -->
-<project name="Qpid Common Protocol Versions" default="generate">
- <property name="topDirectoryLocation" location=".." />
- <property name="project.build.directory" location="target" />
- <property name="gentools.home" location="${topDirectoryLocation}/../gentools" />
- <property name="generated.path" location="${project.build.directory}/generated-sources/gentools" />
- <property name="generated.package" value="org/apache/qpid/framing" />
- <property name="generated.dir" location="${generated.path}/${generated.package}" />
- <property name="generated.timestamp" location="${generated.dir}/timestamp" />
- <property name="xml.spec.dir" location="${topDirectoryLocation}/../specs" />
- <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml amqp0-9-1.stripped.xml" />
- <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml ${xml.spec.dir}/amqp0-9-1.stripped.xml" />
- <property name="template.dir" value="${topDirectoryLocation}/common/templates" />
-
-
- <!--<target name="generate" depends="compile_generator,check_generate_deps" unless="generation.notRequired">-->
- <target name="generate" depends="compile_generator" unless="generation.notRequired">
- <mkdir dir="${generated.dir}"/>
- <java classname="org.apache.qpid.gentools.Main" fork="true" dir="${gentools.home}/src" failonerror="true">
- <arg line="-j -o ${generated.dir} -t ${template.dir} ${xml.spec.list}" />
- <classpath>
- <pathelement path="${gentools.home}/src" />
- <fileset dir="${gentools.home}/lib">
- <include name="**/*.jar"/>
- </fileset>
- <pathelement path="${gentools.home}/lib/velocity-1.4.jar" />
- <pathelement path="${gentools.home}/lib/velocity-dep-1.4.jar" />
- </classpath>
- </java>
- <touch file="${generated.timestamp}" />
- </target>
-
- <target name="check_generate_deps">
- <uptodate property="generation.notRequired" targetfile="${generated.timestamp}">
- <srcfiles dir="${xml.spec.dir}" includes="${xml.spec.deps}" />
- <srcfiles dir="${template.dir}" includes="**/*.vm **/*.tmpl" />
- </uptodate>
- </target>
-
- <target name="compile_generator">
- <ant dir="${gentools.home}" />
- </target>
-
- <target name="precompile" depends="generate"/>
-
- <target name="clean">
- <delete dir="${generated.path}" />
- </target>
-
-</project>
-
diff --git a/java/common/src/main/java/common.bnd b/java/common/src/main/java/common.bnd
index b34f8deacc..84350fdc75 100755
--- a/java/common/src/main/java/common.bnd
+++ b/java/common/src/main/java/common.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.19.0
+ver: 0.21.0
Bundle-SymbolicName: qpid-common
Bundle-Version: ${ver}
diff --git a/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java b/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
index 5268ce9bc2..7aa280ce02 100644
--- a/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
@@ -87,6 +87,8 @@ public class ClientProperties
public static final String USE_LEGACY_MAP_MESSAGE_FORMAT = "qpid.use_legacy_map_message";
+ public static final String USE_LEGACY_STREAM_MESSAGE_FORMAT = "qpid.use_legacy_stream_message";
+
public static final String AMQP_VERSION = "qpid.amqp.version";
public static final String QPID_VERIFY_CLIENT_ID = "qpid.verify_client_id";
@@ -190,6 +192,19 @@ public class ClientProperties
*/
public static final long DEFAULT_FLOW_CONTROL_WAIT_NOTIFY_PERIOD = 5000L;
+ /**
+ * System property to control whether the client will declare queues during
+ * consumer creation when using BindingURLs.
+ */
+ public static final String QPID_DECLARE_QUEUES_PROP_NAME = "qpid.declare_queues";
+
+ /**
+ * System property to control whether the client will declare exchanges during
+ * producer/consumer creation when using BindingURLs.
+ */
+ public static final String QPID_DECLARE_EXCHANGES_PROP_NAME = "qpid.declare_exchanges";
+ public static final String VERIFY_QUEUE_ON_SEND = "qpid.verify_queue_on_send";
+
private ClientProperties()
{
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
index fdc71e31f9..1381390640 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
@@ -110,7 +110,7 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
{
return new LinkedHashMap<AMQShortString, AMQShortString>()
{
-
+ @Override
protected boolean removeEldestEntry(Map.Entry<AMQShortString, AMQShortString> eldest)
{
return size() > LOCAL_INTERN_CACHE_SIZE;
@@ -845,22 +845,15 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
return internString;
}
-
- public static void main(String args[])
+ public static String toString(AMQShortString amqShortString)
{
- AMQShortString s = new AMQShortString("a.b.c.d.e.f.g.h.i.j.k");
- AMQShortString s2 = s.substring(2, 7);
-
- AMQShortStringTokenizer t = s2.tokenize((byte) '.');
- while(t.hasMoreTokens())
- {
- System.err.println(t.nextToken());
- }
+ return amqShortString == null ? null : amqShortString.asString();
}
- public static String toString(AMQShortString amqShortString)
+ public static void clearLocalCache()
{
- return amqShortString == null ? null : amqShortString.asString();
+ _localInternMap.remove();
+ _localStringMap.remove();
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index 57f2c638a2..b9ed1b2154 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -855,6 +855,7 @@ public class FieldTable
public void addAll(FieldTable fieldTable)
{
initMapIfNecessary();
+ fieldTable.initMapIfNecessary();
if (fieldTable._properties != null)
{
_encodedForm = null;
diff --git a/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java b/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java
index 15c144b0eb..59a1b6c5b0 100644
--- a/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java
@@ -49,7 +49,11 @@ public class ConnectionStartProperties
public static final String SESSION_FLOW = "qpid.session_flow";
- public static int getPID()
+ public static int _pid;
+
+ public static final String _platformInfo;
+
+ static
{
RuntimeMXBean rtb = ManagementFactory.getRuntimeMXBean();
String processName = rtb.getName();
@@ -57,23 +61,20 @@ public class ConnectionStartProperties
{
try
{
- return Integer.parseInt(processName.substring(0,processName.indexOf('@')));
+ _pid = Integer.parseInt(processName.substring(0,processName.indexOf('@')));
}
catch(Exception e)
{
LOGGER.warn("Unable to get the PID due to error",e);
- return -1;
+ _pid = -1;
}
}
else
{
LOGGER.warn("Unable to get the PID due to unsupported format : " + processName);
- return -1;
+ _pid = -1;
}
- }
- public static String getPlatformInfo()
- {
StringBuilder fullSystemInfo = new StringBuilder(System.getProperty("java.runtime.name"));
fullSystemInfo.append(", ");
fullSystemInfo.append(System.getProperty("java.runtime.version"));
@@ -88,6 +89,16 @@ public class ConnectionStartProperties
fullSystemInfo.append(", ");
fullSystemInfo.append(System.getProperty("sun.os.patch.level"));
- return fullSystemInfo.toString();
+ _platformInfo = fullSystemInfo.toString();
+ }
+
+ public static int getPID()
+ {
+ return _pid;
+ }
+
+ public static String getPlatformInfo()
+ {
+ return _platformInfo;
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
index 7ca588946b..6774d0a45a 100644
--- a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
@@ -23,6 +23,7 @@ package org.apache.qpid.protocol;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.network.NetworkConnection;
+import org.apache.qpid.transport.network.TransportActivity;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
@@ -31,7 +32,7 @@ import java.nio.ByteBuffer;
* A ProtocolEngine is a Receiver for java.nio.ByteBuffers. It takes the data passed to it in the received
* decodes it and then process the result.
*/
-public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer>
+public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer>, TransportActivity
{
// Returns the remote address of the NetworkDriver
SocketAddress getRemoteAddress();
@@ -56,6 +57,6 @@ public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer>
void readerIdle();
- public void setNetworkConnection(NetworkConnection network, Sender<ByteBuffer> sender);
+ public void setNetworkConnection(NetworkConnection network, Sender<ByteBuffer> sender);
} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index e87851cf7d..cdca726148 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -21,12 +21,7 @@
package org.apache.qpid.transport;
import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.transport.network.Assembler;
-import org.apache.qpid.transport.network.Disassembler;
-import org.apache.qpid.transport.network.InputHandler;
-import org.apache.qpid.transport.network.NetworkConnection;
-import org.apache.qpid.transport.network.OutgoingNetworkTransport;
-import org.apache.qpid.transport.network.Transport;
+import org.apache.qpid.transport.network.*;
import org.apache.qpid.transport.network.security.SecurityLayer;
import org.apache.qpid.transport.network.security.SecurityLayerFactory;
import org.apache.qpid.transport.util.Logger;
@@ -73,6 +68,8 @@ public class Connection extends ConnectionInvoker
//Usable channels are numbered 0 to <ChannelMax> - 1
public static final int MAX_CHANNEL_MAX = 0xFFFF;
public static final int MIN_USABLE_CHANNEL_NUM = 0;
+ private long _lastSendTime;
+ private long _lastReadTime;
public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD, RESUMING }
@@ -89,15 +86,15 @@ public class Connection extends ConnectionInvoker
public static interface SessionFactory
{
- Session newSession(Connection conn, Binary name, long expiry);
+ Session newSession(Connection conn, Binary name, long expiry, boolean isNoReplay);
}
private static final class DefaultSessionFactory implements SessionFactory
{
- public Session newSession(final Connection conn, final Binary name, final long expiry)
+ public Session newSession(final Connection conn, final Binary name, final long expiry, final boolean isNoReplay)
{
- return new Session(conn, name, expiry);
+ return new Session(conn, name, expiry, isNoReplay);
}
}
@@ -232,9 +229,10 @@ public class Connection extends ConnectionInvoker
addConnectionListener((ConnectionListener)secureReceiver);
}
- NetworkConnection network = transport.connect(settings, secureReceiver, null);
- _remoteAddress = network.getRemoteAddress();
- _localAddress = network.getLocalAddress();
+ NetworkConnection network = transport.connect(settings, secureReceiver, new ConnectionActivity());
+
+ setRemoteAddress(network.getRemoteAddress());
+ setLocalAddress(network.getLocalAddress());
final Sender<ByteBuffer> secureSender = securityLayer.sender(network.getSender());
if(secureSender instanceof ConnectionListener)
@@ -298,7 +296,12 @@ public class Connection extends ConnectionInvoker
public Session createSession(long expiry)
{
- return createSession(UUID.randomUUID().toString(), expiry);
+ return createSession(expiry, false);
+ }
+
+ public Session createSession(long expiry, boolean isNoReplay)
+ {
+ return createSession(UUID.randomUUID().toString(), expiry, isNoReplay);
}
public Session createSession(String name)
@@ -311,6 +314,11 @@ public class Connection extends ConnectionInvoker
return createSession(Strings.toUTF8(name), expiry);
}
+ public Session createSession(String name, long expiry,boolean isNoReplay)
+ {
+ return createSession(new Binary(Strings.toUTF8(name)), expiry, isNoReplay);
+ }
+
public Session createSession(byte[] name, long expiry)
{
return createSession(new Binary(name), expiry);
@@ -318,6 +326,11 @@ public class Connection extends ConnectionInvoker
public Session createSession(Binary name, long expiry)
{
+ return createSession(name, expiry, false);
+ }
+
+ public Session createSession(Binary name, long expiry, boolean isNoReplay)
+ {
synchronized (lock)
{
Waiter w = new Waiter(lock, timeout);
@@ -331,7 +344,7 @@ public class Connection extends ConnectionInvoker
throw new ConnectionException("Timed out waiting for connection to be ready. Current state is :" + state);
}
- Session ssn = _sessionFactory.newSession(this, name, expiry);
+ Session ssn = _sessionFactory.newSession(this, name, expiry, isNoReplay);
registerSession(ssn);
map(ssn);
ssn.attach();
@@ -369,6 +382,7 @@ public class Connection extends ConnectionInvoker
public void received(ProtocolEvent event)
{
+ _lastReadTime = System.currentTimeMillis();
if(log.isDebugEnabled())
{
log.debug("RECV: [%s] %s", this, event);
@@ -378,6 +392,7 @@ public class Connection extends ConnectionInvoker
public void send(ProtocolEvent event)
{
+ _lastSendTime = System.currentTimeMillis();
if(log.isDebugEnabled())
{
log.debug("SEND: [%s] %s", this, event);
@@ -728,6 +743,17 @@ public class Connection extends ConnectionInvoker
return _localAddress;
}
+ protected void setRemoteAddress(SocketAddress remoteAddress)
+ {
+ _remoteAddress = remoteAddress;
+ }
+
+ protected void setLocalAddress(SocketAddress localAddress)
+ {
+ _localAddress = localAddress;
+ }
+
+
private void invokeSessionDetached(int channel, SessionDetachCode sessionDetachCode)
{
SessionDetached sessionDetached = new SessionDetached();
@@ -735,4 +761,38 @@ public class Connection extends ConnectionInvoker
sessionDetached.setCode(sessionDetachCode);
invoke(sessionDetached);
}
+
+
+ protected void doHeartBeat()
+ {
+ connectionHeartbeat();
+ }
+
+ private class ConnectionActivity implements TransportActivity
+ {
+ @Override
+ public long getLastReadTime()
+ {
+ return _lastReadTime;
+ }
+
+ @Override
+ public long getLastWriteTime()
+ {
+ return _lastSendTime;
+ }
+
+ @Override
+ public void writerIdle()
+ {
+ connectionHeartbeat();
+ }
+
+ @Override
+ public void readerIdle()
+ {
+ // TODO
+
+ }
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java b/java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java
index 20d6f98fa6..12f8d801dc 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java
@@ -38,14 +38,6 @@ public interface NetworkTransportConfiguration
// The amount of memory in bytes to allocate to the outgoing buffer
Integer getSendBufferSize();
- Integer getPort();
-
- String getHost();
-
- String getTransport();
-
- Integer getConnectorProcessors();
-
InetSocketAddress getAddress();
boolean needClientAuth();
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
index e9a7d51456..1e0d5b9698 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
@@ -71,7 +71,8 @@ public class ServerDelegate extends ConnectionDelegate
if (mechanism == null || mechanism.length() == 0)
{
- tuneAuthorizedConnection(conn);
+ conn.connectionClose(ConnectionCloseCode.CONNECTION_FORCED,
+ "No Sasl mechanism was specified");
return;
}
@@ -82,7 +83,7 @@ public class ServerDelegate extends ConnectionDelegate
if (ss == null)
{
conn.connectionClose(ConnectionCloseCode.CONNECTION_FORCED,
- "null SASL mechanism: " + mechanism);
+ "No SaslServer could be created for mechanism: " + mechanism);
return;
}
conn.setSaslServer(ss);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Session.java b/java/common/src/main/java/org/apache/qpid/transport/Session.java
index 95c3e4669f..8b29d6e424 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Session.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Session.java
@@ -25,7 +25,6 @@ import org.apache.qpid.configuration.ClientProperties;
import org.apache.qpid.transport.network.Frame;
import org.apache.qpid.transport.util.Logger;
import org.apache.qpid.transport.util.Waiter;
-
import static org.apache.qpid.transport.Option.COMPLETED;
import static org.apache.qpid.transport.Option.SYNC;
import static org.apache.qpid.transport.Option.TIMELY_REPLY;
@@ -132,19 +131,31 @@ public class Session extends SessionInvoker
private final Object stateLock = new Object();
private final AtomicBoolean _failoverRequired = new AtomicBoolean(false);
+ private boolean _isNoReplay = false;
protected Session(Connection connection, Binary name, long expiry)
{
this(connection, new SessionDelegate(), name, expiry);
}
+ protected Session(Connection connection, Binary name, long expiry, boolean noReplay)
+ {
+ this(connection, new SessionDelegate(), name, expiry, noReplay);
+ }
+
protected Session(Connection connection, SessionDelegate delegate, Binary name, long expiry)
{
+ this(connection, delegate, name, expiry,false);
+ }
+
+ protected Session(Connection connection, SessionDelegate delegate, Binary name, long expiry, boolean noReplay)
+ {
this.connection = connection;
this.delegate = delegate;
this.name = name;
this.expiry = expiry;
this.closing = false;
+ this._isNoReplay = noReplay;
initReceiver();
}
@@ -282,6 +293,7 @@ public class Session extends SessionInvoker
void resume()
{
_failoverRequired.set(false);
+
synchronized (commandsLock)
{
attach();
@@ -414,7 +426,7 @@ public class Session extends SessionInvoker
if(log.isDebugEnabled())
{
- log.debug("ID: [%s] %s", this.channel, id);
+ log.debug("identify: ch=%s, commandId=%s", this.channel, id);
}
if ((id & 0xff) == 0)
@@ -443,7 +455,7 @@ public class Session extends SessionInvoker
{
if(log.isDebugEnabled())
{
- log.debug("%s processed([%d,%d]) %s %s", this, lower, upper, syncPoint, maxProcessed);
+ log.debug("%s ch=%s processed([%d,%d]) %s %s", this, channel, lower, upper, syncPoint, maxProcessed);
}
boolean flush;
@@ -451,7 +463,7 @@ public class Session extends SessionInvoker
{
if(log.isDebugEnabled())
{
- log.debug("%s", processed);
+ log.debug("%s processed: %s", this, processed);
}
if (ge(upper, commandsIn))
@@ -740,7 +752,7 @@ public class Session extends SessionInvoker
sessionCommandPoint(0, 0);
}
- boolean replayTransfer = !closing && !transacted &&
+ boolean replayTransfer = !_isNoReplay && !closing && !transacted &&
m instanceof MessageTransfer &&
! m.isUnreliable();
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java
index 4d4274278f..8437ef1a94 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java
@@ -27,5 +27,7 @@ import javax.net.ssl.SSLContext;
public interface IncomingNetworkTransport extends NetworkTransport
{
- public void accept(NetworkTransportConfiguration config, ProtocolEngineFactory factory, SSLContext sslContext);
+ public void accept(NetworkTransportConfiguration config,
+ ProtocolEngineFactory factory,
+ SSLContext sslContext);
} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java b/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java
index 12c42d6643..050d194c47 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java
@@ -50,4 +50,8 @@ public interface NetworkConnection
void setPeerPrincipal(Principal principal);
Principal getPeerPrincipal();
+
+ int getMaxReadIdle();
+
+ int getMaxWriteIdle();
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java
index 854d76430b..45231aa05d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java
@@ -23,12 +23,13 @@ package org.apache.qpid.transport.network;
import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.Receiver;
-import javax.net.ssl.SSLContext;
import java.nio.ByteBuffer;
public interface OutgoingNetworkTransport extends NetworkTransport
{
public NetworkConnection getConnection();
- public NetworkConnection connect(ConnectionSettings settings, Receiver<ByteBuffer> delegate, SSLContext sslContext);
+ public NetworkConnection connect(ConnectionSettings settings,
+ Receiver<ByteBuffer> delegate,
+ TransportActivity transportActivity);
} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/Ticker.java b/java/common/src/main/java/org/apache/qpid/transport/network/Ticker.java
new file mode 100644
index 0000000000..210b014a57
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/Ticker.java
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.transport.network;
+
+public interface Ticker
+{
+ int getTimeToNextTick(long currentTime);
+
+ int tick(long currentTime);
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/TransportActivity.java b/java/common/src/main/java/org/apache/qpid/transport/network/TransportActivity.java
new file mode 100644
index 0000000000..2ee336d9b2
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/TransportActivity.java
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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.transport.network;
+
+public interface TransportActivity
+{
+ long getLastReadTime();
+
+ long getLastWriteTime();
+
+ void writerIdle();
+
+ void readerIdle();
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IdleTimeoutTicker.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IdleTimeoutTicker.java
new file mode 100644
index 0000000000..54a2a360bb
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IdleTimeoutTicker.java
@@ -0,0 +1,87 @@
+/*
+ *
+ * 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.transport.network.io;
+
+import org.apache.qpid.transport.network.NetworkConnection;
+import org.apache.qpid.transport.network.Ticker;
+import org.apache.qpid.transport.network.TransportActivity;
+
+class IdleTimeoutTicker implements Ticker
+{
+ private final TransportActivity _transport;
+ private final int _defaultTimeout;
+ private NetworkConnection _connection;
+
+ public IdleTimeoutTicker(TransportActivity transport, int defaultTimeout)
+ {
+ _transport = transport;
+ _defaultTimeout = defaultTimeout;
+ }
+
+ @Override
+ public int getTimeToNextTick(long currentTime)
+ {
+ long nextTime = -1;
+ final long maxReadIdle = 1000l * _connection.getMaxReadIdle();
+
+ if(maxReadIdle > 0)
+ {
+ nextTime = _transport.getLastReadTime() + maxReadIdle;
+ }
+
+ long maxWriteIdle = 1000l * _connection.getMaxWriteIdle();
+
+ if(maxWriteIdle > 0)
+ {
+ long writeTime = _transport.getLastWriteTime() + maxWriteIdle;
+ if(nextTime == -1l || writeTime < nextTime)
+ {
+ nextTime = writeTime;
+ }
+ }
+ return nextTime == -1 ? _defaultTimeout : (int) (nextTime - currentTime);
+ }
+
+ @Override
+ public int tick(long currentTime)
+ {
+ // writer Idle
+ long maxWriteIdle = 1000l * _connection.getMaxWriteIdle();
+ if(maxWriteIdle > 0 && maxWriteIdle+ _transport.getLastWriteTime() <= currentTime)
+ {
+ _transport.writerIdle();
+ }
+ // reader Idle
+ final long maxReadIdle = 1000l * _connection.getMaxReadIdle();
+ if(maxReadIdle > 0 && maxReadIdle+ _transport.getLastReadTime() <= currentTime)
+ {
+
+ _transport.readerIdle();
+ }
+ return getTimeToNextTick(currentTime);
+ }
+
+ public void setConnection(NetworkConnection connection)
+ {
+ _connection = connection;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java
index 2658296c5f..f5c09ac2cc 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java
@@ -26,7 +26,9 @@ import java.nio.ByteBuffer;
import java.security.Principal;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.network.Ticker;
import org.apache.qpid.transport.network.NetworkConnection;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,14 +40,23 @@ public class IoNetworkConnection implements NetworkConnection
private final IoSender _ioSender;
private final IoReceiver _ioReceiver;
private Principal _principal;
+ private int _maxReadIdle;
+ private int _maxWriteIdle;
public IoNetworkConnection(Socket socket, Receiver<ByteBuffer> delegate,
- int sendBufferSize, int receiveBufferSize, long timeout)
+ int sendBufferSize, int receiveBufferSize, long timeout)
+ {
+ this(socket,delegate,sendBufferSize,receiveBufferSize,timeout,null);
+ }
+
+ public IoNetworkConnection(Socket socket, Receiver<ByteBuffer> delegate,
+ int sendBufferSize, int receiveBufferSize, long timeout, Ticker ticker)
{
_socket = socket;
_timeout = timeout;
_ioReceiver = new IoReceiver(_socket, delegate, receiveBufferSize,_timeout);
+ _ioReceiver.setTicker(ticker);
_ioSender = new IoSender(_socket, 2 * sendBufferSize, _timeout);
@@ -88,14 +99,12 @@ public class IoNetworkConnection implements NetworkConnection
public void setMaxWriteIdle(int sec)
{
- // TODO implement support for setting heartbeating config in this way
- // Currently a socket timeout is used in IoSender
+ _maxWriteIdle = sec;
}
public void setMaxReadIdle(int sec)
{
- // TODO implement support for setting heartbeating config in this way
- // Currently a socket timeout is used in IoSender
+ _maxReadIdle = sec;
}
@Override
@@ -109,4 +118,16 @@ public class IoNetworkConnection implements NetworkConnection
{
return _principal;
}
+
+ @Override
+ public int getMaxReadIdle()
+ {
+ return _maxReadIdle;
+ }
+
+ @Override
+ public int getMaxWriteIdle()
+ {
+ return _maxWriteIdle;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
index 9b6f0a0b1b..c8027e143e 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
@@ -41,9 +41,8 @@ import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.NetworkTransportConfiguration;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
-import org.apache.qpid.transport.network.IncomingNetworkTransport;
-import org.apache.qpid.transport.network.NetworkConnection;
-import org.apache.qpid.transport.network.OutgoingNetworkTransport;
+import org.apache.qpid.transport.network.*;
+
import org.slf4j.LoggerFactory;
public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNetworkTransport
@@ -56,7 +55,9 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
private IoNetworkConnection _connection;
private AcceptingThread _acceptor;
- public NetworkConnection connect(ConnectionSettings settings, Receiver<ByteBuffer> delegate, SSLContext sslContext)
+ public NetworkConnection connect(ConnectionSettings settings,
+ Receiver<ByteBuffer> delegate,
+ TransportActivity transportActivity)
{
int sendBufferSize = settings.getWriteBufferSize();
int receiveBufferSize = settings.getReadBufferSize();
@@ -91,7 +92,9 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
try
{
- _connection = new IoNetworkConnection(_socket, delegate, sendBufferSize, receiveBufferSize, TIMEOUT);
+ IdleTimeoutTicker ticker = new IdleTimeoutTicker(transportActivity, TIMEOUT);
+ _connection = new IoNetworkConnection(_socket, delegate, sendBufferSize, receiveBufferSize, TIMEOUT, ticker);
+ ticker.setConnection(_connection);
_connection.start();
}
catch(Exception e)
@@ -128,9 +131,10 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
return _connection;
}
- public void accept(NetworkTransportConfiguration config, ProtocolEngineFactory factory, SSLContext sslContext)
+ public void accept(NetworkTransportConfiguration config,
+ ProtocolEngineFactory factory,
+ SSLContext sslContext)
{
-
try
{
_acceptor = new AcceptingThread(config, factory, sslContext);
@@ -141,8 +145,6 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
{
throw new TransportException("Unable to start server socket", e);
}
-
-
}
private class AcceptingThread extends Thread
@@ -152,15 +154,16 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
private ProtocolEngineFactory _factory;
private SSLContext _sslContext;
private ServerSocket _serverSocket;
+ private int _timeout;
private AcceptingThread(NetworkTransportConfiguration config,
ProtocolEngineFactory factory,
- SSLContext sslContext)
- throws IOException
+ SSLContext sslContext) throws IOException
{
_config = config;
_factory = factory;
_sslContext = sslContext;
+ _timeout = TIMEOUT;
InetSocketAddress address = config.getAddress();
@@ -172,15 +175,19 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
{
SSLServerSocketFactory socketFactory = _sslContext.getServerSocketFactory();
_serverSocket = socketFactory.createServerSocket();
- ((SSLServerSocket)_serverSocket).setNeedClientAuth(config.needClientAuth());
- ((SSLServerSocket)_serverSocket).setWantClientAuth(config.wantClientAuth());
+ if(config.needClientAuth())
+ {
+ ((SSLServerSocket)_serverSocket).setNeedClientAuth(true);
+ }
+ else if(config.wantClientAuth())
+ {
+ ((SSLServerSocket)_serverSocket).setWantClientAuth(true);
+ }
}
_serverSocket.setReuseAddress(true);
_serverSocket.bind(address);
-
-
}
@@ -217,6 +224,7 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
{
socket = _serverSocket.accept();
socket.setTcpNoDelay(_config.getTcpNoDelay());
+ socket.setSoTimeout(_timeout);
final Integer sendBufferSize = _config.getSendBufferSize();
final Integer receiveBufferSize = _config.getReceiveBufferSize();
@@ -224,10 +232,12 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
socket.setSendBufferSize(sendBufferSize);
socket.setReceiveBufferSize(receiveBufferSize);
-
ProtocolEngine engine = _factory.newProtocolEngine();
- NetworkConnection connection = new IoNetworkConnection(socket, engine, sendBufferSize, receiveBufferSize, TIMEOUT);
+ final IdleTimeoutTicker ticker = new IdleTimeoutTicker(engine, TIMEOUT);
+ NetworkConnection connection = new IoNetworkConnection(socket, engine, sendBufferSize, receiveBufferSize, _timeout,
+ ticker);
+ ticker.setConnection(connection);
if(_sslContext != null)
{
@@ -248,14 +258,14 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
}
catch(RuntimeException e)
{
- LOGGER.error("Error in Acceptor thread on port " + _config.getPort(), e);
+ LOGGER.error("Error in Acceptor thread on address " + _config.getAddress(), e);
closeSocketIfNecessary(socket);
}
catch(IOException e)
{
if(!_closed)
{
- LOGGER.error("Error in Acceptor thread on port " + _config.getPort(), e);
+ LOGGER.error("Error in Acceptor thread on address " + _config.getAddress(), e);
closeSocketIfNecessary(socket);
try
{
@@ -275,7 +285,7 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
{
if(LOGGER.isDebugEnabled())
{
- LOGGER.debug("Acceptor exiting, no new connections will be accepted on port " + _config.getPort());
+ LOGGER.debug("Acceptor exiting, no new connections will be accepted on address " + _config.getAddress());
}
}
}
@@ -294,6 +304,7 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
}
}
}
+
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
index 7e63071c16..06a43e21c6 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
@@ -24,6 +24,7 @@ import org.apache.qpid.common.Closeable;
import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.network.Ticker;
import org.apache.qpid.transport.util.Logger;
import javax.net.ssl.SSLSocket;
@@ -31,6 +32,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -51,6 +53,8 @@ final class IoReceiver implements Runnable, Closeable
private final AtomicBoolean closed = new AtomicBoolean(false);
private final Thread receiverThread;
private static final boolean shutdownBroken;
+
+ private Ticker _ticker;
static
{
String osName = System.getProperty("os.name");
@@ -136,7 +140,7 @@ final class IoReceiver implements Runnable, Closeable
{
final int threshold = bufferSize / 2;
- // I set the read buffer size simillar to SO_RCVBUF
+ // I set the read buffer size similar to SO_RCVBUF
// Haven't tested with a lower value to see if it's better or worse
byte[] buffer = new byte[bufferSize];
try
@@ -144,27 +148,71 @@ final class IoReceiver implements Runnable, Closeable
InputStream in = socket.getInputStream();
int read = 0;
int offset = 0;
- while ((read = in.read(buffer, offset, bufferSize-offset)) != -1)
+ long currentTime;
+ while(read != -1)
{
- if (read > 0)
+ try
+ {
+ while ((read = in.read(buffer, offset, bufferSize-offset)) != -1)
+ {
+ if (read > 0)
+ {
+ ByteBuffer b = ByteBuffer.wrap(buffer,offset,read);
+ receiver.received(b);
+ offset+=read;
+ if (offset > threshold)
+ {
+ offset = 0;
+ buffer = new byte[bufferSize];
+ }
+ }
+ currentTime = System.currentTimeMillis();
+
+ if(_ticker != null)
+ {
+ int tick = _ticker.getTimeToNextTick(currentTime);
+ if(tick <= 0)
+ {
+ tick = _ticker.tick(currentTime);
+ }
+ try
+ {
+ if(!socket.isClosed())
+ {
+ socket.setSoTimeout(tick <= 0 ? 1 : tick);
+ }
+ }
+ catch(SocketException e)
+ {
+ // ignore - closed socket
+ }
+ }
+ }
+ }
+ catch (SocketTimeoutException e)
{
- ByteBuffer b = ByteBuffer.wrap(buffer,offset,read);
- receiver.received(b);
- offset+=read;
- if (offset > threshold)
+ currentTime = System.currentTimeMillis();
+ if(_ticker != null)
{
- offset = 0;
- buffer = new byte[bufferSize];
+ final int tick = _ticker.tick(currentTime);
+ if(!socket.isClosed())
+ {
+ try
+ {
+ socket.setSoTimeout(tick <= 0 ? 1 : tick );
+ }
+ catch(SocketException ex)
+ {
+ // ignore - closed socket
+ }
+ }
}
}
}
}
catch (Throwable t)
{
- if (!(shutdownBroken &&
- t instanceof SocketException &&
- t.getMessage().equalsIgnoreCase("socket closed") &&
- closed.get()))
+ if (shouldReport(t))
{
receiver.exception(t);
}
@@ -183,4 +231,30 @@ final class IoReceiver implements Runnable, Closeable
}
}
+ private boolean shouldReport(Throwable t)
+ {
+ boolean brokenClose = closed.get() &&
+ shutdownBroken &&
+ t instanceof SocketException &&
+ "socket closed".equalsIgnoreCase(t.getMessage());
+
+ boolean sslSocketClosed = closed.get() &&
+ socket instanceof SSLSocket &&
+ t instanceof SocketException &&
+ "Socket is closed".equalsIgnoreCase(t.getMessage());
+
+ return !brokenClose && !sslSocketClosed;
+ }
+
+ public Ticker getTicker()
+ {
+ return _ticker;
+ }
+
+ public void setTicker(Ticker ticker)
+ {
+ _ticker = ticker;
+ }
+
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/url/BindingURL.java b/java/common/src/main/java/org/apache/qpid/url/BindingURL.java
index 0e6c865a16..61585443b1 100644
--- a/java/common/src/main/java/org/apache/qpid/url/BindingURL.java
+++ b/java/common/src/main/java/org/apache/qpid/url/BindingURL.java
@@ -36,6 +36,9 @@ public interface BindingURL
public static final String OPTION_SUBSCRIPTION = "subscription";
public static final String OPTION_ROUTING_KEY = "routingkey";
public static final String OPTION_BINDING_KEY = "bindingkey";
+ public static final String OPTION_EXCHANGE_AUTODELETE = "exchangeautodelete";
+ public static final String OPTION_EXCHANGE_DURABLE = "exchangedurable";
+ public static final String OPTION_EXCHANGE_INTERNAL = "exchangeinternal";
/**
* This option is only applicable for 0-8/0-9/0-9-1 protocols connection
diff --git a/java/common/src/main/java/org/apache/qpid/util/FileUtils.java b/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
index 2d3e321812..7362099070 100644
--- a/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
+++ b/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
@@ -220,6 +220,19 @@ public class FileUtils
public static void copyCheckedEx(File src, File dst) throws IOException
{
InputStream in = new FileInputStream(src);
+ copy(in, dst);
+ }
+
+ /**
+ * Copies the specified InputStream to the specified destination file. If the destination file does not exist,
+ * it is created.
+ *
+ * @param in The InputStream
+ * @param dst The destination file name.
+ * @throws IOException
+ */
+ public static void copy(InputStream in, File dst) throws IOException
+ {
try
{
if (!dst.exists())
diff --git a/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java b/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
deleted file mode 100644
index 971dd3fe2a..0000000000
--- a/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/***********************************************************************
- * Copyright (c) 2000-2006 The Apache Software Foundation. *
- * All rights reserved. *
- * ------------------------------------------------------------------- *
- * Licensed 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.util;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-
-public class NetMatcher
-{
- private ArrayList networks;
-
- public void initInetNetworks(final Collection nets)
- {
- networks = new ArrayList();
- for (Iterator iter = nets.iterator(); iter.hasNext(); )
- {
- try
- {
- InetNetwork net = InetNetwork.getFromString((String) iter.next());
- if (!networks.contains(net))
- {
- networks.add(net);
- }
- }
- catch (java.net.UnknownHostException uhe)
- {
- log("Cannot resolve address: " + uhe.getMessage());
- }
- }
- networks.trimToSize();
- }
-
- public void initInetNetworks(final String[] nets)
- {
- networks = new ArrayList();
- for (int i = 0; i < nets.length; i++)
- {
- try
- {
- InetNetwork net = InetNetwork.getFromString(nets[i]);
- if (!networks.contains(net))
- {
- networks.add(net);
- }
- }
- catch (java.net.UnknownHostException uhe)
- {
- log("Cannot resolve address: " + uhe.getMessage());
- }
- }
- networks.trimToSize();
- }
-
- public boolean matchInetNetwork(final String hostIP)
- {
- InetAddress ip = null;
-
- try
- {
- ip = InetAddress.getByName(hostIP);
- }
- catch (java.net.UnknownHostException uhe)
- {
- log("Cannot resolve address for " + hostIP + ": " + uhe.getMessage());
- }
-
- boolean sameNet = false;
-
- if (ip != null)
- {
- for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
- {
- InetNetwork network = (InetNetwork) iter.next();
- sameNet = network.contains(ip);
- }
- }
- return sameNet;
- }
-
- public boolean matchInetNetwork(final InetAddress ip)
- {
- boolean sameNet = false;
-
- for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
- {
- InetNetwork network = (InetNetwork) iter.next();
- sameNet = network.contains(ip);
- }
- return sameNet;
- }
-
- public NetMatcher()
- {
- }
-
- public NetMatcher(final String[] nets)
- {
- initInetNetworks(nets);
- }
-
- public NetMatcher(final Collection nets)
- {
- initInetNetworks(nets);
- }
-
- public String toString() {
- return networks.toString();
- }
-
- protected void log(String s) { }
-}
-
-class InetNetwork
-{
- /*
- * Implements network masking, and is compatible with RFC 1518 and
- * RFC 1519, which describe CIDR: Classless Inter-Domain Routing.
- */
-
- private InetAddress network;
- private InetAddress netmask;
-
- public InetNetwork(InetAddress ip, InetAddress netmask)
- {
- network = maskIP(ip, netmask);
- this.netmask = netmask;
- }
-
- public boolean contains(final String name) throws java.net.UnknownHostException
- {
- return network.equals(maskIP(InetAddress.getByName(name), netmask));
- }
-
- public boolean contains(final InetAddress ip)
- {
- return network.equals(maskIP(ip, netmask));
- }
-
- public String toString()
- {
- return network.getHostAddress() + "/" + netmask.getHostAddress();
- }
-
- public int hashCode()
- {
- return maskIP(network, netmask).hashCode();
- }
-
- public boolean equals(Object obj)
- {
- return (obj != null) && (obj instanceof InetNetwork) &&
- ((((InetNetwork)obj).network.equals(network)) && (((InetNetwork)obj).netmask.equals(netmask)));
- }
-
- public static InetNetwork getFromString(String netspec) throws java.net.UnknownHostException
- {
- if (netspec.endsWith("*"))
- {
- netspec = normalizeFromAsterisk(netspec);
- }
- else
- {
- int iSlash = netspec.indexOf('/');
- if (iSlash == -1)
- {
- netspec += "/255.255.255.255";
- }
- else if (netspec.indexOf('.', iSlash) == -1)
- {
- netspec = normalizeFromCIDR(netspec);
- }
- }
-
- return new InetNetwork(InetAddress.getByName(netspec.substring(0, netspec.indexOf('/'))),
- InetAddress.getByName(netspec.substring(netspec.indexOf('/') + 1)));
- }
-
- public static InetAddress maskIP(final byte[] ip, final byte[] mask)
- {
- try
- {
- return getByAddress(new byte[]
- {
- (byte) (mask[0] & ip[0]),
- (byte) (mask[1] & ip[1]),
- (byte) (mask[2] & ip[2]),
- (byte) (mask[3] & ip[3])
- });
- }
- catch(Exception _) {}
- {
- return null;
- }
- }
-
- public static InetAddress maskIP(final InetAddress ip, final InetAddress mask)
- {
- return maskIP(ip.getAddress(), mask.getAddress());
- }
-
- /*
- * This converts from an uncommon "wildcard" CIDR format
- * to "address + mask" format:
- *
- * * => 000.000.000.0/000.000.000.0
- * xxx.* => xxx.000.000.0/255.000.000.0
- * xxx.xxx.* => xxx.xxx.000.0/255.255.000.0
- * xxx.xxx.xxx.* => xxx.xxx.xxx.0/255.255.255.0
- */
- static private String normalizeFromAsterisk(final String netspec)
- {
- String[] masks = { "0.0.0.0/0.0.0.0", "0.0.0/255.0.0.0", "0.0/255.255.0.0", "0/255.255.255.0" };
- char[] srcb = netspec.toCharArray();
- int octets = 0;
- for (int i = 1; i < netspec.length(); i++)
- {
- if (srcb[i] == '.')
- {
- octets++;
- }
- }
- return (octets == 0) ? masks[0] : netspec.substring(0, netspec.length() -1 ).concat(masks[octets]);
- }
-
- /*
- * RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR)
- * This converts from "prefix + prefix-length" format to
- * "address + mask" format, e.g. from xxx.xxx.xxx.xxx/yy
- * to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy.
- */
- static private String normalizeFromCIDR(final String netspec)
- {
- final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));
- final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1);
-
- return netspec.substring(0, netspec.indexOf('/') + 1) +
- Integer.toString(mask >> 24 & 0xFF, 10) + "." +
- Integer.toString(mask >> 16 & 0xFF, 10) + "." +
- Integer.toString(mask >> 8 & 0xFF, 10) + "." +
- Integer.toString(mask >> 0 & 0xFF, 10);
- }
-
- private static java.lang.reflect.Method getByAddress = null;
-
- static {
- try {
- Class inetAddressClass = Class.forName("java.net.InetAddress");
- Class[] parameterTypes = { byte[].class };
- getByAddress = inetAddressClass.getMethod("getByAddress", parameterTypes);
- } catch (Exception e) {
- getByAddress = null;
- }
- }
-
- private static InetAddress getByAddress(byte[] ip) throws java.net.UnknownHostException
- {
- InetAddress addr = null;
- if (getByAddress != null)
- {
- try
- {
- addr = (InetAddress) getByAddress.invoke(null, new Object[] { ip });
- }
- catch (IllegalAccessException e)
- {
- }
- catch (java.lang.reflect.InvocationTargetException e)
- {
- }
- }
-
- if (addr == null) {
- addr = InetAddress.getByName
- (
- Integer.toString(ip[0] & 0xFF, 10) + "." +
- Integer.toString(ip[1] & 0xFF, 10) + "." +
- Integer.toString(ip[2] & 0xFF, 10) + "." +
- Integer.toString(ip[3] & 0xFF, 10)
- );
- }
- return addr;
- }
-}
diff --git a/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java b/java/common/src/test/java/org/apache/qpid/framing/FieldTableTest.java
index 16f35613d8..1ecf450551 100644
--- a/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
+++ b/java/common/src/test/java/org/apache/qpid/framing/FieldTableTest.java
@@ -22,8 +22,6 @@ package org.apache.qpid.framing;
import junit.framework.Assert;
import junit.framework.TestCase;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.apache.qpid.AMQPInvalidClassException;
@@ -33,10 +31,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-public class PropertyFieldTableTest extends TestCase
+public class FieldTableTest extends TestCase
{
- private static final Logger _logger = LoggerFactory.getLogger(PropertyFieldTableTest.class);
-
/**
* Test that setting a similar named value replaces any previous value set on that name
*/
@@ -696,66 +692,8 @@ public class PropertyFieldTableTest extends TestCase
result.setObject("object-short", Short.MAX_VALUE);
size += 1 + EncodingUtils.encodedShortStringLength("object-short") + EncodingUtils.encodedShortLength();
Assert.assertEquals(size, result.getEncodedSize());
-
}
- // public void testEncodingSize1()
- // {
- // PropertyFieldTable table = new PropertyFieldTable();
- // int length = 0;
- // result.put("one", 1L);
- // length = EncodingUtils.encodedShortStringLength("one");
- // length += 1 + EncodingUtils.encodedLongLength();
- // assertEquals(length, result.getEncodedSize());
- //
- // result.put("two", 2L);
- // length += EncodingUtils.encodedShortStringLength("two");
- // length += 1 + EncodingUtils.encodedLongLength();
- // assertEquals(length, result.getEncodedSize());
- //
- // result.put("three", 3L);
- // length += EncodingUtils.encodedShortStringLength("three");
- // length += 1 + EncodingUtils.encodedLongLength();
- // assertEquals(length, result.getEncodedSize());
- //
- // result.put("four", 4L);
- // length += EncodingUtils.encodedShortStringLength("four");
- // length += 1 + EncodingUtils.encodedLongLength();
- // assertEquals(length, result.getEncodedSize());
- //
- // result.put("five", 5L);
- // length += EncodingUtils.encodedShortStringLength("five");
- // length += 1 + EncodingUtils.encodedLongLength();
- // assertEquals(length, result.getEncodedSize());
- //
- // //fixme should perhaps be expanded to incorporate all types.
- //
- // final ByteBuffer buffer = ByteBuffer.allocate((int) result.getEncodedSize()); // FIXME XXX: Is cast a problem?
- //
- // result.writeToBuffer(buffer);
- //
- // buffer.flip();
- //
- // long length = buffer.getUnsignedInt();
- //
- // try
- // {
- // PropertyFieldTable table2 = new PropertyFieldTable(buffer, length);
- //
- // Assert.assertEquals((Long) 1L, table2.getLong("one"));
- // Assert.assertEquals((Long) 2L, table2.getLong("two"));
- // Assert.assertEquals((Long) 3L, table2.getLong("three"));
- // Assert.assertEquals((Long) 4L, table2.getLong("four"));
- // Assert.assertEquals((Long) 5L, table2.getLong("five"));
- // }
- // catch (AMQFrameDecodingException e)
- // {
- // e.printStackTrace();
- // fail("PFT should be instantiated from bytes." + e.getCause());
- // }
- //
- // }
-
/**
* Additional test for setObject
*/
@@ -883,7 +821,6 @@ public class PropertyFieldTableTest extends TestCase
{
fail("property name are allowed to start with # and $s");
}
-
}
/**
@@ -919,7 +856,6 @@ public class PropertyFieldTableTest extends TestCase
Assert.assertEquals("1", table.getObject("n1"));
Assert.assertEquals("2", table.getObject("n2"));
Assert.assertEquals("3", table.getObject("n3"));
-
}
public void testAddAll()
@@ -952,29 +888,51 @@ public class PropertyFieldTableTest extends TestCase
assertEquals("Unexpected number of entries in table1 after addAll", 2, table1.size());
}
- private void assertBytesEqual(byte[] expected, byte[] actual)
+ /**
+ * Tests that when copying properties into a new FielTable using the addAll() method, the
+ * properties are successfully added to the destination table when the source FieldTable
+ * was created from encoded input bytes,
+ */
+ public void testAddingAllFromFieldTableCreatedUsingEncodedBytes() throws Exception
{
- Assert.assertEquals(expected.length, actual.length);
+ AMQShortString myBooleanTestProperty = new AMQShortString("myBooleanTestProperty");
- for (int index = 0; index < expected.length; index++)
- {
- Assert.assertEquals(expected[index], actual[index]);
- }
+ //Create a new FieldTable and use it to encode data into a byte array.
+ FieldTable encodeTable = new FieldTable();
+ encodeTable.put(myBooleanTestProperty, true);
+ byte[] data = encodeTable.getDataAsBytes();
+ int length = data.length;
+
+ //Verify we got the expected mount of encoded data (1B type hdr + 21B for name + 1B type hdr + 1B for boolean)
+ assertEquals("unexpected data length", 24, length);
+
+ //Create a second FieldTable from the encoded bytes
+ FieldTable tableFromBytes = new FieldTable(new DataInputStream(new ByteArrayInputStream(data)), length);
+
+ //Create a final FieldTable and addAll() from the table created with encoded bytes
+ FieldTable destinationTable = new FieldTable();
+ assertTrue("unexpected size", destinationTable.isEmpty());
+ destinationTable.addAll(tableFromBytes);
+
+ //Verify that the destination table now contains the expected entry
+ assertEquals("unexpected size", 1, destinationTable.size());
+ assertTrue("expected property not present", destinationTable.containsKey(myBooleanTestProperty));
+ assertTrue("unexpected property value", destinationTable.getBoolean(myBooleanTestProperty));
}
- private void assertBytesNotEqual(byte[] expected, byte[] actual)
+ private void assertBytesEqual(byte[] expected, byte[] actual)
{
Assert.assertEquals(expected.length, actual.length);
for (int index = 0; index < expected.length; index++)
{
- Assert.assertFalse(expected[index] == actual[index]);
+ Assert.assertEquals(expected[index], actual[index]);
}
}
public static junit.framework.Test suite()
{
- return new junit.framework.TestSuite(PropertyFieldTableTest.class);
+ return new junit.framework.TestSuite(FieldTableTest.class);
}
}
diff --git a/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java b/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java
index ec06400b7d..08f7387b75 100644
--- a/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java
+++ b/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java
@@ -41,6 +41,7 @@ public class QpidTestCase extends TestCase
public static final String QPID_HOME = System.getProperty("QPID_HOME");
public static final String TEST_RESOURCES_DIR = QPID_HOME + "/../test-profiles/test_resources/";
public static final String TMP_FOLDER = System.getProperty("java.io.tmpdir");
+ public static final String LOG4J_CONFIG_FILE_PATH = System.getProperty("log4j.configuration.file");
private static final Logger _logger = Logger.getLogger(QpidTestCase.class);
@@ -115,12 +116,7 @@ public class QpidTestCase extends TestCase
public QpidTestCase()
{
- this("QpidTestCase");
- }
-
- public QpidTestCase(String name)
- {
- super(name);
+ super();
}
public void run(TestResult testResult)
@@ -204,6 +200,8 @@ public class QpidTestCase extends TestCase
{
System.setProperty(property, value);
}
+
+ _logger.info("Set system property \"" + property + "\" to: \"" + value + "\"");
}
/**
diff --git a/java/common/src/test/java/org/apache/qpid/test/utils/TestFileUtils.java b/java/common/src/test/java/org/apache/qpid/test/utils/TestFileUtils.java
index 056d11faaa..14dec8efad 100644
--- a/java/common/src/test/java/org/apache/qpid/test/utils/TestFileUtils.java
+++ b/java/common/src/test/java/org/apache/qpid/test/utils/TestFileUtils.java
@@ -21,6 +21,12 @@
package org.apache.qpid.test.utils;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.io.FileOutputStream;
+
+import junit.framework.TestCase;
import org.apache.qpid.util.FileUtils;
@@ -30,6 +36,7 @@ import org.apache.qpid.util.FileUtils;
public class TestFileUtils
{
private static final String SYSTEM_TMP_DIR = System.getProperty("java.io.tmpdir");
+ private static final String SUFFIX = "tmp";
/**
* Create and return a temporary directory that will be deleted on exit.
@@ -60,4 +67,87 @@ public class TestFileUtils
return testDir;
}
+
+ public static File createTempFile(TestCase testcase)
+ {
+ return createTempFile(testcase, SUFFIX);
+ }
+
+ public static File createTempFile(TestCase testcase, String suffix)
+ {
+ String prefix = testcase.getClass().getSimpleName() + "-" + testcase.getName();
+
+ File tmpFile;
+ try
+ {
+ tmpFile = File.createTempFile(prefix, suffix);
+ tmpFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Cannot create temporary file with prefix " + prefix + " and suffix " + SUFFIX, e);
+ }
+
+ return tmpFile;
+ }
+
+ /**
+ * Creates a temporary file from the resource name given, using the resource name as the file suffix.
+ *
+ * This is required because the tests use the jar files as their class path.
+ */
+ public static File createTempFileFromResource(TestCase testCase, String resourceName)
+ {
+ File dst = createTempFile(testCase, resourceName);
+ InputStream in = testCase.getClass().getResourceAsStream(resourceName);
+ try
+ {
+ FileUtils.copy(in, dst);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Cannot copy resource " + resourceName +
+ " to temp file " + dst.getAbsolutePath(), e);
+ }
+ dst.deleteOnExit();
+ return dst;
+ }
+
+ /**
+ * Creates a temporary file for given test with given suffix in file name.
+ * The given content is stored in the file using UTF-8 encoding.
+ */
+ public static File createTempFile(TestCase testcase, String suffix, String content)
+ {
+ File file = createTempFile(testcase, suffix);
+ if (content != null)
+ {
+ FileOutputStream fos = null;
+ try
+ {
+ fos = new FileOutputStream(file);
+ fos.write(content.getBytes("UTF-8"));
+ fos.flush();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Cannot add the content into temp file " + file.getAbsolutePath(), e);
+ }
+ finally
+ {
+ if (fos != null)
+ {
+ try
+ {
+ fos.close();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Cannot close output stream into temp file " + file.getAbsolutePath(), e);
+ }
+ }
+ }
+ }
+ return file;
+ }
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java b/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
index f3715f351e..12bbd20228 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
+++ b/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
@@ -155,6 +155,7 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
{
final Connection conn = new Connection();
conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
+
conn.addConnectionListener(new ConnectionListener()
{
public void opened(Connection conn) {}
@@ -225,6 +226,12 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
ssn.setSessionListener(ConnectionTest.this);
return ssn;
}
+
+ @Override
+ public void connectionStartOk(Connection conn, ConnectionStartOk ok)
+ {
+ tuneAuthorizedConnection(conn);
+ }
};
try
diff --git a/java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java
index 893f66c5ff..a19c2e7e43 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java
+++ b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java
@@ -83,6 +83,18 @@ public class TestNetworkConnection implements NetworkConnection
return null;
}
+ @Override
+ public int getMaxReadIdle()
+ {
+ return 0;
+ }
+
+ @Override
+ public int getMaxWriteIdle()
+ {
+ return 0;
+ }
+
public void setMaxWriteIdle(int idleTime)
{
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java b/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java
index c882d3437e..bf9a5843d6 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java
+++ b/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java
@@ -128,7 +128,8 @@ public class TransportTest extends QpidTestCase
}
public NetworkConnection connect(ConnectionSettings settings,
- Receiver<ByteBuffer> delegate, SSLContext sslContext)
+ Receiver<ByteBuffer> delegate,
+ TransportActivity transportActivity)
{
throw new UnsupportedOperationException();
}
@@ -148,7 +149,7 @@ public class TransportTest extends QpidTestCase
}
public void accept(NetworkTransportConfiguration config,
- ProtocolEngineFactory factory, SSLContext sslContext)
+ ProtocolEngineFactory factory, SSLContext sslContext)
{
throw new UnsupportedOperationException();
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/io/IdleTimeoutTickerTest.java b/java/common/src/test/java/org/apache/qpid/transport/network/io/IdleTimeoutTickerTest.java
new file mode 100644
index 0000000000..5cdd7a8597
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/network/io/IdleTimeoutTickerTest.java
@@ -0,0 +1,257 @@
+/*
+ *
+ * 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.transport.network.io;
+
+import junit.framework.TestCase;
+
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.security.Principal;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.network.NetworkConnection;
+import org.apache.qpid.transport.network.TransportActivity;
+
+public class IdleTimeoutTickerTest extends TestCase implements TransportActivity, NetworkConnection
+{
+ private IdleTimeoutTicker _ticker;
+ private static final int DEFAULT_TIMEOUT = 567890;
+ private long _lastReadTime;
+ private long _lastWriteTime;
+ private long _currentTime;
+ private int _maxWriteIdle;
+ private int _maxReadIdle;
+ private boolean _readerIdle;
+ private boolean _writerIdle;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _ticker = new IdleTimeoutTicker(this, DEFAULT_TIMEOUT);
+ _ticker.setConnection(this);
+ _readerIdle = false;
+ _writerIdle = false;
+ _lastReadTime = 0l;
+ _lastWriteTime = 0l;
+ _maxReadIdle = 0;
+ _maxWriteIdle = 0;
+ }
+
+ public void testNoIdle() throws Exception
+ {
+ _maxReadIdle = 4;
+ _maxWriteIdle = 2;
+ _lastReadTime = 0;
+ _lastWriteTime = 1500;
+ _currentTime = 3000;
+ // Current time = 3s,
+ // last read = 0s, max read idle = 4s, should check in 1s
+ // last write = 1.5s, max write idle = 2s, should check in 0.5s
+ long nextTime = _ticker.tick(_currentTime);
+ assertEquals("Incorrect next tick calculation", 500l, nextTime);
+ assertFalse("Incorrectly caused reader idle", _readerIdle);
+ assertFalse("Incorrectly caused writer idle", _writerIdle);
+
+
+ // Current time = 3.4s,
+ // last read = 0s, max read idle = 4s, should check in 0.6s
+ // last write = 3.1s, max write idle = 2s, should check in 1.7s
+ _lastWriteTime = 3100;
+ _currentTime = 3400;
+ nextTime = _ticker.tick(_currentTime);
+ assertEquals("Incorrect next tick calculation", 600l, nextTime);
+ assertFalse("Incorrectly caused reader idle", _readerIdle);
+ assertFalse("Incorrectly caused writer idle", _writerIdle);
+
+ _maxReadIdle = 0;
+ nextTime = _ticker.tick(_currentTime);
+ assertEquals("Incorrect next tick calculation", 1700l, nextTime);
+ assertFalse("Incorrectly caused reader idle", _readerIdle);
+ assertFalse("Incorrectly caused writer idle", _writerIdle);
+
+ _maxWriteIdle = 0;
+ nextTime = _ticker.tick(_currentTime);
+ assertEquals("Incorrect next tick calculation", DEFAULT_TIMEOUT, nextTime);
+ assertFalse("Incorrectly caused reader idle", _readerIdle);
+ assertFalse("Incorrectly caused writer idle", _writerIdle);
+
+ }
+
+ public void testReaderIdle() throws Exception
+ {
+ _maxReadIdle = 4;
+ _maxWriteIdle = 0;
+ _lastReadTime = 0;
+ _lastWriteTime = 2500;
+ _currentTime = 4000;
+ // Current time = 4s,
+ // last read = 0s, max read idle = 4s, reader idle
+ long nextTime = _ticker.tick(_currentTime);
+
+ assertTrue(_readerIdle);
+ assertFalse(_writerIdle);
+
+ _readerIdle = false;
+
+ // last write = 2.5s, max write idle = 2s, should check in 0.5s
+ _maxWriteIdle = 2;
+ nextTime = _ticker.tick(_currentTime);
+ assertTrue(_readerIdle);
+ assertFalse(_writerIdle);
+
+ _readerIdle = false;
+ // last write = 1.5s, max write idle = 2s, should check in 0.5s
+
+ _lastWriteTime = 1500;
+ nextTime = _ticker.tick(_currentTime);
+
+ assertTrue(_readerIdle);
+ assertTrue(_writerIdle);
+
+ }
+
+ public void testWriterIdle() throws Exception
+ {
+ _maxReadIdle = 0;
+ _maxWriteIdle = 2;
+ _lastReadTime = 0;
+ _lastWriteTime = 1500;
+ _currentTime = 4000;
+ // Current time = 4s,
+ // last write = 1.5s, max write idle = 2s, writer idle
+ long nextTime = _ticker.tick(_currentTime);
+
+ assertTrue(_writerIdle);
+ assertFalse(_readerIdle);
+ assertEquals(2000l,nextTime);
+
+ _writerIdle = false;
+ _lastWriteTime = 1500;
+ _maxReadIdle = 5;
+
+ nextTime = _ticker.tick(_currentTime);
+
+ assertTrue(_writerIdle);
+ assertFalse(_readerIdle);
+ assertEquals(1000l,nextTime);
+
+ }
+
+ //-------------------------------------------------------------------------
+ // Implement TransportActivity methods
+ //-------------------------------------------------------------------------
+
+ @Override
+ public long getLastReadTime()
+ {
+ return _lastReadTime;
+ }
+
+ @Override
+ public long getLastWriteTime()
+ {
+ return _lastWriteTime;
+ }
+
+ @Override
+ public void writerIdle()
+ {
+ _writerIdle = true;
+ _lastWriteTime = _currentTime;
+ }
+
+ @Override
+ public void readerIdle()
+ {
+ _readerIdle = true;
+ }
+
+ //-------------------------------------------------------------------------
+ // Implement NetworkConnection methods
+ // Only actually use those relating to idle timeouts
+ //-------------------------------------------------------------------------
+
+ @Override
+ public Sender<ByteBuffer> getSender()
+ {
+ return null;
+ }
+
+ @Override
+ public void start()
+ {
+ }
+
+ @Override
+ public void close()
+ {
+ }
+
+ @Override
+ public SocketAddress getRemoteAddress()
+ {
+ return null;
+ }
+
+ @Override
+ public SocketAddress getLocalAddress()
+ {
+ return null;
+ }
+
+ @Override
+ public void setMaxWriteIdle(int sec)
+ {
+ _maxWriteIdle = sec;
+ }
+
+ @Override
+ public void setMaxReadIdle(int sec)
+ {
+ _maxReadIdle = sec;
+ }
+
+ @Override
+ public void setPeerPrincipal(Principal principal)
+ {
+ }
+
+ @Override
+ public Principal getPeerPrincipal()
+ {
+ return null;
+ }
+
+ @Override
+ public int getMaxReadIdle()
+ {
+ return _maxReadIdle;
+ }
+
+ @Override
+ public int getMaxWriteIdle()
+ {
+ return _maxWriteIdle;
+ }
+}