00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 import roslib; roslib.load_manifest('rosjava_jni')
00036
00037 import sys
00038 import os
00039 import traceback
00040
00041 import roslib.msgs
00042 import roslib.packages
00043 import roslib.gentools
00044
00045 from cStringIO import StringIO
00046
00047 MSG_TYPE_TO_JAVA = {'bool': 'boolean',
00048 'char': 'char',
00049 'byte': 'short',
00050 'uint8': 'short', 'int8': 'byte',
00051 'uint16': 'int', 'int16': 'short',
00052 'uint32': 'long', 'int32': 'int',
00053 'uint64': 'long', 'int64': 'long',
00054 'float32': 'float',
00055 'float64': 'double',
00056 'string': 'java.lang.String',
00057 'time': 'ros.communication.Time',
00058 'duration': 'ros.communication.Duration'}
00059
00060 MSG_TYPE_TO_SERIALIZATION_CODE = {
00061 'bool': '%(buffer)s.put((byte)(%(name)s ? 1 : 0))',
00062 'char': '%(buffer)s.put((byte)%(name)s)',
00063 'byte': '%(buffer)s.put((byte)%(name)s)',
00064 'uint8': '%(buffer)s.put((byte)%(name)s)',
00065 'int8': '%(buffer)s.put(%(name)s)',
00066 'uint16': '%(buffer)s.putShort((short)%(name)s)',
00067 'int16': '%(buffer)s.putShort(%(name)s)',
00068 'uint32': '%(buffer)s.putInt((int)%(name)s)',
00069 'int32': '%(buffer)s.putInt(%(name)s)',
00070 'uint64': '%(buffer)s.putLong(%(name)s)',
00071 'int64': '%(buffer)s.putLong(%(name)s)',
00072 'float32': '%(buffer)s.putFloat(%(name)s)',
00073 'float64': '%(buffer)s.putDouble(%(name)s)',
00074 'string': 'Serialization.writeString(%(buffer)s, %(name)s)',
00075 'time': 'Serialization.writeTime(%(buffer)s, %(name)s)',
00076 'duration': 'Serialization.writeDuration(%(buffer)s, %(name)s)'}
00077
00078 MSG_TYPE_TO_DESERIALIZATION_CODE = {
00079 'bool': '%s.get() != 0 ? true : false',
00080 'char': '(char)(%s.get() & 0xff)',
00081 'byte': '(short)(%s.get() & 0xff)',
00082 'uint8': '(short)(%s.get() & 0xff)',
00083 'int8': '%s.get()',
00084 'uint16': '(int)(%s.getShort() & 0xffff)',
00085 'int16': '%s.getShort()',
00086 'uint32': '(long)(%s.getInt() & 0xffffffff)',
00087 'int32': '%s.getInt()',
00088 'uint64': '%s.getLong()',
00089 'int64': '%s.getLong()',
00090 'float32': '%s.getFloat()',
00091 'float64': '%s.getDouble()',
00092 'string': 'Serialization.readString(%s)',
00093 'time': 'Serialization.readTime(%s)',
00094 'duration': 'Serialization.readDuration(%s)'}
00095
00096 BUILTIN_TYPE_SIZES = {'bool': 1, 'int8': 1, 'byte': 1, 'int16': 2, 'int32': 4, 'int64': 8,
00097 'char': 1, 'uint8': 1, 'uint16': 2, 'uint32': 4, 'uint64': 8,
00098 'float32': 4, 'float64': 8, 'time': 8, 'duration': 8}
00099
00100 JAVA_PRIMITIVE_TYPES = ['char', 'byte', 'short', 'int', 'long', 'boolean', 'float', 'double']
00101
00102 JAVA_HASH_CODES = {
00103 'char': '%(value)s',
00104 'byte': '%(value)s',
00105 'short': '%(value)s',
00106 'int': '%(value)s',
00107 'long': '(int)(%(value)s ^ (%(value)s >>> 32))',
00108 'boolean': '(%(value)s ? 1231 : 1237)',
00109 'float': 'Float.floatToIntBits(%(value)s)',
00110 'double': '(int)((tmp = Double.doubleToLongBits(%(value)s)) ^ (tmp >>> 32))'}
00111
00112 def builtin_type_size(type):
00113 return BUILTIN_TYPE_SIZES[type.split('[')[0]]
00114
00115 def base_type_to_java(base_type):
00116 base_type = base_type.split('[')[0]
00117 if (roslib.msgs.is_builtin(base_type)):
00118 java_type = MSG_TYPE_TO_JAVA[base_type]
00119 elif (len(base_type.split('/')) == 1):
00120 if (roslib.msgs.is_header_type(base_type)):
00121 java_type = 'ros.pkg.std_msgs.msg.Header'
00122 else:
00123 java_type = base_type
00124 else:
00125 pkg = base_type.split('/')[0]
00126 msg = base_type.split('/')[1]
00127 java_type = 'ros.pkg.%s.msg.%s' % (pkg, msg)
00128 return java_type
00129
00130 def base_type_serialization_code(type):
00131 return MSG_TYPE_TO_SERIALIZATION_CODE[type.split('[')[0]]
00132
00133 def base_type_deserialization_code(type):
00134 return MSG_TYPE_TO_DESERIALIZATION_CODE[type.split('[')[0]]
00135
00136 def type_initializer(type, default_val = None):
00137 if default_val is not None:
00138 if type == 'float32':
00139 return ' = %sf' % default_val
00140 else:
00141 return ' = %s' % default_val
00142 elif roslib.msgs.is_builtin(type):
00143 if type in ['time', 'duration', 'string']:
00144 return ' = new %s()' % base_type_to_java(type)
00145 else:
00146 return ''
00147 else:
00148 return ' = new %s()' % base_type_to_java(type)
00149
00150 def msg_decl_to_java(field, default_val=None):
00151 """
00152 Converts a message type (e.g. uint32, std_msgs/String, etc.) to the Java declaration
00153 for that type.
00154
00155 @param type: The message type
00156 @type type: str
00157 @return: The Java declaration
00158 @rtype: str
00159 """
00160 java_type = base_type_to_java(field.type)
00161
00162 if type(field).__name__ == 'Field' and field.is_array:
00163 if field.array_len is None:
00164 if field.is_builtin and java_type in JAVA_PRIMITIVE_TYPES:
00165 decl_string = '%(java_type)s[] %(name)s = new %(java_type)s[0]'
00166 else:
00167 decl_string = 'java.util.ArrayList<%(java_type)s> %(name)s = new java.util.ArrayList<%(java_type)s>()'
00168 return decl_string % { 'name': field.name, 'java_type': java_type}
00169 else:
00170 return '%(java_type)s[] %(name)s = new %(java_type)s[%(array_len)d]' % {'java_type': java_type,
00171 'name': field.name,
00172 'array_len': field.array_len}
00173 else:
00174 return '%(type)s %(name)s%(initializer)s' % {'type': java_type,
00175 'name': field.name,
00176 'initializer': type_initializer(field.type, default_val)}
00177
00178 def write_begin(s, spec, file):
00179 """
00180 Writes the beginning of the header file: a comment saying it's auto-generated and the include guards
00181
00182 @param s: The stream to write to
00183 @type s: stream
00184 @param spec: The spec
00185 @type spec: roslib.msgs.MsgSpec
00186 @param file: The file this message is being generated for
00187 @type file: str
00188 """
00189 s.write('/* Auto-generated by genmsg_java.py for file %s */\n'%(file))
00190 s.write('\npackage ros.pkg.%s.msg;\n' % spec.package)
00191 s.write('\nimport java.nio.ByteBuffer;\n')
00192
00193 def write_end(s, spec):
00194 """
00195 Writes the end of the header file: the ending of the include guards
00196
00197 @param s: The stream to write to
00198 @type s: stream
00199 @param spec: The spec
00200 @type spec: roslib.msgs.MsgSpec
00201 """
00202 pass
00203
00204 def write_imports(s, spec):
00205 """
00206 Writes the message-specific imports
00207
00208 @param s: The stream to write to
00209 @type s: stream
00210 @param spec: The message spec to iterate over
00211 @type spec: roslib.msgs.MsgSpec
00212 """
00213 s.write('\n')
00214
00215
00216 def write_class(s, spec, extra_metadata_methods={}, static=False):
00217 """
00218 Writes the entire message struct: declaration, constructors, members, constants and member functions
00219 @param s: The stream to write to
00220 @type s: stream
00221 @param spec: The message spec
00222 @type spec: roslib.msgs.MsgSpec
00223 """
00224
00225 msg = spec.short_name
00226 if static:
00227 s.write('static public class %s extends ros.communication.Message {\n' % msg)
00228 else:
00229 s.write('public class %s extends ros.communication.Message {\n' % msg)
00230
00231 write_constant_declarations(s, spec)
00232 write_members(s, spec)
00233
00234 write_constructor(s, spec)
00235
00236 gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package, compute_files=False)
00237 md5sum = roslib.gentools.compute_md5(gendeps_dict)
00238 full_text = compute_full_text_escaped(gendeps_dict)
00239
00240 write_member_functions(s, spec,
00241 dict({'MD5Sum': '"%s"' % md5sum,
00242 'DataType': '"%s/%s"' % (spec.package, spec.short_name),
00243 'MessageDefinition': full_text},
00244 **extra_metadata_methods))
00245
00246 s.write('} // class %s\n'%(msg))
00247
00248 def write_constructor(s, spec):
00249 s.write("""
00250 public %s() {
00251 """ % spec.short_name)
00252 for field in spec.parsed_fields():
00253 if field.type.split('[')[0] in roslib.msgs.PRIMITIVE_TYPES and \
00254 field.type.split('[')[0] != 'string':
00255 continue
00256 if field.is_array and field.array_len:
00257 s.write("""
00258 for(int __i=0; __i<%(array_len)d; __i++) {
00259 %(name)s[__i]%(initializer)s;
00260 }
00261 """ % {'name': field.name, 'type': field.type.split('[')[0],
00262 'array_len': field.array_len,
00263 'initializer': type_initializer(field.type.split('[')[0])})
00264 s.write(' }\n')
00265
00266 def write_member(s, field):
00267 """
00268 Writes a single member's declaration and type typedef
00269
00270 @param s: The stream to write to
00271 @type s: stream
00272 @param type: The member type
00273 @type type: str
00274 @param name: The name of the member
00275 @type name: str
00276 """
00277 java_decl = msg_decl_to_java(field)
00278 s.write(' public %s;\n' % java_decl)
00279
00280 def write_members(s, spec):
00281 """
00282 Write all the member declarations
00283
00284 @param s: The stream to write to
00285 @type s: stream
00286 @param spec: The message spec
00287 @type spec: roslib.msgs.MsgSpec
00288 """
00289 [write_member(s, field) for field in spec.parsed_fields()]
00290
00291 def escape_string(str):
00292 str = str.replace('\\', '\\\\')
00293 str = str.replace('"', '\\"')
00294 return str
00295
00296 def write_constant_declaration(s, constant):
00297 """
00298 Write a constant value as a static member
00299
00300 @param s: The stream to write to
00301 @type s: stream
00302 @param constant: The constant
00303 @type constant: roslib.msgs.Constant
00304 """
00305 if constant.type == 'string':
00306 s.write(' static public final %s;\n'% msg_decl_to_java(constant, '"' + escape_string(constant.val) + '"'))
00307 else:
00308 s.write(' static public final %s;\n'% msg_decl_to_java(constant, constant.val))
00309
00310 def write_constant_declarations(s, spec):
00311 """
00312 Write all the constants from a spec as static members
00313
00314 @param s: The stream to write to
00315 @type s: stream
00316 @param spec: The message spec
00317 @type spec: roslib.msgs.MsgSpec
00318 """
00319 for constant in spec.constants:
00320 write_constant_declaration(s, constant)
00321 s.write('\n')
00322
00323 def write_clone_methods(s, spec):
00324 s.write("""
00325 public %(type)s clone() {
00326 %(type)s c = new %(type)s();
00327 c.deserialize(serialize(0));
00328 return c;
00329 }
00330 """ % {'type': spec.short_name})
00331 s.write("""
00332 public void setTo(ros.communication.Message m) {
00333 deserialize(m.serialize(0));
00334 }
00335 """)
00336
00337 def write_serialization_length(s, spec):
00338 s.write("""
00339 public int serializationLength() {
00340 int __l = 0;
00341 """)
00342 for field in spec.parsed_fields():
00343 java_type = base_type_to_java(field.base_type)
00344 if field.type.split('[')[0] == 'string':
00345 if field.is_array:
00346 if field.array_len is None:
00347 s.write(' __l += 4;')
00348 s.write("""
00349 for(java.lang.String val : %(name)s) {
00350 __l += 4 + val.length();
00351 }
00352 """ % {'name': field.name})
00353 else:
00354 s.write(' __l += 4 + %s.length();\n' % field.name)
00355
00356 elif field.is_builtin:
00357 if field.is_array and field.array_len is None:
00358 if java_type in JAVA_PRIMITIVE_TYPES:
00359 size_expr = '4 + %s.length * %d' % (field.name, builtin_type_size(field.type))
00360 else:
00361 size_expr = '4 + %s.size() * %d' % (field.name, builtin_type_size(field.type))
00362 elif field.is_array:
00363 size_expr = '%d' % (int(field.array_len) * builtin_type_size(field.type))
00364 else:
00365 size_expr = '%d' % builtin_type_size(field.type)
00366 s.write(' __l += %s; // %s\n' % (size_expr, field.name))
00367 elif field.is_array:
00368 if field.array_len is None:
00369 s.write(' __l += 4;')
00370 s.write("""
00371 for(%s val : %s) {
00372 __l += val.serializationLength();
00373 }
00374 """ % (java_type, field.name))
00375 else:
00376 s.write(' __l += %s.serializationLength();\n' % field.name)
00377
00378 s.write(' return __l;\n }\n')
00379
00380 def write_serialization_method(s, spec):
00381 s.write("""
00382 public void serialize(ByteBuffer bb, int seq) {
00383 """)
00384 for field in spec.parsed_fields():
00385 java_type = base_type_to_java(field.base_type)
00386 if field.is_builtin:
00387 if field.is_array:
00388 if field.array_len is None:
00389 if java_type in JAVA_PRIMITIVE_TYPES:
00390 s.write(' bb.putInt(%s.length);' % field.name)
00391 else:
00392 s.write(' bb.putInt(%s.size());' % field.name)
00393 s.write("""
00394 for(%(type)s val : %(name)s) {
00395 %(serialization)s;
00396 }
00397 """ % {'type': java_type,
00398 'name': field.name,
00399 'serialization': base_type_serialization_code(field.type) % {'buffer': 'bb', 'name': 'val'}})
00400
00401
00402 else:
00403 s.write(' %s;\n' % (base_type_serialization_code(field.type) % {'buffer': 'bb',
00404 'name': field.name}))
00405
00406 else:
00407 if field.is_array:
00408 if field.array_len is None:
00409 s.write(' bb.putInt(%s.size());' % field.name)
00410 s.write("""
00411 for(%s val : %s) {
00412 val.serialize(bb, seq);
00413 }
00414 """ % (java_type, field.name))
00415
00416
00417 else:
00418 s.write(' %s.serialize(bb, seq);\n' % field.name)
00419
00420 s.write(' }\n')
00421
00422 def write_deserialization_method(s, spec):
00423 s.write("""
00424 public void deserialize(ByteBuffer bb) {
00425 """)
00426 for field in spec.parsed_fields():
00427 java_type = base_type_to_java(field.base_type)
00428
00429 if field.is_array:
00430
00431
00432
00433
00434
00435 size_initializer = None
00436 type_initializer = None
00437 deserialization_code = None
00438
00439 if field.array_len is None:
00440 size_initializer = 'bb.getInt()'
00441 if java_type not in JAVA_PRIMITIVE_TYPES:
00442 type_initializer = 'new java.util.ArrayList<%(type)s>(__%(name)s_len)'
00443 if field.is_builtin:
00444 deserialization_code = '%(name)s.add(%(deserialization_code)s)' \
00445 % {'name': '%(name)s',
00446 'deserialization_code': base_type_deserialization_code(field.type) % 'bb'}
00447 else:
00448 deserialization_code = """%(type)s __tmp = new %(type)s();
00449 %(indent)s__tmp.deserialize(bb);
00450 %(indent)s%(name)s.add(__tmp);"""
00451
00452 if not size_initializer:
00453 size_initializer = '%(name)s.length;' % {'name': field.name}
00454 if not type_initializer:
00455 type_initializer = 'new %(type)s[__%(name)s_len]'
00456 if not deserialization_code:
00457 if field.is_builtin:
00458 deserialization_code = '%(name)s[__i] = %(deserialization_code)s' \
00459 % {'name': '%(name)s',
00460 'deserialization_code': base_type_deserialization_code(field.type) % 'bb'}
00461 else:
00462 deserialization_code = """%(type)s __tmp = new %(type)s();
00463 %(indent)s__tmp.deserialize(bb);
00464 %(indent)s%(name)s[__i] = __tmp"""
00465
00466
00467 default_vars_dict = {'name': field.name, 'type': java_type}
00468 s.write("""
00469 int __%(name)s_len = %(size_initializer)s;
00470 %(name)s = %(type_initializer)s;
00471 for(int __i=0; __i<__%(name)s_len; __i++) {
00472 %(deserialization_code)s;
00473 }
00474 """ % dict(default_vars_dict,
00475 **{'size_initializer': size_initializer % default_vars_dict,
00476 'type_initializer': type_initializer % default_vars_dict,
00477 'deserialization_code': deserialization_code % dict(default_vars_dict, **{'indent': 6*' '})}))
00478
00479
00480 elif field.is_builtin:
00481 s.write(' %s = %s;\n' % (field.name,
00482 base_type_deserialization_code(field.type) % 'bb'))
00483 else:
00484 s.write(' %s.deserialize(bb);\n' % field.name)
00485 s.write(' }\n')
00486
00487 def write_serialization_methods(s, spec):
00488 write_serialization_length(s, spec)
00489 write_serialization_method(s, spec)
00490 write_deserialization_method(s, spec)
00491 write_compare_methods(s, spec)
00492
00493 def write_msg_metadata_method(s, name, return_value):
00494 s.write(' public static java.lang.String __s_get%s() { return %s; }\n' % (name, return_value))
00495 s.write(' public java.lang.String get%(name)s() { return __s_get%(name)s(); }\n'
00496 % {'name': name})
00497
00498 def write_equals_method(s, spec):
00499 s.write("""
00500 @SuppressWarnings("all")
00501 public boolean equals(Object o) {
00502 if(!(o instanceof %(type)s))
00503 return false;
00504 %(type)s other = (%(type)s) o;
00505 return
00506 """ % {'type': spec.short_name})
00507
00508 for field in spec.parsed_fields():
00509 java_type = base_type_to_java(field.base_type)
00510 template_dict = {'name': field.name}
00511 if field.is_array and (field.array_len or java_type in JAVA_PRIMITIVE_TYPES):
00512 s.write(' java.util.Arrays.equals(%(name)s, other.%(name)s) &&\n' % template_dict)
00513 elif not field.is_array and java_type in JAVA_PRIMITIVE_TYPES:
00514 s.write(' %(name)s == other.%(name)s &&\n' % template_dict)
00515 else:
00516 s.write(' %(name)s.equals(other.%(name)s) &&\n' % template_dict)
00517 s.write(""" true;
00518 }
00519 """)
00520
00521 def write_hash_code_method(s, spec):
00522 s.write("""
00523 @SuppressWarnings("all")
00524 public int hashCode() {
00525 final int prime = 31;
00526 int result = 1;
00527 long tmp;
00528 """)
00529 for field in spec.parsed_fields():
00530 java_type = base_type_to_java(field.base_type)
00531 template_dict = {'name': 'this.%s' % field.name}
00532 if field.is_array and (field.array_len or java_type in JAVA_PRIMITIVE_TYPES):
00533 s.write(' result = prime * result + java.util.Arrays.hashCode(%(name)s);\n' % template_dict)
00534 elif not field.is_array and java_type in JAVA_PRIMITIVE_TYPES:
00535 s.write(' result = prime * result + %(hash_code)s;\n' \
00536 % dict(template_dict, **{'hash_code': JAVA_HASH_CODES[java_type] % {'value': template_dict['name']}}))
00537 else:
00538 s.write(' result = prime * result + (%(name)s == null ? 0 : %(name)s.hashCode());\n' % template_dict)
00539 s.write(' return result;\n }\n')
00540
00541 def write_compare_methods(s, spec):
00542 write_equals_method(s, spec)
00543 write_hash_code_method(s, spec)
00544
00545 def write_member_functions(s, spec, msg_metadata_methods):
00546 """
00547 The the default member functions
00548 """
00549 s.write('\n')
00550 for method_desc in msg_metadata_methods.items():
00551 write_msg_metadata_method(s, *method_desc)
00552
00553 write_clone_methods(s, spec)
00554 write_serialization_methods(s, spec)
00555
00556 def compute_full_text_escaped(gen_deps_dict):
00557 """
00558 Same as roslib.gentools.compute_full_text, except that the
00559 resulting text is escaped to be safe for C++ double quotes
00560
00561 @param get_deps_dict: dictionary returned by get_dependencies call
00562 @type get_deps_dict: dict
00563 @return: concatenated text for msg/srv file and embedded msg/srv types. Text will be escaped for double quotes
00564 @rtype: str
00565 """
00566 definition = roslib.gentools.compute_full_text(gen_deps_dict)
00567 lines = definition.split('\n')
00568 s = StringIO()
00569 for line in lines:
00570 line = escape_string(line)
00571 s.write('\"%s\\n\" +\n'%(line))
00572
00573 s.write('\"\"')
00574 val = s.getvalue()
00575 s.close()
00576 return val
00577
00578 def generate(msg_path, output_base_path=None):
00579 """
00580 Generate a message
00581
00582 @param msg_path: The path to the .msg file
00583 @type msg_path: str
00584 """
00585 (package_dir, package) = roslib.packages.get_dir_pkg(msg_path)
00586 (_, spec) = roslib.msgs.load_from_file(msg_path, package)
00587
00588 s = StringIO()
00589 write_begin(s, spec, msg_path)
00590 write_imports(s, spec)
00591
00592 write_class(s, spec)
00593
00594 write_end(s, spec)
00595
00596 if output_base_path:
00597 output_dir = '%s/ros/pkg/%s/msg'%(output_base_path, package)
00598 else:
00599 output_dir = '%s/msg_gen/java/ros/pkg/%s/msg'%(package_dir, package)
00600
00601 if (not os.path.exists(output_dir)):
00602
00603
00604 try:
00605 os.makedirs(output_dir)
00606 except OSError, e:
00607 pass
00608
00609 f = open('%s/%s.java'%(output_dir, spec.short_name), 'w')
00610 print >> f, s.getvalue()
00611
00612 s.close()
00613
00614 def generate_messages(argv):
00615 if not os.path.exists(argv[-1]) or os.path.isdir(argv[-1]):
00616 for arg in argv[1:-1]:
00617 generate(arg, argv[-1])
00618 else:
00619 for arg in argv[1:]:
00620 generate(arg)
00621
00622 if __name__ == "__main__":
00623 generate_messages(sys.argv)