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