## The contents of this file are subject to the Mozilla Public License ## Version 1.1 (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.mozilla.org/MPL/ ## ## Software distributed under the License is distributed on an "AS IS" ## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See ## the License for the specific language governing rights and ## limitations under the License. ## ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is GoPivotal, Inc. ## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. ## from __future__ import nested_scopes import re import sys sys.path.append("../rabbitmq-codegen") # in case we're next to an experimental revision sys.path.append("codegen") # in case we're building from a distribution package from amqp_codegen import * class BogusDefaultValue(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) def java_constant_name(c): return '_'.join(re.split('[- ]', c.upper())) javaTypeMap = { 'octet': 'int', 'shortstr': 'String', 'longstr': 'LongString', 'short': 'int', 'long': 'int', 'longlong': 'long', 'bit': 'boolean', 'table': 'Map', 'timestamp': 'Date' } javaTypesToCheckForNull = set([ 'String', 'LongString', 'Date' ]) # the scalar types in the range of javaTypeMap must be in javaScalarTypes javaScalarTypes = set([ 'int', 'long', 'boolean' ]) # the javaScalarTypes must be in the domain of javaBoxedTypeMap javaBoxedTypeMap = { 'int': 'Integer', 'long': 'Long', 'boolean': 'Boolean' } def java_boxed_type(jtype): if jtype in javaScalarTypes: return javaBoxedTypeMap[jtype] else: return jtype def java_type(spec, domain): return javaTypeMap[spec.resolveDomain(domain)] def java_name(upperNext, name): out = '' for c in name: if not c.isalnum(): upperNext = True elif upperNext: out += c.upper() upperNext = False else: out += c return out def java_class_name(name): return java_name(True, name) def java_getter_name(name): return java_name(False, 'get-' + name) def java_field_name(name): return java_name(False, name) def java_field_type(spec, domain): return javaTypeMap[spec.resolveDomain(domain)] def java_field_default_value(jtype, value): if jtype == 'int': return value elif jtype == 'boolean': return ('%s'% (value)).lower() elif jtype == 'String': return '"%s"' % (value) elif jtype == 'LongString': return 'LongStringHelper.asLongString("%s")' % (value) elif jtype == 'long': return '%sL' % (value) elif jtype == 'Map': return "null" else: raise BogusDefaultValue("JSON provided default value %s for suspicious type %s" % (value, jtype)) def typeNameDefault(spec, a): fieldType = java_field_type(spec, a.domain) defaultVal = java_field_default_value(fieldType, a.defaultvalue) return (fieldType, java_field_name(a.name), defaultVal) def nullCheckedFields(spec, m): fieldsToNullCheck = set([]) for a in m.arguments: (jfType, jfName, jfDefault) = typeNameDefault(spec,a) if jfType in javaTypesToCheckForNull: fieldsToNullCheck.add(jfName) return fieldsToNullCheck #--------------------------------------------------------------------------- def printFileHeader(): print """// NOTE: This -*- java -*- source code is autogenerated from the AMQP // specification! // // The contents of this file are subject to the Mozilla Public License // Version 1.1 (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.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See // the License for the specific language governing rights and // limitations under the License. // // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. // Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. // """ def genJavaApi(spec): def printHeader(): printFileHeader() print "package com.rabbitmq.client;" print print "import java.io.DataInputStream;" print "import java.io.IOException;" print "import java.util.Collections;" print "import java.util.HashMap;" print "import java.util.Map;" print "import java.util.Date;" print print "import com.rabbitmq.client.impl.ContentHeaderPropertyWriter;" print "import com.rabbitmq.client.impl.ContentHeaderPropertyReader;" print "import com.rabbitmq.client.impl.LongStringHelper;" def printProtocolClass(): print print " public static class PROTOCOL {" print " public static final int MAJOR = %i;" % spec.major print " public static final int MINOR = %i;" % spec.minor print " public static final int REVISION = %i;" % spec.revision print " public static final int PORT = %i;" % spec.port print " }" def printConstants(): print for (c,v,cls) in spec.constants: print " public static final int %s = %i;" % (java_constant_name(c), v) def builder(c,m): def ctorCall(c,m): ctor_call = "com.rabbitmq.client.impl.AMQImpl.%s.%s" % (java_class_name(c.name),java_class_name(m.name)) ctor_arg_list = [ java_field_name(a.name) for a in m.arguments ] print " return new %s(%s);" % (ctor_call, ", ".join(ctor_arg_list)) def genFields(spec, m): for a in m.arguments: (jfType, jfName, jfDefault) = typeNameDefault(spec, a) if a.defaultvalue != None: print " private %s %s = %s;" % (jfType, jfName, jfDefault) else: print " private %s %s;" % (jfType, jfName) def genArgMethods(spec, m): for a in m.arguments: (jfType, jfName, jfDefault) = typeNameDefault(spec, a) print " public Builder %s(%s %s)" % (jfName, jfType, jfName) print " { this.%s = %s; return this; }" % (jfName, jfName) if jfType == "boolean": print " public Builder %s()" % (jfName) print " { return this.%s(true); }" % (jfName) elif jfType == "LongString": print " public Builder %s(String %s)" % (jfName, jfName) print " { return this.%s(LongStringHelper.asLongString(%s)); }" % (jfName, jfName) def genBuildMethod(c,m): print " public %s build() {" % (java_class_name(m.name)) ctorCall(c,m) print " }" print print " // Builder for instances of %s.%s" % (java_class_name(c.name), java_class_name(m.name)) print " public static final class Builder" print " {" genFields(spec, m) print print " public Builder() { }" print genArgMethods(spec, m) genBuildMethod(c,m) print " }" def printClassInterfaces(): for c in spec.classes: print print " public static class %s {" % (java_class_name(c.name)) for m in c.allMethods(): print " public interface %s extends Method {" % ((java_class_name(m.name))) for a in m.arguments: print " %s %s();" % (java_field_type(spec, a.domain), java_getter_name(a.name)) builder(c,m) print " }" print " }" def printReadProperties(c): if c.fields: for f in c.fields: print " boolean %s_present = reader.readPresence();" % (java_field_name(f.name)) print print " reader.finishPresence();" if c.fields: print for f in c.fields: (jfName, jfClass) = (java_field_name(f.name), java_class_name(f.domain)) print " this.%s = %s_present ? reader.read%s() : null;" % (jfName, jfName, jfClass) def printWritePropertiesTo(c): print print " public void writePropertiesTo(ContentHeaderPropertyWriter writer)" print " throws IOException" print " {" if c.fields: for f in c.fields: print " writer.writePresence(this.%s != null);" % (java_field_name(f.name)) print print " writer.finishPresence();" if c.fields: print for f in c.fields: (jfName, jfClass) = (java_field_name(f.name), java_class_name(f.domain)) print " if (this.%s != null) writer.write%s(this.%s);" % (jfName, jfClass, jfName) print " }" def printAppendPropertyDebugStringTo(c): appendList = [ "%s=\")\n .append(this.%s)\n .append(\"" % (f.name, java_field_name(f.name)) for f in c.fields ] print print " public void appendPropertyDebugStringTo(StringBuilder acc) {" print " acc.append(\"(%s)\");" % (", ".join(appendList)) print " }" def printPropertiesBuilderClass(c): def printBuilderSetter(fieldType, fieldName): print " public Builder %s(%s %s)" % (fieldName, java_boxed_type(fieldType), fieldName) print " { this.%s = %s; return this; }" % (fieldName, fieldName) if fieldType == "boolean": print " public Builder %s()" % (fieldName) print " { return this.%s(true); }" % (fieldName) elif fieldType == "LongString": print " public Builder %s(String %s)" % (fieldName, fieldName) print " { return this.%s(LongStringHelper.asLongString(%s)); }" % (fieldName, fieldName) print print " public static final class Builder {" # fields for f in c.fields: (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) print " private %s %s;" % (java_boxed_type(fType), fName) # ctor print print " public Builder() {};" # setters print for f in c.fields: printBuilderSetter(java_field_type(spec, f.domain), java_field_name(f.name)) print jClassName = java_class_name(c.name) # build() objName = "%sProperties" % (jClassName) ctor_parm_list = [ java_field_name(f.name) for f in c.fields ] print " public %s build() {" % (objName) print " return new %s" % (objName) print " ( %s" % ("\n , ".join(ctor_parm_list)) print " );" print " }" print " }" def printPropertiesBuilder(c): print print " public Builder builder() {" print " Builder builder = new Builder()" setFieldList = [ "%s(%s)" % (fn, fn) for fn in [ java_field_name(f.name) for f in c.fields ] ] print " .%s;" % ("\n .".join(setFieldList)) print " return builder;" print " }" def printPropertiesClass(c): def printGetter(fieldType, fieldName): capFieldName = fieldName[0].upper() + fieldName[1:] print " public %s get%s() { return this.%s; }" % (java_boxed_type(fieldType), capFieldName, fieldName) jClassName = java_class_name(c.name) print print " public static class %sProperties extends com.rabbitmq.client.impl.AMQ%sProperties {" % (jClassName, jClassName) #property fields for f in c.fields: (fType, fName) = (java_boxed_type(java_field_type(spec, f.domain)), java_field_name(f.name)) print " private %s %s;" % (fType, fName) #explicit constructor if c.fields: print consParmList = [ "%s %s" % (java_boxed_type(java_field_type(spec,f.domain)), java_field_name(f.name)) for f in c.fields ] print " public %sProperties(" % (jClassName) print " %s)" % (",\n ".join(consParmList)) print " {" for f in c.fields: (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) if fType == "Map": print " this.%s = %s==null ? null : Collections.unmodifiableMap(new HashMap(%s));" % (fName, fName, fName) else: print " this.%s = %s;" % (fName, fName) print " }" #datainputstream constructor print print " public %sProperties(DataInputStream in) throws IOException {" % (jClassName) print " super(in);" print " ContentHeaderPropertyReader reader = new ContentHeaderPropertyReader(in);" printReadProperties(c) print " }" # default constructor print " public %sProperties() {}" % (jClassName) #class properties print " public int getClassId() { return %i; }" % (c.index) print " public String getClassName() { return \"%s\"; }" % (c.name) printPropertiesBuilder(c) #accessor methods print for f in c.fields: (jType, jName) = (java_field_type(spec, f.domain), java_field_name(f.name)) printGetter(jType, jName) printWritePropertiesTo(c) printAppendPropertyDebugStringTo(c) printPropertiesBuilderClass(c) print " }" def printPropertiesClasses(): for c in spec.classes: if c.hasContentProperties: printPropertiesClass(c) printHeader() print print "public interface AMQP {" printProtocolClass() printConstants() printClassInterfaces() printPropertiesClasses() print "}" #-------------------------------------------------------------------------------- def genJavaImpl(spec): def printHeader(): printFileHeader() print "package com.rabbitmq.client.impl;" print print "import java.io.IOException;" print "import java.io.DataInputStream;" print "import java.util.Collections;" print "import java.util.HashMap;" print "import java.util.Map;" print print "import com.rabbitmq.client.AMQP;" print "import com.rabbitmq.client.LongString;" print "import com.rabbitmq.client.UnknownClassOrMethodId;" print "import com.rabbitmq.client.UnexpectedMethodError;" def printClassMethods(spec, c): print print " public static class %s {" % (java_class_name(c.name)) print " public static final int INDEX = %s;" % (c.index) for m in c.allMethods(): def getters(): if m.arguments: print for a in m.arguments: print " public %s %s() { return %s; }" % (java_field_type(spec,a.domain), java_getter_name(a.name), java_field_name(a.name)) def constructors(): print argList = [ "%s %s" % (java_field_type(spec,a.domain),java_field_name(a.name)) for a in m.arguments ] print " public %s(%s) {" % (java_class_name(m.name), ", ".join(argList)) fieldsToNullCheckInCons = nullCheckedFields(spec, m) for f in fieldsToNullCheckInCons: print " if (%s == null)" % (f) print " throw new IllegalStateException(\"Invalid configuration: '%s' must be non-null.\");" % (f) for a in m.arguments: (jfType, jfName) = (java_field_type(spec, a.domain), java_field_name(a.name)) if jfType == "Map": print " this.%s = %s==null ? null : Collections.unmodifiableMap(new HashMap(%s));" % (jfName, jfName, jfName) else: print " this.%s = %s;" % (jfName, jfName) print " }" consArgs = [ "rdr.read%s()" % (java_class_name(spec.resolveDomain(a.domain))) for a in m.arguments ] print " public %s(MethodArgumentReader rdr) throws IOException {" % (java_class_name(m.name)) print " this(%s);" % (", ".join(consArgs)) print " }" def others(): print print " public int protocolClassId() { return %s; }" % (c.index) print " public int protocolMethodId() { return %s; }" % (m.index) print " public String protocolMethodName() { return \"%s.%s\";}" % (c.name, m.name) print print " public boolean hasContent() { return %s; }" % (trueOrFalse(m.hasContent)) print print " public Object visit(MethodVisitor visitor) throws IOException" print " { return visitor.visit(this); }" def trueOrFalse(truthVal): if truthVal: return "true" else: return "false" def argument_debug_string(): appendList = [ "%s=\")\n .append(this.%s)\n .append(\"" % (a.name, java_field_name(a.name)) for a in m.arguments ] print print " public void appendArgumentDebugStringTo(StringBuilder acc) {" print " acc.append(\"(%s)\");" % ", ".join(appendList) print " }" def write_arguments(): print print " public void writeArgumentsTo(MethodArgumentWriter writer)" print " throws IOException" print " {" for a in m.arguments: print " writer.write%s(this.%s);" % (java_class_name(spec.resolveDomain(a.domain)), java_field_name(a.name)) print " }" #start print print " public static class %s" % (java_class_name(m.name),) print " extends Method" print " implements com.rabbitmq.client.AMQP.%s.%s" % (java_class_name(c.name), java_class_name(m.name)) print " {" print " public static final int INDEX = %s;" % (m.index) print for a in m.arguments: print " private final %s %s;" % (java_field_type(spec, a.domain), java_field_name(a.name)) getters() constructors() others() argument_debug_string() write_arguments() print " }" print " }" def printMethodVisitor(): print print " public interface MethodVisitor {" for c in spec.allClasses(): for m in c.allMethods(): print " Object visit(%s.%s x) throws IOException;" % (java_class_name(c.name), java_class_name(m.name)) print " }" #default method visitor print print " public static class DefaultMethodVisitor implements MethodVisitor {" for c in spec.allClasses(): for m in c.allMethods(): print " public Object visit(%s.%s x) throws IOException { throw new UnexpectedMethodError(x); }" % (java_class_name(c.name), java_class_name(m.name)) print " }" def printMethodArgumentReader(): print print " public static Method readMethodFrom(DataInputStream in) throws IOException {" print " int classId = in.readShort();" print " int methodId = in.readShort();" print " switch (classId) {" for c in spec.allClasses(): print " case %s:" % (c.index) print " switch (methodId) {" for m in c.allMethods(): fq_name = java_class_name(c.name) + '.' + java_class_name(m.name) print " case %s: {" % (m.index) print " return new %s(new MethodArgumentReader(new ValueReader(in)));" % (fq_name) print " }" print " default: break;" print " } break;" print " }" print print " throw new UnknownClassOrMethodId(classId, methodId);" print " }" def printContentHeaderReader(): print print " public static AMQContentHeader readContentHeaderFrom(DataInputStream in) throws IOException {" print " int classId = in.readShort();" print " switch (classId) {" for c in spec.allClasses(): if c.fields: print " case %s: return new %sProperties(in);" %(c.index, (java_class_name(c.name))) print " default: break;" print " }" print print " throw new UnknownClassOrMethodId(classId);" print " }" printHeader() print print "public class AMQImpl implements AMQP {" for c in spec.allClasses(): printClassMethods(spec,c) printMethodVisitor() printMethodArgumentReader() printContentHeaderReader() print "}" #-------------------------------------------------------------------------------- def generateJavaApi(specPath): genJavaApi(AmqpSpec(specPath)) def generateJavaImpl(specPath): genJavaImpl(AmqpSpec(specPath)) if __name__ == "__main__": do_main(generateJavaApi, generateJavaImpl)