1 18 package org.apache.activemq.openwire.tool; 19 20 import org.codehaus.jam.JAnnotation; 21 import org.codehaus.jam.JAnnotationValue; 22 import org.codehaus.jam.JClass; 23 import org.codehaus.jam.JProperty; 24 25 import java.io.*; 26 import java.util.*; 27 28 32 public class CSharpMarshallingGenerator extends JavaMarshallingGenerator { 33 34 protected String targetDir="./src/main/csharp"; 35 36 public Object run() { 37 filePostFix = ".cs"; 38 if (destDir == null) { 39 destDir = new File(targetDir+"/ActiveMQ/OpenWire/V"+getOpenwireVersion()); 40 } 41 return super.run(); 42 } 43 44 48 protected void generateTightUnmarshalBodyForProperty(PrintWriter out, JProperty property, JAnnotationValue size) { 49 50 String propertyName = property.getSimpleName(); 51 String type = property.getType().getSimpleName(); 52 53 if (type.equals("boolean")) { 54 out.println(" info." + propertyName + " = bs.ReadBoolean();"); 55 } 56 else if (type.equals("byte")) { 57 out.println(" info." + propertyName + " = dataIn.ReadByte();"); 58 } 59 else if (type.equals("char")) { 60 out.println(" info." + propertyName + " = dataIn.ReadChar();"); 61 } 62 else if (type.equals("short")) { 63 out.println(" info." + propertyName + " = dataIn.ReadInt16();"); 64 } 65 else if (type.equals("int")) { 66 out.println(" info." + propertyName + " = dataIn.ReadInt32();"); 67 } 68 else if (type.equals("long")) { 69 out.println(" info." + propertyName + " = TightUnmarshalLong(wireFormat, dataIn, bs);"); 70 } 71 else if (type.equals("String")) { 72 out.println(" info." + propertyName + " = TightUnmarshalString(dataIn, bs);"); 73 } 74 else if (type.equals("byte[]") || type.equals("ByteSequence")) { 75 if (size != null) { 76 out.println(" info." + propertyName + " = ReadBytes(dataIn, " + size.asInt() + ");"); 77 } 78 else { 79 out.println(" info." + propertyName + " = ReadBytes(dataIn, bs.ReadBoolean());"); 80 } 81 } 82 else if (isThrowable(property.getType())) { 83 out.println(" info." + propertyName + " = TightUnmarshalBrokerError(wireFormat, dataIn, bs);"); 84 } 85 else if (isCachedProperty(property)) { 86 out.println(" info." + propertyName + " = (" + type + ") TightUnmarshalCachedObject(wireFormat, dataIn, bs);"); 87 } 88 else { 89 out.println(" info." + propertyName + " = (" + type + ") TightUnmarshalNestedObject(wireFormat, dataIn, bs);"); 90 } 91 } 92 93 protected void generateTightUnmarshalBodyForArrayProperty(PrintWriter out, JProperty property, JAnnotationValue size) { 94 JClass propertyType = property.getType(); 95 String arrayType = propertyType.getArrayComponentType().getSimpleName(); 96 String propertyName = property.getSimpleName(); 97 out.println(); 98 if (size != null) { 99 out.println(" {"); 100 out.println(" " + arrayType + "[] value = new " + arrayType + "[" + size.asInt() + "];"); 101 out.println(" " + "for( int i=0; i < " + size.asInt() + "; i++ ) {"); 102 out.println(" value[i] = (" + arrayType + ") TightUnmarshalNestedObject(wireFormat,dataIn, bs);"); 103 out.println(" }"); 104 out.println(" info." + propertyName + " = value;"); 105 out.println(" }"); 106 } 107 else { 108 out.println(" if (bs.ReadBoolean()) {"); 109 out.println(" short size = dataIn.ReadInt16();"); 110 out.println(" " + arrayType + "[] value = new " + arrayType + "[size];"); 111 out.println(" for( int i=0; i < size; i++ ) {"); 112 out.println(" value[i] = (" + arrayType + ") TightUnmarshalNestedObject(wireFormat,dataIn, bs);"); 113 out.println(" }"); 114 out.println(" info." + propertyName + " = value;"); 115 out.println(" }"); 116 out.println(" else {"); 117 out.println(" info." + propertyName + " = null;"); 118 out.println(" }"); 119 } 120 } 121 122 protected int generateTightMarshal1Body(PrintWriter out) { 123 List properties = getProperties(); 124 int baseSize = 0; 125 for (Iterator iter = properties.iterator(); iter.hasNext();) { 126 JProperty property = (JProperty) iter.next(); 127 JAnnotation annotation = property.getAnnotation("openwire:property"); 128 JAnnotationValue size = annotation.getValue("size"); 129 JClass propertyType = property.getType(); 130 String type = propertyType.getSimpleName(); 131 String getter = "info." + property.getSimpleName(); 132 133 if (type.equals("boolean")) { 134 out.println(" bs.WriteBoolean(" + getter + ");"); 135 } 136 else if (type.equals("byte")) { 137 baseSize += 1; 138 } 139 else if (type.equals("char")) { 140 baseSize += 2; 141 } 142 else if (type.equals("short")) { 143 baseSize += 2; 144 } 145 else if (type.equals("int")) { 146 baseSize += 4; 147 } 148 else if (type.equals("long")) { 149 out.println(" rc += TightMarshalLong1(wireFormat, " + getter + ", bs);"); 150 } 151 else if (type.equals("String")) { 152 out.print(""); 153 out.println(" rc += TightMarshalString1(" + getter + ", bs);"); 154 } 155 else if (type.equals("byte[]") || type.equals("ByteSequence")) { 156 if (size == null) { 157 out.println(" bs.WriteBoolean(" + getter + "!=null);"); 158 out.println(" rc += " + getter + "==null ? 0 : " + getter + ".Length+4;"); 159 } 160 else { 161 baseSize += size.asInt(); 162 } 163 } 164 else if (propertyType.isArrayType()) { 165 if (size != null) { 166 out.println(" rc += TightMarshalObjectArrayConstSize1(wireFormat, " + getter + ", bs, " + size.asInt() + ");"); 167 } 168 else { 169 out.println(" rc += TightMarshalObjectArray1(wireFormat, " + getter + ", bs);"); 170 } 171 } 172 else if (isThrowable(propertyType)) { 173 out.println(" rc += TightMarshalBrokerError1(wireFormat, " + getter + ", bs);"); 174 } 175 else { 176 if (isCachedProperty(property)) { 177 out.println(" rc += TightMarshalCachedObject1(wireFormat, (DataStructure)" + getter + ", bs);"); 178 } 179 else { 180 out.println(" rc += TightMarshalNestedObject1(wireFormat, (DataStructure)" + getter + ", bs);"); 181 } 182 } 183 } 184 return baseSize; 185 } 186 187 protected void generateTightMarshal2Body(PrintWriter out) { 188 List properties = getProperties(); 189 for (Iterator iter = properties.iterator(); iter.hasNext();) { 190 JProperty property = (JProperty) iter.next(); 191 JAnnotation annotation = property.getAnnotation("openwire:property"); 192 JAnnotationValue size = annotation.getValue("size"); 193 JClass propertyType = property.getType(); 194 String type = propertyType.getSimpleName(); 195 String getter = "info." + property.getSimpleName(); 196 197 if (type.equals("boolean")) { 198 out.println(" bs.ReadBoolean();"); 199 } 200 else if (type.equals("byte")) { 201 out.println(" dataOut.Write(" + getter + ");"); 202 } 203 else if (type.equals("char")) { 204 out.println(" dataOut.Write(" + getter + ");"); 205 } 206 else if (type.equals("short")) { 207 out.println(" dataOut.Write(" + getter + ");"); 208 } 209 else if (type.equals("int")) { 210 out.println(" dataOut.Write(" + getter + ");"); 211 } 212 else if (type.equals("long")) { 213 out.println(" TightMarshalLong2(wireFormat, " + getter + ", dataOut, bs);"); 214 } 215 else if (type.equals("String")) { 216 out.println(" TightMarshalString2(" + getter + ", dataOut, bs);"); 217 } 218 else if (type.equals("byte[]") || type.equals("ByteSequence")) { 219 if (size != null) { 220 out.println(" dataOut.Write(" + getter + ", 0, " + size.asInt() + ");"); 221 } 222 else { 223 out.println(" if(bs.ReadBoolean()) {"); 224 out.println(" dataOut.Write(" + getter + ".Length);"); 225 out.println(" dataOut.Write(" + getter + ");"); 226 out.println(" }"); 227 } 228 } 229 else if (propertyType.isArrayType()) { 230 if (size != null) { 231 out.println(" TightMarshalObjectArrayConstSize2(wireFormat, " + getter + ", dataOut, bs, " + size.asInt() + ");"); 232 } 233 else { 234 out.println(" TightMarshalObjectArray2(wireFormat, " + getter + ", dataOut, bs);"); 235 } 236 } 237 else if (isThrowable(propertyType)) { 238 out.println(" TightMarshalBrokerError2(wireFormat, " + getter + ", dataOut, bs);"); 239 } 240 else { 241 if (isCachedProperty(property)) { 242 out.println(" TightMarshalCachedObject2(wireFormat, (DataStructure)" + getter + ", dataOut, bs);"); 243 } 244 else { 245 out.println(" TightMarshalNestedObject2(wireFormat, (DataStructure)" + getter + ", dataOut, bs);"); 246 } 247 } 248 } 249 } 250 251 255 protected void generateLooseUnmarshalBodyForProperty(PrintWriter out, JProperty property, JAnnotationValue size) { 256 257 String propertyName = property.getSimpleName(); 258 String type = property.getType().getSimpleName(); 259 260 if (type.equals("boolean")) { 261 out.println(" info." + propertyName + " = dataIn.ReadBoolean();"); 262 } 263 else if (type.equals("byte")) { 264 out.println(" info." + propertyName + " = dataIn.ReadByte();"); 265 } 266 else if (type.equals("char")) { 267 out.println(" info." + propertyName + " = dataIn.ReadChar();"); 268 } 269 else if (type.equals("short")) { 270 out.println(" info." + propertyName + " = dataIn.ReadInt16();"); 271 } 272 else if (type.equals("int")) { 273 out.println(" info." + propertyName + " = dataIn.ReadInt32();"); 274 } 275 else if (type.equals("long")) { 276 out.println(" info." + propertyName + " = LooseUnmarshalLong(wireFormat, dataIn);"); 277 } 278 else if (type.equals("String")) { 279 out.println(" info." + propertyName + " = LooseUnmarshalString(dataIn);"); 280 } 281 else if (type.equals("byte[]") || type.equals("ByteSequence")) { 282 if (size != null) { 283 out.println(" info." + propertyName + " = ReadBytes(dataIn, " + size.asInt() + ");"); 284 } 285 else { 286 out.println(" info." + propertyName + " = ReadBytes(dataIn, dataIn.ReadBoolean());"); 287 } 288 } 289 else if (isThrowable(property.getType())) { 290 out.println(" info." + propertyName + " = LooseUnmarshalBrokerError(wireFormat, dataIn);"); 291 } 292 else if (isCachedProperty(property)) { 293 out.println(" info." + propertyName + " = (" + type + ") LooseUnmarshalCachedObject(wireFormat, dataIn);"); 294 } 295 else { 296 out.println(" info." + propertyName + " = (" + type + ") LooseUnmarshalNestedObject(wireFormat, dataIn);"); 297 } 298 } 299 300 protected void generateLooseUnmarshalBodyForArrayProperty(PrintWriter out, JProperty property, JAnnotationValue size) { 301 JClass propertyType = property.getType(); 302 String arrayType = propertyType.getArrayComponentType().getSimpleName(); 303 String propertyName = property.getSimpleName(); 304 out.println(); 305 if (size != null) { 306 out.println(" {"); 307 out.println(" " + arrayType + "[] value = new " + arrayType + "[" + size.asInt() + "];"); 308 out.println(" " + "for( int i=0; i < " + size.asInt() + "; i++ ) {"); 309 out.println(" value[i] = (" + arrayType + ") LooseUnmarshalNestedObject(wireFormat,dataIn);"); 310 out.println(" }"); 311 out.println(" info." + propertyName + " = value;"); 312 out.println(" }"); 313 } 314 else { 315 out.println(" if (dataIn.ReadBoolean()) {"); 316 out.println(" short size = dataIn.ReadInt16();"); 317 out.println(" " + arrayType + "[] value = new " + arrayType + "[size];"); 318 out.println(" for( int i=0; i < size; i++ ) {"); 319 out.println(" value[i] = (" + arrayType + ") LooseUnmarshalNestedObject(wireFormat,dataIn);"); 320 out.println(" }"); 321 out.println(" info." + propertyName + " = value;"); 322 out.println(" }"); 323 out.println(" else {"); 324 out.println(" info." + propertyName + " = null;"); 325 out.println(" }"); 326 } 327 } 328 329 330 protected void generateLooseMarshalBody(PrintWriter out) { 331 List properties = getProperties(); 332 for (Iterator iter = properties.iterator(); iter.hasNext();) { 333 JProperty property = (JProperty) iter.next(); 334 JAnnotation annotation = property.getAnnotation("openwire:property"); 335 JAnnotationValue size = annotation.getValue("size"); 336 JClass propertyType = property.getType(); 337 String type = propertyType.getSimpleName(); 338 String getter = "info." + property.getSimpleName(); 339 340 if (type.equals("boolean")) { 341 out.println(" dataOut.Write(" + getter + ");"); 342 } 343 else if (type.equals("byte")) { 344 out.println(" dataOut.Write(" + getter + ");"); 345 } 346 else if (type.equals("char")) { 347 out.println(" dataOut.Write(" + getter + ");"); 348 } 349 else if (type.equals("short")) { 350 out.println(" dataOut.Write(" + getter + ");"); 351 } 352 else if (type.equals("int")) { 353 out.println(" dataOut.Write(" + getter + ");"); 354 } 355 else if (type.equals("long")) { 356 out.println(" LooseMarshalLong(wireFormat, " + getter + ", dataOut);"); 357 } 358 else if (type.equals("String")) { 359 out.println(" LooseMarshalString(" + getter + ", dataOut);"); 360 } 361 else if (type.equals("byte[]") || type.equals("ByteSequence")) { 362 if (size != null) { 363 out.println(" dataOut.Write(" + getter + ", 0, " + size.asInt() + ");"); 364 } 365 else { 366 out.println(" dataOut.Write(" + getter + "!=null);"); 367 out.println(" if(" + getter + "!=null) {"); 368 out.println(" dataOut.Write(" + getter + ".Length);"); 369 out.println(" dataOut.Write(" + getter + ");"); 370 out.println(" }"); 371 } 372 } 373 else if (propertyType.isArrayType()) { 374 if (size != null) { 375 out.println(" LooseMarshalObjectArrayConstSize(wireFormat, " + getter + ", dataOut, " + size.asInt() + ");"); 376 } 377 else { 378 out.println(" LooseMarshalObjectArray(wireFormat, " + getter + ", dataOut);"); 379 } 380 } 381 else if (isThrowable(propertyType)) { 382 out.println(" LooseMarshalBrokerError(wireFormat, " + getter + ", dataOut);"); 383 } 384 else { 385 if (isCachedProperty(property)) { 386 out.println(" LooseMarshalCachedObject(wireFormat, (DataStructure)" + getter + ", dataOut);"); 387 } 388 else { 389 out.println(" LooseMarshalNestedObject(wireFormat, (DataStructure)" + getter + ", dataOut);"); 390 } 391 } 392 } 393 } 394 395 public String getTargetDir() { 396 return targetDir; 397 } 398 399 public void setTargetDir(String targetDir) { 400 this.targetDir = targetDir; 401 } 402 403 private void generateLicence(PrintWriter out) { 404 out.println("/*"); 405 out.println(" * Licensed to the Apache Software Foundation (ASF) under one or more"); 406 out.println(" * contributor license agreements. See the NOTICE file distributed with"); 407 out.println(" * this work for additional information regarding copyright ownership."); 408 out.println(" * The ASF licenses this file to You under the Apache License, Version 2.0"); 409 out.println(" * (the \"License\"); you may not use this file except in compliance with"); 410 out.println(" * the License. You may obtain a copy of the License at"); 411 out.println(" *"); 412 out.println(" * http://www.apache.org/licenses/LICENSE-2.0"); 413 out.println(" *"); 414 out.println(" * Unless required by applicable law or agreed to in writing, software"); 415 out.println(" * distributed under the License is distributed on an \"AS IS\" BASIS,"); 416 out.println(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."); 417 out.println(" * See the License for the specific language governing permissions and"); 418 out.println(" * limitations under the License."); 419 out.println(" */"); 420 } 421 422 protected void generateFile(PrintWriter out) throws Exception { 423 generateLicence(out); 424 out.println(""); 425 out.println("//"); 426 out.println("// NOTE!: This file is autogenerated - do not modify!"); 427 out.println("// if you need to make a change, please see the Groovy scripts in the"); 428 out.println("// activemq-core module"); 429 out.println("//"); 430 out.println(""); 431 out.println("using System;"); 432 out.println("using System.Collections;"); 433 out.println("using System.IO;"); 434 out.println(""); 435 out.println("using ActiveMQ.Commands;"); 436 out.println("using ActiveMQ.OpenWire;"); 437 out.println("using ActiveMQ.OpenWire.V"+getOpenwireVersion()+";"); 438 out.println(""); 439 out.println("namespace ActiveMQ.OpenWire.V"+getOpenwireVersion()+""); 440 out.println("{"); 441 out.println(" /// <summary>"); 442 out.println(" /// Marshalling code for Open Wire Format for "+jclass.getSimpleName()+""); 443 out.println(" /// </summary>"); 444 out.println(" "+getAbstractClassText()+"class "+getClassName()+" : "+getBaseClass()+""); 445 out.println(" {"); 446 447 if( !isAbstractClass() ) { 448 out.println(""); 449 out.println(""); 450 out.println(" public override DataStructure CreateObject() "); 451 out.println(" {"); 452 out.println(" return new "+jclass.getSimpleName()+"();"); 453 out.println(" }"); 454 out.println(""); 455 out.println(" public override byte GetDataStructureType() "); 456 out.println(" {"); 457 out.println(" return "+jclass.getSimpleName()+".ID_"+jclass.getSimpleName()+";"); 458 out.println(" }"); 459 } 460 461 464 out.println(""); 465 out.println(" // "); 466 out.println(" // Un-marshal an object instance from the data input stream"); 467 out.println(" // "); 468 out.println(" public override void TightUnmarshal(OpenWireFormat wireFormat, Object o, BinaryReader dataIn, BooleanStream bs) "); 469 out.println(" {"); 470 out.println(" base.TightUnmarshal(wireFormat, o, dataIn, bs);"); 471 472 if( !getProperties().isEmpty() || isMarshallerAware() ) { 473 out.println(""); 474 out.println(" "+jclass.getSimpleName()+" info = ("+jclass.getSimpleName()+")o;"); 475 } 476 477 if( isMarshallerAware() ){ 478 out.println(""); 479 out.println(" info.BeforeUnmarshall(wireFormat);"); 480 out.println(""); 481 } 482 483 generateTightUnmarshalBody(out); 484 485 if( isMarshallerAware() ){ 486 out.println(""); 487 out.println(" info.AfterUnmarshall(wireFormat);"); 488 } 489 490 out.println(""); 491 out.println(" }"); 492 out.println(""); 493 out.println(" //"); 494 out.println(" // Write the booleans that this object uses to a BooleanStream"); 495 out.println(" //"); 496 out.println(" public override int TightMarshal1(OpenWireFormat wireFormat, Object o, BooleanStream bs) {"); 497 out.println(" "+jclass.getSimpleName()+" info = ("+jclass.getSimpleName()+")o;"); 498 499 if( isMarshallerAware() ) { 500 out.println(""); 501 out.println(" info.BeforeMarshall(wireFormat);"); 502 } 503 504 out.println(""); 505 out.println(" int rc = base.TightMarshal1(wireFormat, info, bs);"); 506 507 int baseSize = generateTightMarshal1Body(out); 508 509 out.println(""); 510 out.println(" return rc + "+baseSize+";"); 511 out.println(" }"); 512 out.println(""); 513 out.println(" // "); 514 out.println(" // Write a object instance to data output stream"); 515 out.println(" //"); 516 out.println(" public override void TightMarshal2(OpenWireFormat wireFormat, Object o, BinaryWriter dataOut, BooleanStream bs) {"); 517 out.println(" base.TightMarshal2(wireFormat, o, dataOut, bs);"); 518 519 if( !getProperties().isEmpty() || isMarshallerAware() ) { 520 out.println(""); 521 out.println(" "+jclass.getSimpleName()+" info = ("+jclass.getSimpleName()+")o;"); 522 } 523 524 generateTightMarshal2Body(out); 525 526 if( isMarshallerAware() ) { 527 out.println(""); 528 out.println(" info.AfterMarshall(wireFormat);"); 529 } 530 531 out.println(""); 532 out.println(" }"); 533 534 out.println(""); 535 out.println(" // "); 536 out.println(" // Un-marshal an object instance from the data input stream"); 537 out.println(" // "); 538 out.println(" public override void LooseUnmarshal(OpenWireFormat wireFormat, Object o, BinaryReader dataIn) "); 539 out.println(" {"); 540 out.println(" base.LooseUnmarshal(wireFormat, o, dataIn);"); 541 542 if( !getProperties().isEmpty() || isMarshallerAware() ) { 543 out.println(""); 544 out.println(" "+jclass.getSimpleName()+" info = ("+jclass.getSimpleName()+")o;"); 545 } 546 547 if( isMarshallerAware() ) { 548 out.println(""); 549 out.println(" info.BeforeUnmarshall(wireFormat);"); 550 out.println(""); 551 } 552 553 generateLooseUnmarshalBody(out); 554 555 if( isMarshallerAware() ) { 556 out.println(""); 557 out.println(" info.AfterUnmarshall(wireFormat);"); 558 } 559 560 out.println(""); 561 out.println(" }"); 562 out.println(""); 563 out.println(" // "); 564 out.println(" // Write a object instance to data output stream"); 565 out.println(" //"); 566 out.println(" public override void LooseMarshal(OpenWireFormat wireFormat, Object o, BinaryWriter dataOut) {"); 567 568 if( !getProperties().isEmpty() || isMarshallerAware() ) { 569 out.println(""); 570 out.println(" "+jclass.getSimpleName()+" info = ("+jclass.getSimpleName()+")o;"); 571 } 572 573 if( isMarshallerAware() ) { 574 out.println(""); 575 out.println(" info.BeforeMarshall(wireFormat);"); 576 } 577 578 out.println(""); 579 out.println(" base.LooseMarshal(wireFormat, o, dataOut);"); 580 581 generateLooseMarshalBody(out); 582 583 if( isMarshallerAware() ) { 584 out.println(""); 585 out.println(" info.AfterMarshall(wireFormat);"); 586 } 587 out.println(""); 588 out.println(" }"); 589 out.println(" }"); 590 out.println("}"); 591 592 } 593 594 595 public void generateFactory(PrintWriter out) { 596 generateLicence(out); 597 out.println(""); 598 out.println("//"); 599 out.println("// NOTE!: This file is autogenerated - do not modify!"); 600 out.println("// if you need to make a change, please see the Groovy scripts in the"); 601 out.println("// activemq-core module"); 602 out.println("//"); 603 out.println(""); 604 out.println("using System;"); 605 out.println("using System.Collections;"); 606 out.println("using System.IO;"); 607 out.println(""); 608 out.println("using ActiveMQ.Commands;"); 609 out.println("using ActiveMQ.OpenWire;"); 610 out.println("using ActiveMQ.OpenWire.V"+getOpenwireVersion()+";"); 611 out.println(""); 612 out.println("namespace ActiveMQ.OpenWire.V"+getOpenwireVersion()+""); 613 out.println("{"); 614 out.println(" /// <summary>"); 615 out.println(" /// Used to create marshallers for a specific version of the wire protocol"); 616 out.println(" /// </summary>"); 617 out.println(" public class MarshallerFactory : IMarshallerFactory"); 618 out.println(" {"); 619 out.println(" public void configure(OpenWireFormat format) "); 620 out.println(" {"); 621 out.println(" format.clearMarshallers();"); 622 623 List list = new ArrayList(getConcreteClasses()); 624 Collections.sort(list, new Comparator(){ 625 public int compare(Object o1, Object o2) { 626 JClass c1 = (JClass) o1; 627 JClass c2 = (JClass) o2; 628 return c1.getSimpleName().compareTo(c2.getSimpleName()); 629 }}); 630 631 for (Iterator iter = list.iterator(); iter.hasNext();) { 632 JClass jclass = (JClass) iter.next(); 633 out.println(" format.addMarshaller(new "+jclass.getSimpleName()+"Marshaller());"); 634 } 635 636 out.println(""); 637 out.println(" }"); 638 out.println(" }"); 639 out.println("}"); 640 641 } 642 } 643 | Popular Tags |