From 4bddf9b38cb29b2528a66305ca6acfd5f09067cc Mon Sep 17 00:00:00 2001 From: Kim van der Riet Date: Wed, 18 Oct 2006 18:13:01 +0000 Subject: Initial checkin of code generator (Java only at this stage) which allows for the simultaneous support of multiple AMQP versions. This is a temporary location, for comment and evaluation purposes only. This generator is NOT integrated with the rest of the QPID project; it is intended for stand-alone use only for now. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@465322 13f79535-47bb-0310-9956-ffa450edef68 --- gentools/org/apache/qpid/gentools/AmqpClass.java | 119 ++ .../org/apache/qpid/gentools/AmqpClassMap.java | 26 + gentools/org/apache/qpid/gentools/AmqpDomain.java | 80 ++ .../org/apache/qpid/gentools/AmqpDomainMap.java | 116 ++ gentools/org/apache/qpid/gentools/AmqpField.java | 129 ++ .../org/apache/qpid/gentools/AmqpFieldMap.java | 271 ++++ gentools/org/apache/qpid/gentools/AmqpMethod.java | 97 ++ .../org/apache/qpid/gentools/AmqpMethodMap.java | 26 + gentools/org/apache/qpid/gentools/AmqpModel.java | 74 + .../org/apache/qpid/gentools/AmqpOrdinalMap.java | 9 + .../apache/qpid/gentools/AmqpParseException.java | 27 + .../qpid/gentools/AmqpTemplateException.java | 10 + .../qpid/gentools/AmqpTypeMappingException.java | 27 + gentools/org/apache/qpid/gentools/AmqpVersion.java | 54 + .../org/apache/qpid/gentools/AmqpVersionSet.java | 31 + .../org/apache/qpid/gentools/CppGenerator.java | 217 +++ gentools/org/apache/qpid/gentools/Generator.java | 402 ++++++ .../org/apache/qpid/gentools/JavaGenerator.java | 1451 ++++++++++++++++++++ .../apache/qpid/gentools/LanguageConverter.java | 33 + gentools/org/apache/qpid/gentools/Main.java | 168 +++ gentools/org/apache/qpid/gentools/NodeAware.java | 42 + gentools/org/apache/qpid/gentools/Printable.java | 25 + .../qpid/gentools/TargetDirectoryException.java | 27 + gentools/org/apache/qpid/gentools/Utils.java | 210 +++ 24 files changed, 3671 insertions(+) create mode 100644 gentools/org/apache/qpid/gentools/AmqpClass.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpClassMap.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpDomain.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpDomainMap.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpField.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpFieldMap.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpMethod.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpMethodMap.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpModel.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpOrdinalMap.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpParseException.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpTemplateException.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpTypeMappingException.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpVersion.java create mode 100644 gentools/org/apache/qpid/gentools/AmqpVersionSet.java create mode 100644 gentools/org/apache/qpid/gentools/CppGenerator.java create mode 100644 gentools/org/apache/qpid/gentools/Generator.java create mode 100644 gentools/org/apache/qpid/gentools/JavaGenerator.java create mode 100644 gentools/org/apache/qpid/gentools/LanguageConverter.java create mode 100644 gentools/org/apache/qpid/gentools/Main.java create mode 100644 gentools/org/apache/qpid/gentools/NodeAware.java create mode 100644 gentools/org/apache/qpid/gentools/Printable.java create mode 100644 gentools/org/apache/qpid/gentools/TargetDirectoryException.java create mode 100644 gentools/org/apache/qpid/gentools/Utils.java (limited to 'gentools/org/apache') diff --git a/gentools/org/apache/qpid/gentools/AmqpClass.java b/gentools/org/apache/qpid/gentools/AmqpClass.java new file mode 100644 index 0000000000..4ded7db94a --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpClass.java @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.Iterator; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class AmqpClass implements Printable, NodeAware +{ + public LanguageConverter converter; + public AmqpVersionSet versionList; + public AmqpFieldMap fieldMap; + public AmqpMethodMap methodMap; + public String name; + public AmqpOrdinalMap indexMap; + + public AmqpClass(String name, LanguageConverter converter) + { + this.name = name; + this.converter = converter; + versionList = new AmqpVersionSet(); + fieldMap = new AmqpFieldMap(); + methodMap = new AmqpMethodMap(); + indexMap = new AmqpOrdinalMap(); + } + + public void addFromNode(Node classNode, int ordinal, AmqpVersion version) + throws AmqpParseException, AmqpTypeMappingException + { + versionList.add(version); + int index = Utils.getNamedIntegerAttribute(classNode, "index"); + AmqpVersionSet versionSet = indexMap.get(index); + if (versionSet != null) + versionSet.add(version); + else + { + versionSet = new AmqpVersionSet(); + versionSet.add(version); + indexMap.put(index, versionSet); + } + NodeList nList = classNode.getChildNodes(); + int fieldCntr = 0; + int methodCntr = 0; + for (int i=0; i iItr = indexMap.keySet().iterator(); + while (iItr.hasNext()) + { + int index = iItr.next(); + AmqpVersionSet indexVersionSet = indexMap.get(index); + out.println(margin + tab + "[I] " + index + indexVersionSet); + } + + Iterator sItr = fieldMap.keySet().iterator(); + while (sItr.hasNext()) + { + AmqpField thisField = fieldMap.get(sItr.next()); + thisField.print(out, marginSize + tabSize, tabSize); + } + + sItr = methodMap.keySet().iterator(); + while (sItr.hasNext()) + { + AmqpMethod thisMethod = methodMap.get(sItr.next()); + thisMethod.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpClassMap.java b/gentools/org/apache/qpid/gentools/AmqpClassMap.java new file mode 100644 index 0000000000..e86495f27e --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpClassMap.java @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpClassMap extends TreeMap +{ + +} diff --git a/gentools/org/apache/qpid/gentools/AmqpDomain.java b/gentools/org/apache/qpid/gentools/AmqpDomain.java new file mode 100644 index 0000000000..e313772a83 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpDomain.java @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.Iterator; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpDomain extends TreeMap implements Printable +{ + public String domainName; + + public AmqpDomain(String domainName) + { + this.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 v) + throws AmqpTypeMappingException + { + Iterator i = keySet().iterator(); + while (i.hasNext()) + { + String type = i.next(); + AmqpVersionSet vs = get(type); + if (vs.contains(v)) + return type; + } throw new AmqpTypeMappingException("Unable to find version " + v + "."); + } + + 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 + domainName + ":"); + + Iterator i = keySet().iterator(); + while (i.hasNext()) + { + String type = i.next(); + AmqpVersionSet vs = get(type); + out.println(margin + tab + type + " : " + vs.toString()); + } + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpDomainMap.java b/gentools/org/apache/qpid/gentools/AmqpDomainMap.java new file mode 100644 index 0000000000..88cc9a17b3 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpDomainMap.java @@ -0,0 +1,116 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.Iterator; +import java.util.TreeMap; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +@SuppressWarnings("serial") +public class AmqpDomainMap extends TreeMap implements Printable, NodeAware +{ + public LanguageConverter converter; + + public AmqpDomainMap(LanguageConverter converter) + { + this.converter = converter; + this.converter.setDomainMap(this); + } + + public void addFromNode(Node n, int o, AmqpVersion v) + throws AmqpParseException, AmqpTypeMappingException + { + NodeList nl = n.getChildNodes(); + for (int i=0; i for all domains + if (c.getNodeName().compareTo(Utils.ELEMENT_DOMAIN) == 0) + { + String domainName = converter.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 for all complex domains and use + // attribute 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 = converter.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); + } + } + } + + public String getDomainType(String domainName, AmqpVersion v) + throws AmqpTypeMappingException + { + AmqpDomain domain = get(domainName); + // For AMQP 8.0, primitive types were not described as domains, so + // return itself as the type. + if (domain == null) + return converter.getDomainType(domainName, v); + try + { + return domain.getDomainType(v); + } + catch (AmqpTypeMappingException e) + { + throw new AmqpTypeMappingException("Unable to find domain type for domain \"" + domainName + + "\" version " + v + "."); + } + } + + + public void print(PrintStream out, int marginSize, int tabSize) + { + Iterator i = keySet().iterator(); + out.println(Utils.createSpaces(marginSize) + "Domain Map:"); + while (i.hasNext()) + { + String domainName = i.next(); + AmqpDomain domain = get(domainName); + domain.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpField.java b/gentools/org/apache/qpid/gentools/AmqpField.java new file mode 100644 index 0000000000..a46c424887 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpField.java @@ -0,0 +1,129 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeMap; + +import org.w3c.dom.Node; + +public class AmqpField implements Printable, NodeAware +{ + public LanguageConverter converter; + public AmqpVersionSet versionSet; + public TreeMap domainMap; + public AmqpOrdinalMap ordinalMap; + public String name; + + public AmqpField(String name, LanguageConverter converter) + { + this.name = name; + this.converter = converter; + versionSet = new AmqpVersionSet(); + domainMap = new TreeMap(); + ordinalMap = new AmqpOrdinalMap(); + } + + public void 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 = converter.prepareDomainName(Utils.getNamedAttribute(fieldNode, Utils.ATTRIBUTE_DOMAIN)); + } + catch (AmqpParseException e) + { + domainType = converter.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); + } + 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); + } + + public boolean isCodeTypeConsistent(Generator generator) + throws AmqpTypeMappingException + { + if (domainMap.size() == 1) + return true; // By definition + ArrayList codeTypeList = new ArrayList(); + Iterator itr = domainMap.keySet().iterator(); + while (itr.hasNext()) + { + String domainName = itr.next(); + AmqpVersionSet versionSet = domainMap.get(domainName); + String codeType = generator.getGeneratedType(domainName, 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; + Iterator itr = domainMap.keySet().iterator(); + while (itr.hasNext()) + vCntr += domainMap.get(itr.next()).size(); + return vCntr == generator.globalVersionSet.size(); + } + + public void print(PrintStream out, int marginSize, int tabSize) + { + String margin = Utils.createSpaces(marginSize); + out.println(margin + "[F] " + name + ": " + versionSet); + + Iterator iItr = ordinalMap.keySet().iterator(); + while (iItr.hasNext()) + { + Integer ordinalValue = iItr.next(); + AmqpVersionSet versionList = ordinalMap.get(ordinalValue); + out.println(margin + " [O] " + ordinalValue + " : " + versionList.toString()); + } + + Iterator sItr = domainMap.keySet().iterator(); + while (sItr.hasNext()) + { + String domainKey = sItr.next(); + AmqpVersionSet versionList = domainMap.get(domainKey); + out.println(margin + " [D] " + domainKey + " : " + versionList.toString()); + } + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpFieldMap.java b/gentools/org/apache/qpid/gentools/AmqpFieldMap.java new file mode 100644 index 0000000000..8e7421b45a --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpFieldMap.java @@ -0,0 +1,271 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpFieldMap extends TreeMap +{ + public AmqpFieldMap getFieldMapForOrdinal(int ordinal) + { + AmqpFieldMap newMap = new AmqpFieldMap(); + Iterator i = keySet().iterator(); + while (i.hasNext()) + { + String fieldName = i.next(); + AmqpField field = get(fieldName); + TreeMap ordinalMap = field.ordinalMap; + AmqpVersionSet ordinalVersions = ordinalMap.get(ordinal); + if (ordinalVersions != null) + newMap.put(fieldName, field); + } + return newMap; + } + + public boolean isDomainConsistent(Generator generator, AmqpVersionSet versionSet) + throws AmqpTypeMappingException + { + if (size() != 1) // Only one field for this ordinal + return false; + return get(firstKey()).isConsistent(generator); + } + + public int getNumFields(AmqpVersion version) + { + int fCntr = 0; + Iterator fItr = keySet().iterator(); + while (fItr.hasNext()) + { + AmqpField field = get(fItr.next()); + if (field.versionSet.contains(version)) + fCntr++; + } + return fCntr; + } + + public String parseFieldMap(Method commonGenerateMethod, Method mangledGenerateMethod, + int indentSize, int tabSize, Generator codeGenerator) + throws AmqpTypeMappingException, IllegalAccessException, InvocationTargetException + { + String indent = Utils.createSpaces(indentSize); + String cr = Utils.lineSeparator; + 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 itr = keySet().iterator(); + while (itr.hasNext()) + { + String fieldName = itr.next(); + AmqpField field = get(fieldName); + if (field.isCodeTypeConsistent(codeGenerator)) + { + // All versions identical - Common declaration + String domainName = field.domainMap.firstKey(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = codeGenerator.getGeneratedType(domainName, versionSet.first()); + if (commonGenerateMethod != null) + sb.append(commonGenerateMethod.invoke(codeGenerator, codeType, field, versionSet, + indentSize, tabSize, itr.hasNext())); + } + else if (mangledGenerateMethod != null) // Version-mangled + { + sb.append(mangledGenerateMethod.invoke(codeGenerator, field, indentSize, tabSize, + itr.hasNext())); + } + } + return sb.toString(); + } + + public String parseFieldMapOrdinally(Method generateMethod, Method bitGenerateMethod, + int indentSize, int tabSize, Generator codeGenerator) +// int indentSize, int tabSize, AmqpVersionSet versionSet, AmqpDomainMap globalDomainMap) + throws AmqpTypeMappingException, IllegalAccessException, InvocationTargetException + { + String indent = Utils.createSpaces(indentSize); + String cr = Utils.lineSeparator; + 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 bitFieldList = new ArrayList(); + 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, codeGenerator.globalVersionSet)) + { + String fieldName = ordinalFieldMap.firstKey(); + String domain = ordinalFieldMap.get(fieldName).domainMap.firstKey(); + String domainType = codeGenerator.getDomainType(domain, + codeGenerator.globalVersionSet.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.invoke(codeGenerator, 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.invoke(codeGenerator, 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[codeGenerator.globalVersionSet.size()]; + codeGenerator.globalVersionSet.toArray(versionArray); + for (int v=0; 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 bitFieldList2 = new ArrayList(bitFieldList); + for (int o = ordinal; o 0) + { + // 3. Cycle through each of the fields that have this ordinal. + Iterator i = ordinalFieldMap.keySet().iterator(); + while (i.hasNext()) + { + String fieldName = i.next(); + AmqpField field = ordinalFieldMap.get(fieldName); + + // 4. Some fields may have more than one ordinal - match by both + // ordinal and version. + Iterator j = field.ordinalMap.keySet().iterator(); + while (j.hasNext()) + { + int thisOrdinal = j.next(); + AmqpVersionSet v1 = field.ordinalMap.get(thisOrdinal); + if (thisOrdinal == o && v1.contains(versionArray[v])) + { + // 5. Now get the domain for this version + int domainCntr = 0; + Iterator k = field.domainMap.keySet().iterator(); + while (k.hasNext()) + { + // Mangle domain-divergent field names + String mangledFieldName = fieldName; + if (field.domainMap.size() > 1) + mangledFieldName += "_" + (domainCntr++); + String domainName = k.next(); + AmqpVersionSet v2 = field.domainMap.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.invoke(codeGenerator, + 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.invoke(codeGenerator, domainType, + mangledFieldName, o, indentSize + tabSize, tabSize)); + } + } + } + } + } + } + } + // Check for remaining deferred bits + if (bitFieldList2.size() > 0 && bitGenerateMethod != null) + sb.append(bitGenerateMethod.invoke(codeGenerator, bitFieldList2, size(), + indentSize + tabSize, tabSize)); + sb.append(indent + "}" + cr); + } + } + // Check for remaining deferred bits + else if (bitFieldList.size() > 0 && bitGenerateMethod != null) + sb.append(bitGenerateMethod.invoke(codeGenerator, bitFieldList, size(), + indentSize, tabSize)); + return sb.toString(); + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpMethod.java b/gentools/org/apache/qpid/gentools/AmqpMethod.java new file mode 100644 index 0000000000..37c254e32c --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpMethod.java @@ -0,0 +1,97 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.Iterator; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class AmqpMethod implements Printable, NodeAware +{ + public LanguageConverter converter; + public AmqpVersionSet versionSet; + public AmqpFieldMap fieldMap; + public String name; + public AmqpOrdinalMap indexMap; + + public AmqpMethod(String name, LanguageConverter converter) + { + this.name = name; + this.converter = converter; + versionSet = new AmqpVersionSet(); + fieldMap = new AmqpFieldMap(); + indexMap = new AmqpOrdinalMap(); + } + + public void addFromNode(Node methodNode, int ordinal, AmqpVersion version) + throws AmqpParseException, AmqpTypeMappingException + { + versionSet.add(version); + int index = Utils.getNamedIntegerAttribute(methodNode, "index"); + AmqpVersionSet versionSet = indexMap.get(index); + if (versionSet != null) + versionSet.add(version); + else + { + versionSet = new AmqpVersionSet(); + versionSet.add(version); + indexMap.put(index, versionSet); + } + NodeList nList = methodNode.getChildNodes(); + int fieldCntr = 0; + for (int i=0; i iItr = indexMap.keySet().iterator(); + while (iItr.hasNext()) + { + int index = iItr.next(); + AmqpVersionSet indexVersionSet = indexMap.get(index); + out.println(margin + tab + "[I] " + index + indexVersionSet); + } + + Iterator sItr = fieldMap.keySet().iterator(); + while (sItr.hasNext()) + { + AmqpField thisField = fieldMap.get(sItr.next()); + thisField.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpMethodMap.java b/gentools/org/apache/qpid/gentools/AmqpMethodMap.java new file mode 100644 index 0000000000..07e236d2cd --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpMethodMap.java @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpMethodMap extends TreeMap +{ + +} diff --git a/gentools/org/apache/qpid/gentools/AmqpModel.java b/gentools/org/apache/qpid/gentools/AmqpModel.java new file mode 100644 index 0000000000..f379674f49 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpModel.java @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +import java.util.Iterator; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class AmqpModel implements Printable, NodeAware +{ + public LanguageConverter converter; + public AmqpClassMap classMap; + + public AmqpModel(LanguageConverter converter) + { + this.converter = converter; + this.converter.setModel(this); + classMap = new AmqpClassMap(); + } + + public void addFromNode(Node n, int o, AmqpVersion v) + throws AmqpParseException, AmqpTypeMappingException + { + NodeList nList = n.getChildNodes(); + int eCntr = 0; + for (int i=0; i i = classMap.keySet().iterator(); + while (i.hasNext()) + { + String className = i.next(); + AmqpClass thisClass = classMap.get(className); + thisClass.print(out, marginSize + tabSize, tabSize); + } + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpOrdinalMap.java b/gentools/org/apache/qpid/gentools/AmqpOrdinalMap.java new file mode 100644 index 0000000000..a340376d0e --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpOrdinalMap.java @@ -0,0 +1,9 @@ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +@SuppressWarnings("serial") +public class AmqpOrdinalMap extends TreeMap +{ + +} diff --git a/gentools/org/apache/qpid/gentools/AmqpParseException.java b/gentools/org/apache/qpid/gentools/AmqpParseException.java new file mode 100644 index 0000000000..2a85001f99 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpParseException.java @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class AmqpParseException extends Exception +{ + public AmqpParseException(String msg) + { + super(msg); + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpTemplateException.java b/gentools/org/apache/qpid/gentools/AmqpTemplateException.java new file mode 100644 index 0000000000..c0a3edb207 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpTemplateException.java @@ -0,0 +1,10 @@ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class AmqpTemplateException extends Exception +{ + public AmqpTemplateException(String msg) + { + super(msg); + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpTypeMappingException.java b/gentools/org/apache/qpid/gentools/AmqpTypeMappingException.java new file mode 100644 index 0000000000..b2304344c6 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpTypeMappingException.java @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +@SuppressWarnings("serial") +public class AmqpTypeMappingException extends Exception +{ + public AmqpTypeMappingException(String msg) + { + super(msg); + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpVersion.java b/gentools/org/apache/qpid/gentools/AmqpVersion.java new file mode 100644 index 0000000000..f3f4f5833b --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpVersion.java @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +public class AmqpVersion implements Comparable +{ + private int major; + private int minor; + + public AmqpVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + public int getMajor() + { + return major; + } + + public int getMinor() + { + return minor; + } + + public int compareTo(AmqpVersion v) + { + if (major != v.major) + return major - v.major; + if (minor != v.minor) + return minor - v.minor; + return 0; + } + + public String toString() + { + return major + "-" + minor; + } +} diff --git a/gentools/org/apache/qpid/gentools/AmqpVersionSet.java b/gentools/org/apache/qpid/gentools/AmqpVersionSet.java new file mode 100644 index 0000000000..608a319146 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/AmqpVersionSet.java @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.PrintStream; +//import java.util.ArrayList; +import java.util.TreeSet; + +@SuppressWarnings("serial") +public class AmqpVersionSet extends TreeSet implements Printable +{ + public void print(PrintStream out, int marginSize, int tabSize) + { + out.print(Utils.createSpaces(marginSize) + "Version Set: " + toString()); + } +} diff --git a/gentools/org/apache/qpid/gentools/CppGenerator.java b/gentools/org/apache/qpid/gentools/CppGenerator.java new file mode 100644 index 0000000000..3405e48984 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/CppGenerator.java @@ -0,0 +1,217 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.util.TreeMap; + +public class CppGenerator extends Generator +{ + private class DomainInfo + { + public String type; + public String size; + public DomainInfo(String domain, String size) + { + this.type = domain; + this.size = size; + } + } + + private static TreeMap typeMap = new TreeMap(); + + public CppGenerator(AmqpVersionSet versionList) + { + super(versionList); + // 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. + typeMap.put("bit", new DomainInfo( + "bool", // domain + "1")); // size + typeMap.put("long", new DomainInfo( + "u_int32_t", // domain + "4")); // size + typeMap.put("longlong", new DomainInfo( + "u_int64_t", // domain + "8")); // size + typeMap.put("longstr", new DomainInfo( + "string", // domain + "4 + #.length()")); // size + typeMap.put("octet", new DomainInfo( + "u_int8_t", // domain + "1")); // size + typeMap.put("short", new DomainInfo( + "u_int16_t", // domain + "2")); // size + typeMap.put("shortstr", new DomainInfo( + "string", // domain + "1 + #.length()")); // size + typeMap.put("table", new DomainInfo( + "FieldTable", // domain + "#.size()")); // size + typeMap.put("timestamp", new DomainInfo( + "u_int64_t", // domain + "8")); // 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 getDomainType(String domainType, AmqpVersion version) + throws AmqpTypeMappingException + { + String domain = globalDomainMap.getDomainType(domainType, version); + String type = typeMap.get(domain).type; + if (type == null) + throw new AmqpTypeMappingException("Domain type \"" + domainType + "\" not found in Java typemap."); + return type; + } + + public String getGeneratedType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + String domainType = getDomainType(domainName, version); + return typeMap.get(domainType).type; + } + + // === Abstract methods from class Generator - C++-specific implementation === + + @Override + protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method, + AmqpField field) + { + StringBuffer sb = new StringBuffer(filenameTemplate); + if (thisClass != null) + replaceToken(sb, "${CLASS}", thisClass.name); + if (method != null) + replaceToken(sb, "${METHOD}", method.name); + if (field != null) + replaceToken(sb, "${FIELD}", field.name); + return sb.toString(); + } + + @Override + protected String processToken(String snipitKey, AmqpClass thisClass, AmqpMethod method, AmqpField field) + throws AmqpTemplateException + { + if (snipitKey.compareTo("${property_flags_initializer}") == 0) + { + StringBuffer sb = new StringBuffer(); + // TODO + return sb.toString(); + } + throw new AmqpTemplateException("Template token " + snipitKey + " unknown."); + } + + @Override + protected void processClassList(StringBuffer sb, int tokStart, int tokEnd, AmqpModel model) + throws AmqpTemplateException + { +// TODO + } + + @Override + protected void processMethodList(StringBuffer sb, int tokStart, int tokEnd, AmqpClass thisClass) + throws AmqpTemplateException + { +// TODO + } + + @Override + protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpFieldMap fieldMap) + throws AmqpTypeMappingException, AmqpTemplateException + { +// TODO + } + +// @Override +// protected String generateFieldDeclaration(AmqpFieldMap fieldMap, int indentSize) +// throws AmqpTypeMappingException +// { +// String indent = Utils.createSpaces(indentSize); +// StringBuffer sb = new StringBuffer(indent + "// [FieldDeclaration]" + Utils.lineSeparator); +// // TODO +// return sb.toString(); +// } +// +// @Override +// protected String generateFieldGetMethod(AmqpFieldMap fieldMap, int indentSize, int tabSize) +// throws AmqpTypeMappingException +// { +// String indent = Utils.createSpaces(indentSize); +//// String tab = Utils.createSpaces(tabSize); +// StringBuffer sb = new StringBuffer(indent + "// [FieldGetMethod]" + Utils.lineSeparator); +// // TODO +// return sb.toString(); +// } +// +// @Override +// protected String generateContentHeaderGetSetMethod(AmqpFieldMap fieldMap, int indentSize, +// int tabSize) +// throws AmqpTypeMappingException +// { +// String indent = Utils.createSpaces(indentSize); +//// String tab = Utils.createSpaces(tabSize); +// StringBuffer sb = new StringBuffer(indent + "// Property get/set methods" + Utils.lineSeparator); +// // TODO +// return sb.toString(); +// } +// +// @Override +// protected String generateCodeSnippet(String token, AmqpFieldMap fieldMap, int indentSize, +// int tabSize) +// throws AmqpTypeMappingException +// { +// String indent = Utils.createSpaces(indentSize); +//// String tab = Utils.createSpaces(tabSize); +// StringBuffer sb = new StringBuffer(indent + "// [Code snippet " + token + "]" + Utils.lineSeparator); +// // TODO +// return sb.toString(); +// } + + // Private helper functions unique to C++ + + private String camelCaseName(String name, boolean upperFirstFlag) + { + StringBuffer ccn = new StringBuffer(); + String[] toks = name.split("[-_.\\ ]"); + for (int i=0; i0) + b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0))); + ccn.append(b); + } + return ccn.toString(); + } +} diff --git a/gentools/org/apache/qpid/gentools/Generator.java b/gentools/org/apache/qpid/gentools/Generator.java new file mode 100644 index 0000000000..db75599b45 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/Generator.java @@ -0,0 +1,402 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.LineNumberReader; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Set; + +public abstract class Generator implements LanguageConverter +{ + // This string is reproduced in every generated file as a comment + // TODO: Tie the version info into the build system. + protected static final String generatorInfo = "Qpid Gentools v.0.1"; + + protected ArrayList modelTemplateList; + protected ArrayList classTemplateList; + protected ArrayList methodTemplateList; + protected ArrayList fieldTemplateList; + protected String genDir; + + protected AmqpVersionSet globalVersionSet; + protected AmqpDomainMap globalDomainMap; + protected AmqpModel model; + + protected int generatedFileCounter; + + public Generator(AmqpVersionSet versionList) + { + this.globalVersionSet = versionList; + modelTemplateList = new ArrayList(); + classTemplateList = new ArrayList(); + methodTemplateList = new ArrayList(); + fieldTemplateList = new ArrayList(); + generatedFileCounter = 0; + } + + public int getNumberGeneratedFiles() + { + return generatedFileCounter; + } + + public void setDomainMap(AmqpDomainMap domainMap) + { + this.globalDomainMap = domainMap; + } + + public AmqpDomainMap getDomainMap() + { + return globalDomainMap; + } + + public void setModel(AmqpModel model) + { + this.model = model; + } + + public AmqpModel getModel() + { + return model; + } + + public void initializeTemplates(File[] modelTemplateFiles, File[] classTemplatesFiles, + File[] methodTemplatesFiles, File[] fieldTemplatesFiles) + throws FileNotFoundException, IOException + { + if (modelTemplateFiles.length > 0) + { + System.out.println("Model template file(s):"); + for (int t=0; t 0) + { + System.out.println("Class template file(s):"); + for (int c=0; c 0) + { + System.out.println("Method template file(s):"); + for (int m=0; m 0) + { + System.out.println("Field template file(s):"); + for (int f=0; f ckeys = model.classMap.keySet(); + Iterator citr = ckeys.iterator(); + while (citr.hasNext()) + { + String className = citr.next(); + AmqpClass thisClass = model.classMap.get(className); + + // Use all class-level templates + for (int c = 0; c < classTemplateList.size(); c++) + { + processTemplate(classTemplateList.get(c), thisClass, null, null); + } + + // Cycle through all methods + Set mkeys = thisClass.methodMap.keySet(); + Iterator mitr = mkeys.iterator(); + while (mitr.hasNext()) + { + String methodName = mitr.next(); + AmqpMethod method = thisClass.methodMap.get(methodName); + + // Use all method-level templates + for (int m = 0; m < methodTemplateList.size(); m++) + { + processTemplate(methodTemplateList.get(m), thisClass, method, null); + } + + // Cycle through all fields + Set fkeys = method.fieldMap.keySet(); + Iterator fitr = fkeys.iterator(); + while (fitr.hasNext()) + { + String fieldName = fitr.next(); + AmqpField field = method.fieldMap.get(fieldName); + + // Use all field-level templates + for (int f = 0; f < fieldTemplateList.size(); f++) + { + processTemplate(fieldTemplateList.get(f), thisClass, method, field); + } + } + } + } + } + + abstract protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method, + AmqpField field); + + abstract protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, AmqpField field) + throws AmqpTemplateException; + + abstract protected void processClassList(StringBuffer sb, int tokStart, int tokEnd, AmqpModel model) + throws AmqpTemplateException; + + abstract protected void processMethodList(StringBuffer sb, int tokStart, int tokEnd, AmqpClass thisClass) + throws AmqpTemplateException; + + abstract protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpFieldMap fieldMap) + throws AmqpTypeMappingException, AmqpTemplateException, IllegalAccessException, + InvocationTargetException; + + protected void processVersionList(StringBuffer sb, int tokStart, int tokEnd) + throws AmqpTypeMappingException + { + int lend = sb.indexOf(Utils.lineSeparator, tokStart) + 1; // Include cr at end of line + String tline = sb.substring(tokEnd, lend); // Line excluding line marker, including cr + sb.delete(tokStart, lend); + AmqpVersion[] versionArray = new AmqpVersion[globalVersionSet.size()]; + globalVersionSet.toArray(versionArray); + for (int i=0; i 0) + { + String listToken = sb.substring(lstart + 2, lend); + if (listToken.compareTo("VLIST") == 0) + { + processVersionList(sb, lstart, lend + 1); + } + else if (listToken.compareTo("CLIST") == 0) + { + processClassList(sb, lstart, lend + 1, model); + } + else if (listToken.compareTo("MLIST") == 0) + { + processMethodList(sb, lstart, lend + 1, thisClass); + } + else if (listToken.compareTo("FLIST") == 0) + { + // Pass the FieldMap from either a class or a method. + // If this is called from a class-level template, we assume that the + // class field list is required. In this case, method will be null. + processFieldList(sb, lstart, lend + 1, + (method == null ? thisClass.fieldMap : method.fieldMap)); + } + 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) + throws AmqpTemplateException + { + 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)); + } + lstart = sb.indexOf("${", lstart); + } + } + + protected static void writeTargetFile(StringBuffer sb, File f) + throws IOException + { + FileWriter fw = new FileWriter(f); + fw.write(sb.toString().toCharArray()); + fw.flush(); + fw.close(); + } + + protected static String getTemplateFileName(StringBuffer sb) + throws AmqpTemplateException + { + if (sb.charAt(0) != '&') + throw new AmqpTemplateException("No filename marker &{filename} found at start of template."); + int cr = sb.indexOf(Utils.lineSeparator); + if (cr < 0) + throw new AmqpTemplateException("Bad template structure - unable to find first line."); + String fileName = sb.substring(2, cr-1); + sb.delete(0, cr + 1); + return fileName; + } + + protected static void replaceToken(StringBuffer sb, String token, String replacement) + { + replaceToken(sb, 0, token, replacement); + } + + protected static void replaceToken(StringBuffer sb, int index, String token, String replacement) + { + if (replacement != null) + { + int start = sb.indexOf(token, index); + int len = token.length(); + // Find first letter in token and determine if it is capitalized + char firstTokenLetter = getFirstLetter(token); + if (firstTokenLetter != 0 && Character.isUpperCase(firstTokenLetter)) + sb.replace(start, start+len, Utils.firstUpper(replacement)); + else + sb.replace(start, start+len, replacement); + } + } + + private static char getFirstLetter(String str) + { + int len = str.length(); + int index = 0; + char tokChar = str.charAt(index); + while (!Character.isLetter(tokChar) && index 0 && line.charAt(0) != '#') + sb.append(line + Utils.lineSeparator); + else + sb.append(Utils.lineSeparator); + line = lnr.readLine(); + } + lnr.close(); + fr.close(); + return sb.toString(); + } +} diff --git a/gentools/org/apache/qpid/gentools/JavaGenerator.java b/gentools/org/apache/qpid/gentools/JavaGenerator.java new file mode 100644 index 0000000000..dc19d0e14a --- /dev/null +++ b/gentools/org/apache/qpid/gentools/JavaGenerator.java @@ -0,0 +1,1451 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.TreeMap; + +public class JavaGenerator extends Generator +{ + static String cr = Utils.lineSeparator; + + 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 typeMap = new TreeMap(); + + // Methods used for generation of code snippets called from the field map parsers + + // Common methods + static private Method declarationGenerateMethod; + static private Method mangledDeclarationGenerateMethod; + + // Methods for MessageBody classes + static private Method mbGetGenerateMethod; + static private Method mbMangledGetGenerateMethod; + static private Method mbParamListGenerateMethod; + static private Method mbMangledParamListGenerateMethod; + static private Method mbBodyInitGenerateMethod; + static private Method mbMangledBodyInitGenerateMethod; + static private Method mbSizeGenerateMethod; + static private Method mbBitSizeGenerateMethod; + static private Method mbEncodeGenerateMethod; + static private Method mbBitEncodeGenerateMethod; + static private Method mbDecodeGenerateMethod; + static private Method mbBitDecodeGenerateMethod; + static private Method mbToStringGenerateMethod; + static private Method mbBitToStringGenerateMethod; + + // Methods for PropertyContentHeader classes + static private Method pchClearGenerateMethod; + static private Method pchMangledClearGenerateMethod; + static private Method pchGetGenerateMethod; + static private Method pchMangledGetGenerateMethod; + static private Method pchSetGenerateMethod; + static private Method pchMangledSetGenerateMethod; + static private Method pchSizeGenerateMethod; + static private Method pchBitSizeGenerateMethod; + static private Method pchEncodeGenerateMethod; + static private Method pchBitEncodeGenerateMethod; + static private Method pchDecodeGenerateMethod; + static private Method pchBitDecodeGenerateMethod; + static private Method pchGetPropertyFlagsGenerateMethod; + static private Method pchBitGetPropertyFlagsGenerateMethod; + static private Method pchSetPropertyFlagsGenerateMethod; + static private Method pchBitSetPropertyFlagsGenerateMethod; + + static + { + // ************** + // Common methods + // ************** + + // Methods for AmqpFieldMap.parseFieldMap() + + try { declarationGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateFieldDeclaration", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mangledDeclarationGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMangledFieldDeclaration", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + + // ******************************* + // Methods for MessageBody classes + // ******************************* + + // Methods for AmqpFieldMap.parseFieldMap() + + try { mbGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbGetMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledGetMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbParamListGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbParamList", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledParamListGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledParamList", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBodyInitGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBodyInit", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbMangledBodyInitGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbMangledBodyInit", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + // Methods for AmqpFieldMap.parseFieldMapOrdinally() + + try { mbSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldSize", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitArrayFieldSize", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldEncode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitFieldEncode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldDecode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitFieldDecode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbToStringGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbFieldToString", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { mbBitToStringGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generateMbBitFieldToString", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + // ***************************************** + // Methods for PropertyContentHeader classes + // ***************************************** + + // Methods for AmqpFieldMap.parseFieldMap() + + try { pchClearGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchClearMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchMangledClearGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchMangledClearMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchSetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchSetMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchMangledSetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchMangledSetMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchGetMethod", String.class, AmqpField.class, + AmqpVersionSet.class, int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchMangledGetGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchMangledGetMethod", AmqpField.class, + int.class, int.class, boolean.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + // Methods for AmqpFieldMap.parseFieldMapOrdinally() + + try { pchSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchFieldSize", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitSizeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitArrayFieldSize", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchFieldEncode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitEncodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitFieldEncode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchFieldDecode", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitDecodeGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitFieldDecode", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchGetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchGetPropertyFlags", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitGetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitGetPropertyFlags", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchSetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchSetPropertyFlags", String.class, String.class, + int.class, int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + + try { pchBitSetPropertyFlagsGenerateMethod = JavaGenerator.class.getDeclaredMethod( + "generatePchBitSetPropertyFlags", ArrayList.class, int.class, + int.class, int.class); } + catch (NoSuchMethodException e) { e.printStackTrace(); } + } + + public JavaGenerator(AmqpVersionSet versionList) + { + super(versionList); + // 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 + "EncodingUtils.writeBooleans(buffer, #)", // encode expression + "# = EncodingUtils.readBooleans(buffer)")); // decode expression + typeMap.put("long", new DomainInfo( + "long", // Java code type + "4", // size + "EncodingUtils.writeUnsignedInteger(buffer, #)", // encode expression + "# = buffer.getUnsignedInt()")); // decode expression + typeMap.put("longlong", new DomainInfo( + "long", // Java code type + "8", // size + "buffer.putLong(#)", // encode expression + "# = buffer.getLong()")); // decode expression + typeMap.put("longstr", new DomainInfo( + "String", // Java code type + "EncodingUtils.encodedLongStringLength(#)", // size + "EncodingUtils.writeLongStringBytes(buffer, #)", // encode expression + "# = EncodingUtils.readLongString(buffer)")); // decode expression + typeMap.put("octet", new DomainInfo( + "char", // Java code type + "1", // size + "buffer.putChar(#)", // encode expression + "# = buffer.getChar()")); // decode expression + typeMap.put("short", new DomainInfo( + "int", // Java code type + "2", // size + "EncodingUtils.writeUnsignedShort(buffer, #)", // encode expression + "# = buffer.getUnsignedShort()")); // decode expression + typeMap.put("shortstr", new DomainInfo( + "String", // Java code type + "EncodingUtils.encodedShortStringLength(#)", // size + "EncodingUtils.writeShortStringBytes(buffer, #)", // encode expression + "# = EncodingUtils.readShortString(buffer)")); // decode expression + typeMap.put("table", new DomainInfo( + "FieldTable", // Java code type + "EncodingUtils.encodedFieldTableLength(#)", // size + "EncodingUtils.writeFieldTableBytes(buffer, #)", // encode expression + "# = EncodingUtils.readFieldTable(buffer)")); // decode expression + typeMap.put("timestamp", new DomainInfo( + "long", // Java code type + "8", // size + "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 getDomainType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + return globalDomainMap.getDomainType(domainName, version); + } + + public String getGeneratedType(String domainName, AmqpVersion version) + throws AmqpTypeMappingException + { + String domainType = globalDomainMap.getDomainType(domainName, version); + if (domainType == null) + throw new AmqpTypeMappingException("Domain type \"" + domainName + "\" not found in Java typemap."); + return typeMap.get(domainType).type; + } + + + // === Abstract methods from class Generator - Java-specific implementations === + + @Override + protected String prepareFilename(String filenameTemplate, AmqpClass thisClass, AmqpMethod method, + AmqpField field) + { + StringBuffer sb = new StringBuffer(filenameTemplate); + if (thisClass != null) + replaceToken(sb, "${CLASS}", thisClass.name); + if (method != null) + replaceToken(sb, "${METHOD}", method.name); + if (field != null) + replaceToken(sb, "${FIELD}", field.name); + return sb.toString(); + } + + @Override + protected String processToken(String token, AmqpClass thisClass, AmqpMethod method, AmqpField field) + throws AmqpTemplateException + { + if (token.compareTo("${GENERATOR}") == 0) + return generatorInfo; + if (token.compareTo("${CLASS}") == 0 && thisClass != null) + return thisClass.name; + if (token.compareTo("${CLASS_ID_INIT}") == 0 && thisClass != null) + return generateIndexInitializer("classIdMap", thisClass.indexMap, 8); + if (token.compareTo("${METHOD}") == 0 && method != null) + return method.name; + if (token.compareTo("${METHOD_ID_INIT}") == 0 && method != null) + return generateIndexInitializer("methodIdMap", method.indexMap, 8); + if (token.compareTo("${FIELD}") == 0 && field != null) + return field.name; + + // 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.fieldMap.size() : method.fieldMap.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 tokStart, int tokEnd, AmqpModel model) + throws AmqpTemplateException + { + String codeSnippet; + int lend = sb.indexOf(cr, tokStart) + 1; // Include cr at end of line + String tline = sb.substring(tokEnd, lend); // Line excluding line marker, including cr + int tokxStart = tline.indexOf('$'); + String token = tline.substring(tokxStart).trim(); + sb.delete(tokStart, 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(tokStart, codeSnippet); + } + + @Override + protected void processMethodList(StringBuffer sb, int tokStart, int tokEnd, AmqpClass thisClass) + throws AmqpTemplateException + { + String codeSnippet; + int lend = sb.indexOf(cr, tokStart) + 1; // Include cr at end of line + String tline = sb.substring(tokEnd, lend); // Line excluding line marker, including cr + int tokxStart = tline.indexOf('$'); + String token = tline.substring(tokxStart).trim(); + sb.delete(tokStart, 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(tokStart, codeSnippet); + } + + @Override + protected void processFieldList(StringBuffer sb, int listMarkerStartIndex, int listMarkerEndIndex, + AmqpFieldMap fieldMap) + throws AmqpTypeMappingException, AmqpTemplateException, IllegalAccessException, + InvocationTargetException + { + 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); + + // 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) + { + // This is klunky... (cringe) TODO: Find a more elegant solution here sometime... + codeSnippet = fieldMap.size() > 0 ? Utils.createSpaces(42) + "," + cr : ""; + codeSnippet += fieldMap.parseFieldMap(mbParamListGenerateMethod, + mbMangledParamListGenerateMethod, 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); + } + + // === 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.name + + "; // AMQP version(s): " + versionSet + cr; + } + + protected String generateMangledFieldDeclaration(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + sb.append(Utils.createSpaces(indentSize) + "public " + codeType + " " + + field.name + "_" + (domainCntr++) + "; // AMQP Version(s): " + versionSet + + cr); + } + return sb.toString(); + } + + protected String generateIndexInitializer(String mapName, AmqpOrdinalMap indexMap, int indentSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + + Iterator iItr = indexMap.keySet().iterator(); + while (iItr.hasNext()) + { + int index = iItr.next(); + AmqpVersionSet versionSet = indexMap.get(index); + Iterator vItr = versionSet.iterator(); + while (vItr.hasNext()) + { + AmqpVersion version = vItr.next(); + sb.append(indent + mapName + ".put(\"" + version.toString() + "\", " + 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(); + + Iterator cItr = model.classMap.keySet().iterator(); + while (cItr.hasNext()) + { + AmqpClass thisClass = model.classMap.get(cItr.next()); + AmqpVersionSet firstVersionSet = thisClass.indexMap.get(thisClass.indexMap.firstKey()); + boolean classVersionConsistentFlag = firstVersionSet.equals(globalVersionSet); + Iterator mItr = thisClass.methodMap.keySet().iterator(); + while (mItr.hasNext()) + { + AmqpMethod method = thisClass.methodMap.get(mItr.next()); + firstVersionSet = method.indexMap.get(method.indexMap.firstKey()); + boolean methodVersionConsistentFlag = firstVersionSet.equals(globalVersionSet); + if (classVersionConsistentFlag && methodVersionConsistentFlag) + { + // Both class and method with consistent indeces for all known versions + int classIndex = thisClass.indexMap.firstKey(); + int methodIndex = method.indexMap.firstKey(); + sb.append(indent + "map.put(" + classIndex + "*1000 + " + methodIndex + + ", " + thisClass.name + Utils.firstUpper(method.name) + "Body.class);" + cr); + } + else + { + // Non-consistent indeces for all known versions - version-specific code required + sb.append(cr); + + Iterator vItr = globalVersionSet.iterator(); + while (vItr.hasNext()) + { + boolean first = true; + AmqpVersion version = vItr.next(); + + // Find class and method index for this version (if it exists) + try + { + int classIndex = findIndex(thisClass.indexMap, version); + int methodIndex = findIndex(method.indexMap, version); + sb.append(indent); + if (!first) + sb.append("else "); + sb.append("if ( major == " + version.getMajor() + " && minor == " + + version.getMinor() + " )" + cr); + sb.append(indent + tab + "map.put(" + classIndex + "*1000 + " + + methodIndex + ", " + thisClass.name + Utils.firstUpper(method.name) + + "Body.class);" + cr); + first = false; + } + catch (Exception e) {} // Ignore + } + sb.append(cr); + } + } + } + return sb.toString(); + } + + protected int findIndex(TreeMap map, AmqpVersion version) + throws Exception + { + Iterator iItr = map.keySet().iterator(); + while (iItr.hasNext()) + { + int index = iItr.next(); + AmqpVersionSet versionSet = map.get(index); + if (versionSet.contains(version)) + return index; + } + throw new Exception("Index not found"); + } + + // 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.name) + "() { return " + field.name + "; }" + + cr; + } + + protected String generateMbMangledGetMethod(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(cr); + sb.append(indent + "public T get" + Utils.firstUpper(field.name) + + "(Class classObj) throws AMQProtocolVersionException" + cr); + sb.append(indent + "{" + cr); + Iterator dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.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.name + "_" + + (domainCntr++) + ";" + cr); + } + sb.append(indent + tab + + "throw new AMQProtocolVersionException(\"None of the AMQP versions defines \" +" + + cr + " \"field \\\"" + field.name + + "\\\" 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.name + + (nextFlag ? "," : "") + " // AMQP version(s): " + versionSet + cr; + } + + protected String generateMbMangledParamList(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + sb.append(Utils.createSpaces(indentSize) + codeType + " " + field.name + "_" + + (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) + "body." + field.name + " = " + field.name + + ";" + cr; + } + + protected String generateMbMangledBodyInit(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + Iterator dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + dItr.next(); + sb.append(Utils.createSpaces(indentSize) + "body." + field.name + "_" + domainCntr + + " = " + field.name + "_" + (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(ArrayList 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(ArrayList bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String bitArrayName = "bitArray_" + ordinal; + StringBuffer sb = new StringBuffer(indent + "boolean[] " + bitArrayName + + " = new boolean[] { "); + for (int i=0; i bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + String bitArrayName = "bitArray_" + ordinal; + StringBuffer sb = new StringBuffer(); + sb.append(indent + + typeMap.get("bit").decodeExpression.replaceAll("#", "boolean[] " + bitArrayName) + + ";" + cr); + for (int i=0; i bitFieldList, + int ordinal, int indentSize, int tabSize) + { + String indent = Utils.createSpaces(indentSize); + StringBuffer sb = new StringBuffer(); + for (int i=0; i oItr = field.ordinalMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + AmqpVersionSet versionSet = field.ordinalMap.get(ordinal); + sb.append(indent + tab); + if (ordinal != field.ordinalMap.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) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(indent + "public " + codeType + " get" + + Utils.firstUpper(field.name) + "()" + cr); + sb.append(indent + "{" + cr); + sb.append(indent + tab + "decodeIfNecessary();" + cr); + sb.append(indent + tab + "return " + field.name + ";" + cr); + sb.append(indent + "}" + cr); + sb.append(cr); + return sb.toString(); + } + + protected String generatePchMangledGetMethod(AmqpField field, int indentSize, + int tabSize, boolean nextFlag) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(indent + "public T get" + + Utils.firstUpper(field.name) + + "(Class classObj) throws AMQProtocolVersionException" + cr); + sb.append(indent + "{" + cr); + Iterator dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.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.name + "_" + + (domainCntr++) + ";" + cr); + sb.append(indent + tab + "}" + cr); + } + sb.append(indent + tab + + "throw new AMQProtocolVersionException(\"None of the AMQP versions defines \" +" + + cr + " \"field \\\"" + field.name + + "\\\" 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) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + sb.append(indent + "public void set" + Utils.firstUpper(field.name) + + "(" + codeType + " " + field.name + ")" + 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.ordinalMap.size() == 1 && + field.ordinalMap.get(field.ordinalMap.firstKey()).size() == globalVersionSet.size()) + { + int ordinal = field.ordinalMap.firstKey(); + sb.append(indent + tab + "clearEncodedForm();" + cr); + sb.append(indent + tab + "propertyFlags[" + ordinal + "] = true;" + cr); + sb.append(indent + tab + "this." + field.name + " = " + field.name + ";" + cr); + } + else + { + Iterator oItr = field.ordinalMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + AmqpVersionSet oVersionSet = field.ordinalMap.get(ordinal); + sb.append(indent + tab); + if (ordinal != field.ordinalMap.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.name + " = " + field.name + ";" + 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) + throws AmqpTypeMappingException + { + String indent = Utils.createSpaces(indentSize); + String tab = Utils.createSpaces(tabSize); + StringBuffer sb = new StringBuffer(); + + Iterator dItr = field.domainMap.keySet().iterator(); + int domainCntr = 0; + while (dItr.hasNext()) + { + String domainName = dItr.next(); + AmqpVersionSet versionSet = field.domainMap.get(domainName); + String codeType = getGeneratedType(domainName, versionSet.first()); + + // Find ordinal with matching version + AmqpVersionSet commonVersionSet = new AmqpVersionSet(); + Iterator oItr = field.ordinalMap.keySet().iterator(); + while (oItr.hasNext()) + { + int ordinal = oItr.next(); + AmqpVersionSet oVersionSet = field.ordinalMap.get(ordinal); + Iterator 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.name) + + "(" + codeType + " " + field.name + ")" + 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.name + "_" + (domainCntr++) + + " = " + field.name + ";" + 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(ArrayList 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(ArrayList 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, + 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, + 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 0;" + cr); + return sb.toString(); + } + + protected String generatePchBitSetPropertyFlags(ArrayList 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 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 vItr = globalVersionSet.iterator(); + while (vItr.hasNext()) + { + AmqpVersion version = vItr.next(); + int numBytes = ((thisClass.fieldMap.getNumFields(version) - 1) / 15) + 1; + + sb.append(indent); + if (!version.equals(globalVersionSet.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 vItr = globalVersionSet.iterator(); + while (vItr.hasNext()) + { + AmqpVersion version = vItr.next(); + int numFields = thisClass.fieldMap.getNumFields(version); + int numBytes = ((numFields - 1) / 15) + 1; + + sb.append(indent); + if (!version.equals(globalVersionSet.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) + throws AmqpTypeMappingException + { + StringBuffer sb = new StringBuffer(); + AmqpVersion[] versionArray = new AmqpVersion[v.size()]; + v.toArray(versionArray); + for (int i=0; i 1) + sb.append("("); + sb.append("major == " + versionArray[i].getMajor() + " && minor == " + + 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; i0) + b.setCharAt(0, Character.toUpperCase(toks[i].charAt(0))); + ccn.append(b); + } + return ccn.toString(); + } +} diff --git a/gentools/org/apache/qpid/gentools/LanguageConverter.java b/gentools/org/apache/qpid/gentools/LanguageConverter.java new file mode 100644 index 0000000000..b9a2c81aa3 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/LanguageConverter.java @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +public interface LanguageConverter +{ + public void setDomainMap(AmqpDomainMap domainMap); + public AmqpDomainMap getDomainMap(); + + public void setModel(AmqpModel model); + 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) throws AmqpTypeMappingException; + public String getGeneratedType(String domainName, AmqpVersion version) throws AmqpTypeMappingException; +} diff --git a/gentools/org/apache/qpid/gentools/Main.java b/gentools/org/apache/qpid/gentools/Main.java new file mode 100644 index 0000000000..6deed79024 --- /dev/null +++ b/gentools/org/apache/qpid/gentools/Main.java @@ -0,0 +1,168 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.qpid.gentools; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +public class Main +{ + private DocumentBuilder docBuilder; + private AmqpVersionSet versionSet; + private Generator generator; + private AmqpDomainMap domainMap; + private AmqpModel model; + + public Main() throws ParserConfigurationException + { + docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + versionSet = new AmqpVersionSet(); + } + + public void run(String[] args) + throws IOException, + SAXException, + AmqpParseException, + AmqpTypeMappingException, + AmqpTemplateException, + TargetDirectoryException, + IllegalAccessException, + InvocationTargetException + { + File[] modelTemplateFiles = new File[]{}; + File[] classTemplateFiles = new File[]{}; + File[] methodTemplateFiles = new File[]{}; + File[] fieldTemplateFiles = new File[]{}; + String outDir = "out"; + + if (args[0].compareToIgnoreCase("-c") == 0) + { + // *** C++ generation *** + generator = new CppGenerator(versionSet); + domainMap = new AmqpDomainMap(generator); + model = new AmqpModel(generator); +// classTemplateFiles = new File[]{ new File("templ.cpp/PropertyContentHeaderClass.tmpl") }; +// methodTemplateFiles = new File[]{ new File("templ.cpp/MethodBodyClass.tmpl") }; + outDir += ".cpp"; + } + else if (args[0].compareToIgnoreCase("-j") == 0) + { + // *** Java generation *** + generator = new JavaGenerator(versionSet); + domainMap = new AmqpDomainMap(generator); + model = new AmqpModel(generator); + modelTemplateFiles = new File[] + { new File("templ.java/MethodRegistryClass.tmpl") }; + classTemplateFiles = new File[] + { new File("templ.java/PropertyContentHeaderClass.tmpl") }; + methodTemplateFiles = new File[] + { new File("templ.java/MethodBodyClass.tmpl") }; + outDir += ".java"; + } + else + { + System.err.println("ERROR: Required argument specifying language (C++ [-c] or Java [-j]) missing."); + usage(); + } + + // 1. Suck in all the XML spec files provided on the command line. + for (int i=1; i buildVersionMap(Node n)throws AmqpParseException +// { +// Vector versionList = new Vector(); +// NodeList nl = n.getChildNodes(); +// for (int i=0; i buildFieldMap(Node n)throws AmqpParseException +// { +// Vector fieldList = new Vector(); +// NodeList nl = n.getChildNodes(); +// for (int i=0; i