diff options
Diffstat (limited to 'java/common/gentools/src')
41 files changed, 8645 insertions, 0 deletions
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); +} |