001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.fusesource.hawtbuf.proto.compiler; 018 019 import java.io.File; 020 import java.io.FileInputStream; 021 import java.io.FileNotFoundException; 022 import java.io.FileOutputStream; 023 import java.io.PrintWriter; 024 import java.util.ArrayList; 025 import java.util.HashSet; 026 import java.util.LinkedHashMap; 027 import java.util.Map; 028 import java.util.StringTokenizer; 029 030 import org.fusesource.hawtbuf.proto.compiler.parser.ParseException; 031 import org.fusesource.hawtbuf.proto.compiler.parser.ProtoParser; 032 033 import static org.fusesource.hawtbuf.proto.WireFormat.*; 034 035 public class JavaGenerator { 036 037 private File out = new File("."); 038 private File[] path = new File[]{new File(".")}; 039 040 private ProtoDescriptor proto; 041 private String javaPackage; 042 private String outerClassName; 043 private PrintWriter w; 044 private int indent; 045 private ArrayList<String> errors = new ArrayList<String>(); 046 private boolean multipleFiles; 047 private boolean deferredDecode; 048 private boolean auto_clear_optional_fields; 049 050 public static void main(String[] args) { 051 052 JavaGenerator generator = new JavaGenerator(); 053 args = CommandLineSupport.setOptions(generator, args); 054 055 if (args.length == 0) { 056 System.out.println("No proto files specified."); 057 } 058 for (int i = 0; i < args.length; i++) { 059 try { 060 System.out.println("Compiling: "+args[i]); 061 generator.compile(new File(args[i])); 062 } catch (CompilerException e) { 063 System.out.println("Protocol Buffer Compiler failed with the following error(s):"); 064 for (String error : e.getErrors() ) { 065 System.out.println(""); 066 System.out.println(error); 067 } 068 System.out.println(""); 069 System.out.println("Compile failed. For more details see error messages listed above."); 070 return; 071 } 072 } 073 074 } 075 076 interface Closure { 077 void execute() throws CompilerException; 078 } 079 080 public void compile(File file) throws CompilerException { 081 082 // Parse the proto file 083 FileInputStream is=null; 084 try { 085 is = new FileInputStream(file); 086 ProtoParser parser = new ProtoParser(is); 087 proto = parser.ProtoDescriptor(); 088 proto.setName(file.getName()); 089 loadImports(proto, file.getParentFile()); 090 proto.validate(errors); 091 } catch (FileNotFoundException e) { 092 errors.add("Failed to open: "+file.getPath()+":"+e.getMessage()); 093 } catch (ParseException e) { 094 errors.add("Failed to parse: "+file.getPath()+":"+e.getMessage()); 095 } finally { 096 try { is.close(); } catch (Throwable ignore){} 097 } 098 099 if (!errors.isEmpty()) { 100 throw new CompilerException(errors); 101 } 102 103 // Load the options.. 104 javaPackage = javaPackage(proto); 105 outerClassName = javaClassName(proto); 106 // optimizeFor = getOption(proto.getOptions(), "optimize_for", "SPEED"); 107 multipleFiles = isMultipleFilesEnabled(proto); 108 deferredDecode = Boolean.parseBoolean(getOption(proto.getOptions(), "deferred_decode", "false")); 109 auto_clear_optional_fields = Boolean.parseBoolean(getOption(proto.getOptions(), "auto_clear_optional_fields", "false")); 110 111 if( multipleFiles ) { 112 generateProtoFile(); 113 } else { 114 writeFile(outerClassName, new Closure(){ 115 public void execute() throws CompilerException { 116 generateProtoFile(); 117 } 118 }); 119 } 120 121 if (!errors.isEmpty()) { 122 throw new CompilerException(errors); 123 } 124 125 } 126 127 private void writeFile(String className, Closure closure) throws CompilerException { 128 PrintWriter oldWriter = w; 129 // Figure out the java file name.. 130 File outputFile = out; 131 if (javaPackage != null) { 132 String packagePath = javaPackage.replace('.', '/'); 133 outputFile = new File(outputFile, packagePath); 134 } 135 outputFile = new File(outputFile, className + ".java"); 136 137 // Start writing the output file.. 138 outputFile.getParentFile().mkdirs(); 139 140 FileOutputStream fos=null; 141 try { 142 fos = new FileOutputStream(outputFile); 143 w = new PrintWriter(fos); 144 closure.execute(); 145 w.flush(); 146 } catch (FileNotFoundException e) { 147 errors.add("Failed to write to: "+outputFile.getPath()+":"+e.getMessage()); 148 } finally { 149 try { fos.close(); } catch (Throwable ignore){} 150 w = oldWriter; 151 } 152 } 153 154 private void loadImports(ProtoDescriptor proto, File protoDir) { 155 LinkedHashMap<String,ProtoDescriptor> children = new LinkedHashMap<String,ProtoDescriptor>(); 156 for (String imp : proto.getImports()) { 157 File file = new File(protoDir, imp); 158 for (int i = 0; i < path.length && !file.exists(); i++) { 159 file = new File(path[i], imp); 160 } 161 if ( !file.exists() ) { 162 errors.add("Cannot load import: "+imp); 163 } 164 165 FileInputStream is=null; 166 try { 167 is = new FileInputStream(file); 168 ProtoParser parser = new ProtoParser(is); 169 ProtoDescriptor child = parser.ProtoDescriptor(); 170 child.setName(file.getName()); 171 loadImports(child, file.getParentFile()); 172 children.put(imp, child); 173 } catch (ParseException e) { 174 errors.add("Failed to parse: "+file.getPath()+":"+e.getMessage()); 175 } catch (FileNotFoundException e) { 176 errors.add("Failed to open: "+file.getPath()+":"+e.getMessage()); 177 } finally { 178 try { is.close(); } catch (Throwable ignore){} 179 } 180 } 181 proto.setImportProtoDescriptors(children); 182 } 183 184 185 private void generateProtoFile() throws CompilerException { 186 if( multipleFiles ) { 187 for (EnumDescriptor value : proto.getEnums().values()) { 188 final EnumDescriptor o = value; 189 String className = uCamel(o.getName()); 190 writeFile(className, new Closure(){ 191 public void execute() throws CompilerException { 192 generateFileHeader(); 193 generateEnum(o); 194 } 195 }); 196 } 197 for (MessageDescriptor value : proto.getMessages().values()) { 198 final MessageDescriptor o = value; 199 String className = uCamel(o.getName()); 200 writeFile(className, new Closure(){ 201 public void execute() throws CompilerException { 202 generateFileHeader(); 203 generateMessageBean(o); 204 } 205 }); 206 } 207 208 } else { 209 generateFileHeader(); 210 211 p("public class " + outerClassName + " {"); 212 indent(); 213 214 for (EnumDescriptor enumType : proto.getEnums().values()) { 215 generateEnum(enumType); 216 } 217 for (MessageDescriptor m : proto.getMessages().values()) { 218 generateMessageBean(m); 219 } 220 221 unindent(); 222 p("}"); 223 } 224 } 225 226 private void generateFileHeader() { 227 p("//"); 228 p("// Generated by protoc, do not edit by hand."); 229 p("//"); 230 if (javaPackage != null) { 231 p("package " + javaPackage + ";"); 232 p(""); 233 } 234 } 235 236 private void generateMessageBean(MessageDescriptor m) { 237 238 String className = uCamel(m.getName()); 239 p(); 240 241 String staticOption = "static "; 242 if( multipleFiles && m.getParent()==null ) { 243 staticOption=""; 244 } 245 246 String javaImplements = getOption(m.getOptions(), "java_implments", null); 247 248 String implementsExpression = ""; 249 if( javaImplements!=null ) { 250 implementsExpression = "implements "+javaImplements+" "; 251 } 252 253 String baseClass = "org.fusesource.hawtbuf.proto.BaseMessage"; 254 if( deferredDecode ) { 255 baseClass = "org.fusesource.hawtbuf.proto.DeferredDecodeMessage"; 256 } 257 if( m.getBaseType()!=null ) { 258 baseClass = javaType(m.getBaseType())+"Base"; 259 } 260 261 p(staticOption+"public final class " + className + " extends "+className+"Base<"+className+"> "+implementsExpression+"{"); 262 p(); 263 264 indent(); 265 266 for (EnumDescriptor enumType : m.getEnums().values()) { 267 generateEnum(enumType); 268 } 269 270 // Generate the Nested Messages. 271 for (MessageDescriptor subMessage : m.getMessages().values()) { 272 generateMessageBean(subMessage); 273 } 274 275 // Generate the Group Messages 276 for (FieldDescriptor field : m.getFields().values()) { 277 if( isInBaseClass(m, field) ) { 278 continue; 279 } 280 if( field.isGroup() ) { 281 generateMessageBean(field.getGroup()); 282 } 283 } 284 285 286 generateMethodAssertInitialized(m, className); 287 288 generateMethodClear(m); 289 290 p("public "+className+" clone() {"); 291 p(" return new "+className+"().mergeFrom(this);"); 292 p("}"); 293 p(); 294 295 generateMethodMergeFromBean(m, className); 296 297 generateMethodSerializedSize(m); 298 299 generateMethodMergeFromStream(m, className); 300 301 generateMethodWriteTo(m); 302 303 generateMethodParseFrom(m, className); 304 305 generateMethodToString(m); 306 307 generateMethodVisitor(m); 308 309 generateMethodType(m, className); 310 311 generateMethodEquals(m, className); 312 313 unindent(); 314 p("}"); 315 p(); 316 317 p(staticOption+"abstract class " + className + "Base<T> extends "+baseClass+"<T> {"); 318 p(); 319 indent(); 320 321 // Generate the field accessors.. 322 for (FieldDescriptor field : m.getFields().values()) { 323 if( isInBaseClass(m, field) ) { 324 continue; 325 } 326 generateFieldAccessor(field); 327 } 328 329 unindent(); 330 p("}"); 331 p(); 332 } 333 334 private boolean isInBaseClass(MessageDescriptor m, FieldDescriptor field) { 335 if( m.getBaseType() ==null ) 336 return false; 337 return m.getBaseType().getFields().containsKey(field.getName()); 338 } 339 340 /** 341 * If the java_visitor message option is set, then this method generates a visitor method. The option 342 * speifiies the class name of the visitor and optionally the return value and exceptions thrown by the visitor. 343 * 344 * Examples: 345 * 346 * option java_visitor = "org.apache.kahadb.store.Visitor"; 347 * generates: 348 * public void visit(org.apache.kahadb.store.Visitor visitor) { 349 * visitor.visit(this); 350 * } 351 * 352 * option java_visitor = "org.apache.kahadb.store.Visitor:int:java.io.IOException"; 353 * generates: 354 * public int visit(org.apache.kahadb.store.Visitor visitor) throws java.io.IOException { 355 * return visitor.visit(this); 356 * } 357 * 358 * @param m 359 */ 360 private void generateMethodVisitor(MessageDescriptor m) { 361 String javaVisitor = getOption(m.getOptions(), "java_visitor", null); 362 if( javaVisitor!=null ) { 363 String returns = "void"; 364 String throwsException = null; 365 366 StringTokenizer st = new StringTokenizer(javaVisitor, ":"); 367 String vistorClass = st.nextToken(); 368 if( st.hasMoreTokens() ) { 369 returns = st.nextToken(); 370 } 371 if( st.hasMoreTokens() ) { 372 throwsException = st.nextToken(); 373 } 374 375 String throwsClause = ""; 376 if( throwsException!=null ) { 377 throwsClause = "throws "+throwsException+" "; 378 } 379 380 p("public "+returns+" visit("+vistorClass+" visitor) "+throwsClause+ "{"); 381 indent(); 382 if( "void".equals(returns) ) { 383 p("visitor.visit(this);"); 384 } else { 385 p("return visitor.visit(this);"); 386 } 387 unindent(); 388 p("}"); 389 p(); 390 } 391 } 392 393 private void generateMethodType(MessageDescriptor m, String className) { 394 String typeEnum = getOption(m.getOptions(), "java_type_method", null); 395 if( typeEnum!=null ) { 396 397 TypeDescriptor typeDescriptor = m.getType(typeEnum); 398 if( typeDescriptor == null ) { 399 typeDescriptor = m.getProtoDescriptor().getType(typeEnum); 400 } 401 if( typeDescriptor == null || !typeDescriptor.isEnum() ) { 402 errors.add("The java_type_method option on the "+m.getName()+" message does not point to valid enum type"); 403 return; 404 } 405 406 407 String constant = constantCase(className); 408 EnumDescriptor enumDescriptor = (EnumDescriptor)typeDescriptor; 409 if( enumDescriptor.getFields().get(constant) == null ) { 410 errors.add("The java_type_method option on the "+m.getName()+" message does not points to the "+typeEnum+" enum but it does not have an entry for "+constant); 411 } 412 413 String type = javaType(typeDescriptor); 414 415 p("public "+type+" type() {"); 416 indent(); 417 p("return "+type+"."+constant+";"); 418 unindent(); 419 p("}"); 420 p(); 421 } 422 } 423 424 private void generateMethodParseFrom(MessageDescriptor m, String className) { 425 426 String postMergeProcessing = ".checktInitialized()"; 427 if( deferredDecode ) { 428 postMergeProcessing=""; 429 } 430 431 p("public static "+className+" parseUnframed(org.fusesource.hawtbuf.proto.CodedInputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); 432 indent(); 433 p("return new "+className+"().mergeUnframed(data)"+postMergeProcessing+";"); 434 unindent(); 435 p("}"); 436 p(); 437 438 p("public static "+className+" parseUnframed(org.fusesource.hawtbuf.Buffer data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); 439 indent(); 440 p("return new "+className+"().mergeUnframed(data)"+postMergeProcessing+";"); 441 unindent(); 442 p("}"); 443 p(); 444 445 p("public static "+className+" parseUnframed(byte[] data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); 446 indent(); 447 p("return new "+className+"().mergeUnframed(data)"+postMergeProcessing+";"); 448 unindent(); 449 p("}"); 450 p(); 451 452 p("public static "+className+" parseUnframed(java.io.InputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); 453 indent(); 454 p("return new "+className+"().mergeUnframed(data)"+postMergeProcessing+";"); 455 unindent(); 456 p("}"); 457 p(); 458 459 p("public static "+className+" parseFramed(org.fusesource.hawtbuf.proto.CodedInputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); 460 indent(); 461 p("return new "+className+"().mergeFramed(data)"+postMergeProcessing+";"); 462 unindent(); 463 p("}"); 464 p(); 465 466 p("public static "+className+" parseFramed(org.fusesource.hawtbuf.Buffer data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); 467 indent(); 468 p("return new "+className+"().mergeFramed(data)"+postMergeProcessing+";"); 469 unindent(); 470 p("}"); 471 p(); 472 473 p("public static "+className+" parseFramed(byte[] data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException {"); 474 indent(); 475 p("return new "+className+"().mergeFramed(data)"+postMergeProcessing+";"); 476 unindent(); 477 p("}"); 478 p(); 479 480 p("public static "+className+" parseFramed(java.io.InputStream data) throws org.fusesource.hawtbuf.proto.InvalidProtocolBufferException, java.io.IOException {"); 481 indent(); 482 p("return new "+className+"().mergeFramed(data)"+postMergeProcessing+";"); 483 unindent(); 484 p("}"); 485 p(); 486 } 487 488 private void generateMethodEquals(MessageDescriptor m, String className) { 489 p("public boolean equals(Object obj) {"); 490 indent(); 491 p("if( obj==this )"); 492 p(" return true;"); 493 p(""); 494 p("if( obj==null || obj.getClass()!="+className+".class )"); 495 p(" return false;"); 496 p(""); 497 p("return equals(("+className+")obj);"); 498 unindent(); 499 p("}"); 500 p(""); 501 502 p("public boolean equals("+className+" obj) {"); 503 indent(); 504 if( deferredDecode ) { 505 p("return toUnframedBuffer().equals(obj.toUnframedBuffer());"); 506 } else { 507 for (FieldDescriptor field : m.getFields().values()) { 508 String uname = uCamel(field.getName()); 509 String getterMethod="get"+uname+"()"; 510 String hasMethod = "has"+uname+"()"; 511 512 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 513 getterMethod = "get"+uname+"List()"; 514 } 515 516 p("if ("+hasMethod+" ^ obj."+hasMethod+" ) "); 517 p(" return false;"); 518 519 520 521 if( field.getRule() != FieldDescriptor.REPEATED_RULE && (field.isNumberType() || field.getType()==FieldDescriptor.BOOL_TYPE) ) { 522 p("if ("+hasMethod+" && ( "+getterMethod+"!=obj."+getterMethod+" ))"); 523 } else { 524 p("if ("+hasMethod+" && ( !"+getterMethod+".equals(obj."+getterMethod+") ))"); 525 } 526 p(" return false;"); 527 } 528 p("return true;"); 529 } 530 unindent(); 531 p("}"); 532 p(""); 533 p("public int hashCode() {"); 534 indent(); 535 int hc = className.hashCode(); 536 if( deferredDecode ) { 537 p("return "+hc+" ^ toUnframedBuffer().hashCode();"); 538 } else { 539 p("int rc="+hc+";"); 540 int counter=0; 541 for (FieldDescriptor field : m.getFields().values()) { 542 counter++; 543 544 String uname = uCamel(field.getName()); 545 String getterMethod="get"+uname+"()"; 546 String hasMethod = "has"+uname+"()"; 547 548 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 549 getterMethod = "get"+uname+"List()"; 550 } 551 552 p("if ("+hasMethod+") {"); 553 indent(); 554 555 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 556 p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+".hashCode() );"); 557 } else if( field.isInteger32Type() ) { 558 p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+" );"); 559 } else if( field.isInteger64Type() ) { 560 p("rc ^= ( "+uname.hashCode()+"^(new Long("+getterMethod+")).hashCode() );"); 561 } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) { 562 p("rc ^= ( "+uname.hashCode()+"^(new Double("+getterMethod+")).hashCode() );"); 563 } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) { 564 p("rc ^= ( "+uname.hashCode()+"^(new Double("+getterMethod+")).hashCode() );"); 565 } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) { 566 p("rc ^= ( "+uname.hashCode()+"^ ("+getterMethod+"? "+counter+":-"+counter+") );"); 567 } else { 568 p("rc ^= ( "+uname.hashCode()+"^"+getterMethod+".hashCode() );"); 569 } 570 571 unindent(); 572 p("}"); 573 574 } 575 p("return rc;"); 576 } 577 unindent(); 578 p("}"); 579 p(""); 580 } 581 582 /** 583 * @param m 584 */ 585 private void generateMethodSerializedSize(MessageDescriptor m) { 586 p("public int serializedSizeUnframed() {"); 587 indent(); 588 if( deferredDecode ) { 589 p("if (encodedForm != null) {"); 590 indent(); 591 p("return encodedForm.length;"); 592 unindent(); 593 p("}"); 594 } 595 p("if (memoizedSerializedSize != -1)"); 596 p(" return memoizedSerializedSize;"); 597 p(); 598 p("int size = 0;"); 599 for (FieldDescriptor field : m.getFields().values()) { 600 601 String uname = uCamel(field.getName()); 602 String getter="get"+uname+"()"; 603 String type = javaType(field); 604 p("if (has"+uname+"()) {"); 605 indent(); 606 607 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 608 p("for ("+type+" i : get"+uname+"List()) {"); 609 indent(); 610 getter = "i"; 611 } 612 613 if( field.getType()==FieldDescriptor.STRING_TYPE ) { 614 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeStringSize("+field.getTag()+", "+getter+");"); 615 } else if( field.getType()==FieldDescriptor.BYTES_TYPE ) { 616 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeBytesSize("+field.getTag()+", "+getter+");"); 617 } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) { 618 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeBoolSize("+field.getTag()+", "+getter+");"); 619 } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) { 620 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeDoubleSize("+field.getTag()+", "+getter+");"); 621 } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) { 622 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeFloatSize("+field.getTag()+", "+getter+");"); 623 } else if( field.getType()==FieldDescriptor.INT32_TYPE ) { 624 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeInt32Size("+field.getTag()+", "+getter+");"); 625 } else if( field.getType()==FieldDescriptor.INT64_TYPE ) { 626 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeInt64Size("+field.getTag()+", "+getter+");"); 627 } else if( field.getType()==FieldDescriptor.SINT32_TYPE ) { 628 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSInt32Size("+field.getTag()+", "+getter+");"); 629 } else if( field.getType()==FieldDescriptor.SINT64_TYPE ) { 630 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSInt64Size("+field.getTag()+", "+getter+");"); 631 } else if( field.getType()==FieldDescriptor.UINT32_TYPE ) { 632 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeUInt32Size("+field.getTag()+", "+getter+");"); 633 } else if( field.getType()==FieldDescriptor.UINT64_TYPE ) { 634 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeUInt64Size("+field.getTag()+", "+getter+");"); 635 } else if( field.getType()==FieldDescriptor.FIXED32_TYPE ) { 636 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeFixed32Size("+field.getTag()+", "+getter+");"); 637 } else if( field.getType()==FieldDescriptor.FIXED64_TYPE ) { 638 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeFixed64Size("+field.getTag()+", "+getter+");"); 639 } else if( field.getType()==FieldDescriptor.SFIXED32_TYPE ) { 640 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSFixed32Size("+field.getTag()+", "+getter+");"); 641 } else if( field.getType()==FieldDescriptor.SFIXED64_TYPE ) { 642 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeSFixed64Size("+field.getTag()+", "+getter+");"); 643 } else if( field.getTypeDescriptor().isEnum() ) { 644 p("size += org.fusesource.hawtbuf.proto.CodedOutputStream.computeEnumSize("+field.getTag()+", "+getter+".getNumber());"); 645 } else if ( field.getGroup()!=null ) { 646 p("size += computeGroupSize("+field.getTag()+", "+getter+");"); 647 } else { 648 p("size += computeMessageSize("+field.getTag()+", "+getter+");"); 649 } 650 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 651 unindent(); 652 p("}"); 653 } 654 //TODO: finish this up. 655 unindent(); 656 p("}"); 657 658 } 659 // TODO: handle unknown fields 660 // size += getUnknownFields().getSerializedSize();"); 661 p("memoizedSerializedSize = size;"); 662 p("return size;"); 663 unindent(); 664 p("}"); 665 p(); 666 } 667 668 /** 669 * @param m 670 */ 671 private void generateMethodWriteTo(MessageDescriptor m) { 672 p("public void writeUnframed(org.fusesource.hawtbuf.proto.CodedOutputStream output) throws java.io.IOException {"); 673 indent(); 674 675 if( deferredDecode ) { 676 p("if (encodedForm == null) {"); 677 indent(); 678 p("int size = serializedSizeUnframed();"); 679 p("encodedForm = output.getNextBuffer(size);"); 680 p("org.fusesource.hawtbuf.proto.CodedOutputStream original=null;"); 681 p("if( encodedForm == null ) {"); 682 indent(); 683 p("encodedForm = new org.fusesource.hawtbuf.Buffer(new byte[size]);"); 684 p("original = output;"); 685 p("output = new org.fusesource.hawtbuf.proto.CodedOutputStream(encodedForm);"); 686 unindent(); 687 p("}"); 688 } 689 690 691 for (FieldDescriptor field : m.getFields().values()) { 692 String uname = uCamel(field.getName()); 693 String getter="get"+uname+"()"; 694 String type = javaType(field); 695 p("if (has"+uname+"()) {"); 696 indent(); 697 698 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 699 p("for ("+type+" i : get"+uname+"List()) {"); 700 indent(); 701 getter = "i"; 702 } 703 704 if( field.getType()==FieldDescriptor.STRING_TYPE ) { 705 p("output.writeString("+field.getTag()+", "+getter+");"); 706 } else if( field.getType()==FieldDescriptor.BYTES_TYPE ) { 707 p("output.writeBytes("+field.getTag()+", "+getter+");"); 708 } else if( field.getType()==FieldDescriptor.BOOL_TYPE ) { 709 p("output.writeBool("+field.getTag()+", "+getter+");"); 710 } else if( field.getType()==FieldDescriptor.DOUBLE_TYPE ) { 711 p("output.writeDouble("+field.getTag()+", "+getter+");"); 712 } else if( field.getType()==FieldDescriptor.FLOAT_TYPE ) { 713 p("output.writeFloat("+field.getTag()+", "+getter+");"); 714 } else if( field.getType()==FieldDescriptor.INT32_TYPE ) { 715 p("output.writeInt32("+field.getTag()+", "+getter+");"); 716 } else if( field.getType()==FieldDescriptor.INT64_TYPE ) { 717 p("output.writeInt64("+field.getTag()+", "+getter+");"); 718 } else if( field.getType()==FieldDescriptor.SINT32_TYPE ) { 719 p("output.writeSInt32("+field.getTag()+", "+getter+");"); 720 } else if( field.getType()==FieldDescriptor.SINT64_TYPE ) { 721 p("output.writeSInt64("+field.getTag()+", "+getter+");"); 722 } else if( field.getType()==FieldDescriptor.UINT32_TYPE ) { 723 p("output.writeUInt32("+field.getTag()+", "+getter+");"); 724 } else if( field.getType()==FieldDescriptor.UINT64_TYPE ) { 725 p("output.writeUInt64("+field.getTag()+", "+getter+");"); 726 } else if( field.getType()==FieldDescriptor.FIXED32_TYPE ) { 727 p("output.writeFixed32("+field.getTag()+", "+getter+");"); 728 } else if( field.getType()==FieldDescriptor.FIXED64_TYPE ) { 729 p("output.writeFixed64("+field.getTag()+", "+getter+");"); 730 } else if( field.getType()==FieldDescriptor.SFIXED32_TYPE ) { 731 p("output.writeSFixed32("+field.getTag()+", "+getter+");"); 732 } else if( field.getType()==FieldDescriptor.SFIXED64_TYPE ) { 733 p("output.writeSFixed64("+field.getTag()+", "+getter+");"); 734 } else if( field.getTypeDescriptor().isEnum() ) { 735 p("output.writeEnum("+field.getTag()+", "+getter+".getNumber());"); 736 } else if ( field.getGroup()!=null ) { 737 p("writeGroup(output, "+field.getTag()+", "+getter+");"); 738 } else { 739 p("writeMessage(output, "+field.getTag()+", "+getter+");"); 740 } 741 742 if( field.getRule() == FieldDescriptor.REPEATED_RULE ) { 743 unindent(); 744 p("}"); 745 } 746 747 unindent(); 748 p("}"); 749 } 750 751 if( deferredDecode ) { 752 p("if( original !=null ) {"); 753 indent(); 754 p("output.checkNoSpaceLeft();"); 755 p("output = original;"); 756 p("output.writeRawBytes(encodedForm);"); 757 unindent(); 758 p("}"); 759 unindent(); 760 p("} else {"); 761 indent(); 762 p("output.writeRawBytes(encodedForm);"); 763 unindent(); 764 p("}"); 765 } 766 767 unindent(); 768 p("}"); 769 p(); 770 } 771 772 /** 773 * @param m 774 * @param className 775 */ 776 private void generateMethodMergeFromStream(MessageDescriptor m, String className) { 777 p("public "+className+" mergeUnframed(org.fusesource.hawtbuf.proto.CodedInputStream input) throws java.io.IOException {"); 778 indent(); 779 { 780 p("while (true) {"); 781 indent(); 782 { 783 p("int tag = input.readTag();"); 784 p("if ((tag & 0x07) == 4) {"); 785 p(" return this;"); 786 p("}"); 787 788 p("switch (tag) {"); 789 p("case 0:"); 790 p(" return this;"); 791 p("default: {"); 792 793 p(" break;"); 794 p("}"); 795 796 for (FieldDescriptor field : m.getFields().values()) { 797 String uname = uCamel(field.getName()); 798 String setter = "set" + uname; 799 boolean repeated = field.getRule() == FieldDescriptor.REPEATED_RULE; 800 if (repeated) { 801 setter = "get" + uname + "List().add"; 802 } 803 if (field.getType() == FieldDescriptor.STRING_TYPE) { 804 p("case " 805 + makeTag(field.getTag(), 806 WIRETYPE_LENGTH_DELIMITED) + ":"); 807 indent(); 808 p(setter + "(input.readString());"); 809 } else if (field.getType() == FieldDescriptor.BYTES_TYPE) { 810 p("case " 811 + makeTag(field.getTag(), 812 WIRETYPE_LENGTH_DELIMITED) + ":"); 813 indent(); 814 p(setter + "(input.readBytes());"); 815 } else if (field.getType() == FieldDescriptor.BOOL_TYPE) { 816 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 817 + ":"); 818 indent(); 819 p(setter + "(input.readBool());"); 820 } else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) { 821 p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64) 822 + ":"); 823 indent(); 824 p(setter + "(input.readDouble());"); 825 } else if (field.getType() == FieldDescriptor.FLOAT_TYPE) { 826 p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32) 827 + ":"); 828 indent(); 829 p(setter + "(input.readFloat());"); 830 } else if (field.getType() == FieldDescriptor.INT32_TYPE) { 831 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 832 + ":"); 833 indent(); 834 p(setter + "(input.readInt32());"); 835 } else if (field.getType() == FieldDescriptor.INT64_TYPE) { 836 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 837 + ":"); 838 indent(); 839 p(setter + "(input.readInt64());"); 840 } else if (field.getType() == FieldDescriptor.SINT32_TYPE) { 841 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 842 + ":"); 843 indent(); 844 p(setter + "(input.readSInt32());"); 845 } else if (field.getType() == FieldDescriptor.SINT64_TYPE) { 846 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 847 + ":"); 848 indent(); 849 p(setter + "(input.readSInt64());"); 850 } else if (field.getType() == FieldDescriptor.UINT32_TYPE) { 851 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 852 + ":"); 853 indent(); 854 p(setter + "(input.readUInt32());"); 855 } else if (field.getType() == FieldDescriptor.UINT64_TYPE) { 856 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 857 + ":"); 858 indent(); 859 p(setter + "(input.readUInt64());"); 860 } else if (field.getType() == FieldDescriptor.FIXED32_TYPE) { 861 p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32) 862 + ":"); 863 indent(); 864 p(setter + "(input.readFixed32());"); 865 } else if (field.getType() == FieldDescriptor.FIXED64_TYPE) { 866 p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64) 867 + ":"); 868 indent(); 869 p(setter + "(input.readFixed64());"); 870 } else if (field.getType() == FieldDescriptor.SFIXED32_TYPE) { 871 p("case " + makeTag(field.getTag(), WIRETYPE_FIXED32) 872 + ":"); 873 indent(); 874 p(setter + "(input.readSFixed32());"); 875 } else if (field.getType() == FieldDescriptor.SFIXED64_TYPE) { 876 p("case " + makeTag(field.getTag(), WIRETYPE_FIXED64) 877 + ":"); 878 indent(); 879 p(setter + "(input.readSFixed64());"); 880 } else if (field.getTypeDescriptor().isEnum()) { 881 p("case " + makeTag(field.getTag(), WIRETYPE_VARINT) 882 + ":"); 883 indent(); 884 String type = javaType(field); 885 p("{"); 886 indent(); 887 p("int t = input.readEnum();"); 888 p("" + type + " value = " + type + ".valueOf(t);"); 889 p("if( value !=null ) {"); 890 indent(); 891 p(setter + "(value);"); 892 unindent(); 893 p("}"); 894 // TODO: else store it as an known 895 896 unindent(); 897 p("}"); 898 899 } else if (field.getGroup() != null) { 900 p("case " 901 + makeTag(field.getTag(), WIRETYPE_START_GROUP) 902 + ":"); 903 indent(); 904 String type = javaType(field); 905 if (repeated) { 906 p(setter + "(readGroup(input, " + field.getTag() 907 + ", new " + type + "()));"); 908 } else { 909 p("if (has" + uname + "()) {"); 910 indent(); 911 p("readGroup(input, " + field.getTag() + ", get" 912 + uname + "());"); 913 unindent(); 914 p("} else {"); 915 indent(); 916 p(setter + "(readGroup(input, " + field.getTag() 917 + ",new " + type + "()));"); 918 unindent(); 919 p("}"); 920 } 921 p(""); 922 } else { 923 p("case " 924 + makeTag(field.getTag(), 925 WIRETYPE_LENGTH_DELIMITED) + ":"); 926 indent(); 927 String type = javaType(field); 928 if (repeated) { 929 p(setter + "(new " + type 930 + "().mergeFramed(input));"); 931 } else { 932 p("if (has" + uname + "()) {"); 933 indent(); 934 p("get" + uname + "().mergeFramed(input);"); 935 unindent(); 936 p("} else {"); 937 indent(); 938 p(setter + "(new " + type 939 + "().mergeFramed(input));"); 940 unindent(); 941 p("}"); 942 } 943 } 944 p("break;"); 945 unindent(); 946 } 947 p("}"); 948 } 949 unindent(); 950 p("}"); 951 } 952 unindent(); 953 p("}"); 954 } 955 956 /** 957 * @param m 958 * @param className 959 */ 960 private void generateMethodMergeFromBean(MessageDescriptor m, String className) { 961 p("public "+className+" mergeFrom("+className+" other) {"); 962 indent(); 963 for (FieldDescriptor field : m.getFields().values()) { 964 String uname = uCamel(field.getName()); 965 p("if (other.has"+uname+"()) {"); 966 indent(); 967 968 if( field.isScalarType() || field.getTypeDescriptor().isEnum() ) { 969 if( field.isRepeated() ) { 970 p("get"+uname+"List().addAll(other.get"+uname+"List());"); 971 } else { 972 p("set"+uname+"(other.get"+uname+"());"); 973 } 974 } else { 975 976 String type = javaType(field); 977 // It's complex type... 978 if( field.isRepeated() ) { 979 p("for("+type+" element: other.get"+uname+"List() ) {"); 980 indent(); 981 p("get"+uname+"List().add(element.clone());"); 982 unindent(); 983 p("}"); 984 } else { 985 p("if (has"+uname+"()) {"); 986 indent(); 987 p("get"+uname+"().mergeFrom(other.get"+uname+"());"); 988 unindent(); 989 p("} else {"); 990 indent(); 991 p("set"+uname+"(other.get"+uname+"().clone());"); 992 unindent(); 993 p("}"); 994 } 995 } 996 unindent(); 997 p("}"); 998 } 999 p("return this;"); 1000 unindent(); 1001 p("}"); 1002 p(); 1003 } 1004 1005 /** 1006 * @param m 1007 */ 1008 private void generateMethodClear(MessageDescriptor m) { 1009 p("public void clear() {"); 1010 indent(); 1011 p("super.clear();"); 1012 for (FieldDescriptor field : m.getFields().values()) { 1013 String uname = uCamel(field.getName()); 1014 p("clear" + uname + "();"); 1015 } 1016 unindent(); 1017 p("}"); 1018 p(); 1019 } 1020 1021 private void generateMethodAssertInitialized(MessageDescriptor m, String className) { 1022 1023 p("public java.util.ArrayList<String> missingFields() {"); 1024 indent(); 1025 p("java.util.ArrayList<String> missingFields = super.missingFields();"); 1026 1027 for (FieldDescriptor field : m.getFields().values()) { 1028 String uname = uCamel(field.getName()); 1029 if( field.isRequired() ) { 1030 p("if( !has" + uname + "() ) {"); 1031 indent(); 1032 p("missingFields.add(\""+field.getName()+"\");"); 1033 unindent(); 1034 p("}"); 1035 } 1036 } 1037 1038 if( !deferredDecode ) { 1039 for (FieldDescriptor field : m.getFields().values()) { 1040 if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) { 1041 String uname = uCamel(field.getName()); 1042 p("if( has" + uname + "() ) {"); 1043 indent(); 1044 if( !field.isRepeated() ) { 1045 p("try {"); 1046 indent(); 1047 p("get" + uname + "().assertInitialized();"); 1048 unindent(); 1049 p("} catch (org.fusesource.hawtbuf.proto.UninitializedMessageException e){"); 1050 indent(); 1051 p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+".\"));"); 1052 unindent(); 1053 p("}"); 1054 } else { 1055 String type = javaCollectionType(field); 1056 p("java.util.List<"+type+"> l = get" + uname + "List();"); 1057 p("for( int i=0; i < l.size(); i++ ) {"); 1058 indent(); 1059 p("try {"); 1060 indent(); 1061 p("l.get(i).assertInitialized();"); 1062 unindent(); 1063 p("} catch (org.fusesource.hawtbuf.proto.UninitializedMessageException e){"); 1064 indent(); 1065 p("missingFields.addAll(prefix(e.getMissingFields(),\""+field.getName()+"[\"+i+\"]\"));"); 1066 unindent(); 1067 p("}"); 1068 unindent(); 1069 p("}"); 1070 } 1071 unindent(); 1072 p("}"); 1073 } 1074 } 1075 } 1076 p("return missingFields;"); 1077 unindent(); 1078 p("}"); 1079 p(); 1080 } 1081 1082 private void generateMethodToString(MessageDescriptor m) { 1083 1084 p("public String toString() {"); 1085 indent(); 1086 p("return toString(new java.lang.StringBuilder(), \"\").toString();"); 1087 unindent(); 1088 p("}"); 1089 p(); 1090 1091 p("public java.lang.StringBuilder toString(java.lang.StringBuilder sb, String prefix) {"); 1092 indent(); 1093 1094 if( deferredDecode ) { 1095 p("load();"); 1096 } 1097 for (FieldDescriptor field : m.getFields().values()) { 1098 String uname = uCamel(field.getName()); 1099 p("if( has" + uname + "() ) {"); 1100 indent(); 1101 if( field.isRepeated() ) { 1102 String type = javaCollectionType(field); 1103 p("java.util.List<"+type+"> l = get" + uname + "List();"); 1104 p("for( int i=0; i < l.size(); i++ ) {"); 1105 indent(); 1106 if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) { 1107 p("sb.append(prefix+\""+field.getName()+"[\"+i+\"] {\\n\");"); 1108 p("l.get(i).toString(sb, prefix+\" \");"); 1109 p("sb.append(prefix+\"}\\n\");"); 1110 } else { 1111 p("sb.append(prefix+\""+field.getName()+"[\"+i+\"]: \");"); 1112 p("sb.append(l.get(i));"); 1113 p("sb.append(\"\\n\");"); 1114 } 1115 unindent(); 1116 p("}"); 1117 } else { 1118 if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) { 1119 p("sb.append(prefix+\""+field.getName()+" {\\n\");"); 1120 p("get" + uname + "().toString(sb, prefix+\" \");"); 1121 p("sb.append(prefix+\"}\\n\");"); 1122 } else { 1123 p("sb.append(prefix+\""+field.getName()+": \");"); 1124 p("sb.append(get" + uname + "());"); 1125 p("sb.append(\"\\n\");"); 1126 } 1127 } 1128 unindent(); 1129 p("}"); 1130 } 1131 1132 1133 p("return sb;"); 1134 unindent(); 1135 p("}"); 1136 p(); 1137 1138 } 1139 1140 /** 1141 * @param field 1142 * @param className 1143 */ 1144 private void generateFieldAccessor(FieldDescriptor field) { 1145 1146 String lname = lCamel(field.getName()); 1147 String uname = uCamel(field.getName()); 1148 String type = field.getRule()==FieldDescriptor.REPEATED_RULE ? javaCollectionType(field):javaType(field); 1149 String typeDefault = javaTypeDefault(field); 1150 boolean primitive = field.getTypeDescriptor()==null || field.getTypeDescriptor().isEnum(); 1151 boolean repeated = field.getRule()==FieldDescriptor.REPEATED_RULE; 1152 1153 // Create the fields.. 1154 p("// " + field.getRule() + " " + field.getType() + " " + field.getName() + " = " + field.getTag() + ";"); 1155 1156 if( repeated ) { 1157 p("private java.util.List<" + type + "> f_" + lname + ";"); 1158 p(); 1159 1160 // Create the field accessors 1161 p("public boolean has" + uname + "() {"); 1162 indent(); 1163 if( deferredDecode ) { 1164 p("load();"); 1165 } 1166 p("return this.f_" + lname + "!=null && !this.f_" + lname + ".isEmpty();"); 1167 unindent(); 1168 p("}"); 1169 p(); 1170 1171 p("public java.util.List<" + type + "> get" + uname + "List() {"); 1172 indent(); 1173 if( deferredDecode ) { 1174 p("load();"); 1175 } 1176 p("if( this.f_" + lname + " == null ) {"); 1177 indent(); 1178 p("this.f_" + lname + " = new java.util.ArrayList<" + type + ">();"); 1179 unindent(); 1180 p("}"); 1181 p("return this.f_" + lname + ";"); 1182 unindent(); 1183 p("}"); 1184 p(); 1185 1186 p("public T set" + uname + "List(java.util.List<" + type + "> " + lname + ") {"); 1187 indent(); 1188 p("loadAndClear();"); 1189 p("this.f_" + lname + " = " + lname + ";"); 1190 p("return (T)this;"); 1191 unindent(); 1192 p("}"); 1193 p(); 1194 1195 p("public int get" + uname + "Count() {"); 1196 indent(); 1197 if( deferredDecode ) { 1198 p("load();"); 1199 } 1200 p("if( this.f_" + lname + " == null ) {"); 1201 indent(); 1202 p("return 0;"); 1203 unindent(); 1204 p("}"); 1205 p("return this.f_" + lname + ".size();"); 1206 unindent(); 1207 p("}"); 1208 p(); 1209 1210 p("public " + type + " get" + uname + "(int index) {"); 1211 indent(); 1212 if( deferredDecode ) { 1213 p("load();"); 1214 } 1215 p("if( this.f_" + lname + " == null ) {"); 1216 indent(); 1217 p("return null;"); 1218 unindent(); 1219 p("}"); 1220 p("return this.f_" + lname + ".get(index);"); 1221 unindent(); 1222 p("}"); 1223 p(); 1224 1225 p("public T set" + uname + "(int index, " + type + " value) {"); 1226 indent(); 1227 p("loadAndClear();"); 1228 p("get" + uname + "List().set(index, value);"); 1229 p("return (T)this;"); 1230 unindent(); 1231 p("}"); 1232 p(); 1233 1234 p("public T add" + uname + "(" + type + " value) {"); 1235 indent(); 1236 p("loadAndClear();"); 1237 p("get" + uname + "List().add(value);"); 1238 p("return (T)this;"); 1239 unindent(); 1240 p("}"); 1241 p(); 1242 1243 p("public T addAll" + uname + "(java.lang.Iterable<? extends " + type + "> collection) {"); 1244 indent(); 1245 p("loadAndClear();"); 1246 p("super.addAll(collection, get" + uname + "List());"); 1247 p("return (T)this;"); 1248 unindent(); 1249 p("}"); 1250 p(); 1251 1252 p("public void clear" + uname + "() {"); 1253 indent(); 1254 p("loadAndClear();"); 1255 p("this.f_" + lname + " = null;"); 1256 unindent(); 1257 p("}"); 1258 p(); 1259 1260 } else { 1261 1262 p("private " + type + " f_" + lname + " = "+typeDefault+";"); 1263 if (primitive) { 1264 p("private boolean b_" + lname + ";"); 1265 } 1266 p(); 1267 1268 // Create the field accessors 1269 p("public boolean has" + uname + "() {"); 1270 indent(); 1271 if( deferredDecode ) { 1272 p("load();"); 1273 } 1274 if (primitive) { 1275 p("return this.b_" + lname + ";"); 1276 } else { 1277 p("return this.f_" + lname + "!=null;"); 1278 } 1279 unindent(); 1280 p("}"); 1281 p(); 1282 1283 p("public " + type + " get" + uname + "() {"); 1284 indent(); 1285 if( deferredDecode ) { 1286 p("load();"); 1287 } 1288 if( field.getTypeDescriptor()!=null && !field.getTypeDescriptor().isEnum()) { 1289 p("if( this.f_" + lname + " == null ) {"); 1290 indent(); 1291 p("this.f_" + lname + " = new " + type + "();"); 1292 unindent(); 1293 p("}"); 1294 } 1295 p("return this.f_" + lname + ";"); 1296 unindent(); 1297 p("}"); 1298 p(); 1299 1300 p("public T set" + uname + "(" + type + " " + lname + ") {"); 1301 indent(); 1302 p("loadAndClear();"); 1303 if (primitive) { 1304 if( auto_clear_optional_fields && field.isOptional() ) { 1305 if( field.isStringType() && !"null".equals(typeDefault)) { 1306 p("this.b_" + lname + " = ("+lname+" != "+typeDefault+");"); 1307 } else { 1308 p("this.b_" + lname + " = ("+lname+" != "+typeDefault+");"); 1309 } 1310 } else { 1311 p("this.b_" + lname + " = true;"); 1312 } 1313 } 1314 p("this.f_" + lname + " = " + lname + ";"); 1315 p("return (T)this;"); 1316 unindent(); 1317 p("}"); 1318 p(); 1319 1320 p("public void clear" + uname + "() {"); 1321 indent(); 1322 p("loadAndClear();"); 1323 if (primitive) { 1324 p("this.b_" + lname + " = false;"); 1325 } 1326 p("this.f_" + lname + " = " + typeDefault + ";"); 1327 unindent(); 1328 p("}"); 1329 p(); 1330 } 1331 1332 } 1333 1334 private String javaTypeDefault(FieldDescriptor field) { 1335 OptionDescriptor defaultOption = field.getOptions().get("default"); 1336 if( defaultOption!=null ) { 1337 if( field.isStringType() ) { 1338 return asJavaString(defaultOption.getValue()); 1339 } else if( field.getType() == FieldDescriptor.BYTES_TYPE ) { 1340 return "new org.fusesource.hawtbuf.Buffer(org.fusesource.hawtbuf.UTF8Buffer.encode("+asJavaString(defaultOption.getValue())+"))"; 1341 } else if( field.isInteger32Type() ) { 1342 int v; 1343 if( field.getType() == FieldDescriptor.UINT32_TYPE ) { 1344 v = TextFormat.parseUInt32(defaultOption.getValue()); 1345 } else { 1346 v = TextFormat.parseInt32(defaultOption.getValue()); 1347 } 1348 return ""+v; 1349 } else if( field.isInteger64Type() ) { 1350 long v; 1351 if( field.getType() == FieldDescriptor.UINT64_TYPE ) { 1352 v = TextFormat.parseUInt64(defaultOption.getValue()); 1353 } else { 1354 v = TextFormat.parseInt64(defaultOption.getValue()); 1355 } 1356 return ""+v+"l"; 1357 } else if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) { 1358 double v = Double.valueOf(defaultOption.getValue()); 1359 return ""+v+"d"; 1360 } else if( field.getType() == FieldDescriptor.FLOAT_TYPE ) { 1361 float v = Float.valueOf(defaultOption.getValue()); 1362 return ""+v+"f"; 1363 } else if( field.getType() == FieldDescriptor.BOOL_TYPE ) { 1364 boolean v = Boolean.valueOf(defaultOption.getValue()); 1365 return ""+v; 1366 } else if( field.getTypeDescriptor()!=null && field.getTypeDescriptor().isEnum() ) { 1367 return javaType(field)+"."+defaultOption.getValue(); 1368 } 1369 return defaultOption.getValue(); 1370 } else { 1371 if( field.isNumberType() ) { 1372 return "0"; 1373 } 1374 if( field.getType() == FieldDescriptor.BOOL_TYPE ) { 1375 return "false"; 1376 } 1377 return "null"; 1378 } 1379 } 1380 1381 static final char HEX_TABLE[] = new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 1382 1383 private String asJavaString(String value) { 1384 StringBuilder sb = new StringBuilder(value.length()+2); 1385 sb.append("\""); 1386 for (int i = 0; i < value.length(); i++) { 1387 1388 char b = value.charAt(i); 1389 switch (b) { 1390 // Java does not recognize \a or \v, apparently. 1391 case '\b': sb.append("\\b" ); break; 1392 case '\f': sb.append("\\f" ); break; 1393 case '\n': sb.append("\\n" ); break; 1394 case '\r': sb.append("\\r" ); break; 1395 case '\t': sb.append("\\t" ); break; 1396 case '\\': sb.append("\\\\"); break; 1397 case '\'': sb.append("\\\'"); break; 1398 case '"' : sb.append("\\\""); break; 1399 default: 1400 if (b >= 0x20 && b <'Z') { 1401 sb.append((char) b); 1402 } else { 1403 sb.append("\\u"); 1404 sb.append(HEX_TABLE[(b >>> 12) & 0x0F] ); 1405 sb.append(HEX_TABLE[(b >>> 8) & 0x0F] ); 1406 sb.append(HEX_TABLE[(b >>> 4) & 0x0F] ); 1407 sb.append(HEX_TABLE[b & 0x0F] ); 1408 } 1409 break; 1410 } 1411 1412 } 1413 sb.append("\""); 1414 return sb.toString(); 1415 } 1416 1417 private void generateEnum(EnumDescriptor ed) { 1418 String uname = uCamel(ed.getName()); 1419 1420 String staticOption = "static "; 1421 if( multipleFiles && ed.getParent()==null ) { 1422 staticOption=""; 1423 } 1424 1425 // TODO Auto-generated method stub 1426 p(); 1427 p("public "+staticOption+"enum " +uname + " {"); 1428 indent(); 1429 1430 1431 p(); 1432 int counter=0; 1433 for (EnumFieldDescriptor field : ed.getFields().values()) { 1434 boolean last = counter+1 == ed.getFields().size(); 1435 p(field.getName()+"(\""+field.getName()+"\", "+field.getValue()+")"+(last?";":",")); 1436 counter++; 1437 } 1438 p(); 1439 p("private final String name;"); 1440 p("private final int value;"); 1441 p(); 1442 p("private "+uname+"(String name, int value) {"); 1443 p(" this.name = name;"); 1444 p(" this.value = value;"); 1445 p("}"); 1446 p(); 1447 p("public final int getNumber() {"); 1448 p(" return value;"); 1449 p("}"); 1450 p(); 1451 p("public final String toString() {"); 1452 p(" return name;"); 1453 p("}"); 1454 p(); 1455 p("public static "+uname+" valueOf(int value) {"); 1456 p(" switch (value) {"); 1457 1458 // It's possible to define multiple ENUM fields with the same value.. 1459 // we only want to put the first one into the switch statement. 1460 HashSet<Integer> values = new HashSet<Integer>(); 1461 for (EnumFieldDescriptor field : ed.getFields().values()) { 1462 if( !values.contains(field.getValue()) ) { 1463 p(" case "+field.getValue()+":"); 1464 p(" return "+field.getName()+";"); 1465 values.add(field.getValue()); 1466 } 1467 1468 } 1469 p(" default:"); 1470 p(" return null;"); 1471 p(" }"); 1472 p("}"); 1473 p(); 1474 1475 1476 String createMessage = getOption(ed.getOptions(), "java_create_message", null); 1477 if( "true".equals(createMessage) ) { 1478 p("public org.fusesource.hawtbuf.proto.Message createMessage() {"); 1479 indent(); 1480 p("switch (this) {"); 1481 indent(); 1482 for (EnumFieldDescriptor field : ed.getFields().values()) { 1483 p("case "+field.getName()+":"); 1484 String type = constantToUCamelCase(field.getName()); 1485 p(" return new "+type+"();"); 1486 } 1487 p("default:"); 1488 p(" return null;"); 1489 unindent(); 1490 p("}"); 1491 unindent(); 1492 p("}"); 1493 p(); 1494 } 1495 1496 unindent(); 1497 p("}"); 1498 p(); 1499 } 1500 1501 1502 1503 private String javaCollectionType(FieldDescriptor field) { 1504 if( field.isInteger32Type() ) { 1505 return "java.lang.Integer"; 1506 } 1507 if( field.isInteger64Type() ) { 1508 return "java.lang.Long"; 1509 } 1510 if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) { 1511 return "java.lang.Double"; 1512 } 1513 if( field.getType() == FieldDescriptor.FLOAT_TYPE ) { 1514 return "java.lang.Float"; 1515 } 1516 if( field.getType() == FieldDescriptor.STRING_TYPE ) { 1517 return "java.lang.String"; 1518 } 1519 if( field.getType() == FieldDescriptor.BYTES_TYPE ) { 1520 return "org.fusesource.hawtbuf.Buffer"; 1521 } 1522 if( field.getType() == FieldDescriptor.BOOL_TYPE ) { 1523 return "java.lang.Boolean"; 1524 } 1525 1526 TypeDescriptor descriptor = field.getTypeDescriptor(); 1527 return javaType(descriptor); 1528 } 1529 1530 private String javaType(FieldDescriptor field) { 1531 if( field.isInteger32Type() ) { 1532 return "int"; 1533 } 1534 if( field.isInteger64Type() ) { 1535 return "long"; 1536 } 1537 if( field.getType() == FieldDescriptor.DOUBLE_TYPE ) { 1538 return "double"; 1539 } 1540 if( field.getType() == FieldDescriptor.FLOAT_TYPE ) { 1541 return "float"; 1542 } 1543 if( field.getType() == FieldDescriptor.STRING_TYPE ) { 1544 return "java.lang.String"; 1545 } 1546 if( field.getType() == FieldDescriptor.BYTES_TYPE ) { 1547 return "org.fusesource.hawtbuf.Buffer"; 1548 } 1549 if( field.getType() == FieldDescriptor.BOOL_TYPE ) { 1550 return "boolean"; 1551 } 1552 1553 TypeDescriptor descriptor = field.getTypeDescriptor(); 1554 return javaType(descriptor); 1555 } 1556 1557 private String javaType(TypeDescriptor descriptor) { 1558 ProtoDescriptor p = descriptor.getProtoDescriptor(); 1559 if( p != proto ) { 1560 // Try to keep it short.. 1561 String othePackage = javaPackage(p); 1562 if( equals(othePackage,javaPackage(proto) ) ) { 1563 return javaClassName(p)+"."+descriptor.getQName(); 1564 } 1565 // Use the fully qualified class name. 1566 return othePackage+"."+javaClassName(p)+"."+descriptor.getQName(); 1567 } 1568 return descriptor.getQName(); 1569 } 1570 1571 private boolean equals(String o1, String o2) { 1572 if( o1==o2 ) 1573 return true; 1574 if( o1==null || o2==null ) 1575 return false; 1576 return o1.equals(o2); 1577 } 1578 1579 private String javaClassName(ProtoDescriptor proto) { 1580 return getOption(proto.getOptions(), "java_outer_classname", uCamel(removeFileExtension(proto.getName()))); 1581 } 1582 1583 private boolean isMultipleFilesEnabled(ProtoDescriptor proto) { 1584 return "true".equals(getOption(proto.getOptions(), "java_multiple_files", "false")); 1585 } 1586 1587 1588 private String javaPackage(ProtoDescriptor proto) { 1589 String name = proto.getPackageName(); 1590 if( name!=null ) { 1591 name = name.replace('-', '.'); 1592 name = name.replace('/', '.'); 1593 } 1594 return getOption(proto.getOptions(), "java_package", name); 1595 } 1596 1597 1598 // ---------------------------------------------------------------- 1599 // Internal Helper methods 1600 // ---------------------------------------------------------------- 1601 1602 private void indent() { 1603 indent++; 1604 } 1605 1606 private void unindent() { 1607 indent--; 1608 } 1609 1610 private void p(String line) { 1611 // Indent... 1612 for (int i = 0; i < indent; i++) { 1613 w.print(" "); 1614 } 1615 // Then print. 1616 w.println(line); 1617 } 1618 1619 private void p() { 1620 w.println(); 1621 } 1622 1623 private String getOption(Map<String, OptionDescriptor> options, String optionName, String defaultValue) { 1624 OptionDescriptor optionDescriptor = options.get(optionName); 1625 if (optionDescriptor == null) { 1626 return defaultValue; 1627 } 1628 return optionDescriptor.getValue(); 1629 } 1630 1631 static private String removeFileExtension(String name) { 1632 return name.replaceAll("\\..*", ""); 1633 } 1634 1635 static private String uCamel(String name) { 1636 boolean upNext=true; 1637 StringBuilder sb = new StringBuilder(); 1638 for (int i = 0; i < name.length(); i++) { 1639 char c = name.charAt(i); 1640 if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) { 1641 if( upNext ) { 1642 c = Character.toUpperCase(c); 1643 upNext=false; 1644 } 1645 sb.append(c); 1646 } else { 1647 upNext=true; 1648 } 1649 } 1650 return sb.toString(); 1651 } 1652 1653 static private String lCamel(String name) { 1654 if( name == null || name.length()<1 ) 1655 return name; 1656 String uCamel = uCamel(name); 1657 return uCamel.substring(0,1).toLowerCase()+uCamel.substring(1); 1658 } 1659 1660 1661 private String constantToUCamelCase(String name) { 1662 boolean upNext=true; 1663 StringBuilder sb = new StringBuilder(); 1664 for (int i = 0; i < name.length(); i++) { 1665 char c = name.charAt(i); 1666 if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) { 1667 if( upNext ) { 1668 c = Character.toUpperCase(c); 1669 upNext=false; 1670 } else { 1671 c = Character.toLowerCase(c); 1672 } 1673 sb.append(c); 1674 } else { 1675 upNext=true; 1676 } 1677 } 1678 return sb.toString(); 1679 } 1680 1681 1682 private String constantCase(String name) { 1683 StringBuilder sb = new StringBuilder(); 1684 for (int i = 0; i < name.length(); i++) { 1685 char c = name.charAt(i); 1686 if( i!=0 && Character.isUpperCase(c) ) { 1687 sb.append("_"); 1688 } 1689 sb.append(Character.toUpperCase(c)); 1690 } 1691 return sb.toString(); 1692 } 1693 1694 public File getOut() { 1695 return out; 1696 } 1697 1698 public void setOut(File outputDirectory) { 1699 this.out = outputDirectory; 1700 } 1701 1702 public File[] getPath() { 1703 return path; 1704 } 1705 1706 public void setPath(File[] path) { 1707 this.path = path; 1708 } 1709 1710 }