diff options
| author | Kim van der Riet <kpvdr@apache.org> | 2013-02-28 16:14:30 +0000 | 
|---|---|---|
| committer | Kim van der Riet <kpvdr@apache.org> | 2013-02-28 16:14:30 +0000 | 
| commit | 9c73ef7a5ac10acd6a50d5d52bd721fc2faa5919 (patch) | |
| tree | 2a890e1df09e5b896a9b4168a7b22648f559a1f2 /java/common | |
| parent | 172d9b2a16cfb817bbe632d050acba7e31401cd2 (diff) | |
| download | qpid-python-asyncstore.tar.gz | |
Update from trunk r1375509 through r1450773asyncstore
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/asyncstore@1451244 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/common')
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 <constant> 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 <constant> 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 <constant> 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 <constant> declaration. +     * @param value   Constant value as defined by the value attribute of the <constant> 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 <constant> 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 <constant> 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 <constant> 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 <constant> 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; +    } +}  | 
