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