MC.java revision 560:dca8c03d693d
1/* 2 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package build.tools.logutil; 26 27import java.io.File; 28import java.io.FileNotFoundException; 29import java.io.FileOutputStream; 30import java.io.IOException; 31 32import java.util.Arrays; 33import java.util.Date; 34import java.util.Formatter; 35import java.util.List; 36import java.util.Queue; 37 38public class MC { 39 40 private static final String VERSION = "1.0"; 41 42 private static final List<String> SUN_EXCEPTION_GROUPS = Arrays.asList(new String[] 43 { "SUNBASE", "ORBUTIL", "ACTIVATION", "NAMING", "INTERCEPTORS", "POA", "IOR", "UTIL" }); 44 45 private static final List<String> EXCEPTIONS = Arrays.asList(new String[] 46 { "UNKNOWN", "BAD_PARAM", "NO_MEMORY", "IMP_LIMIT", "COMM_FAILURE", "INV_OBJREF", "NO_PERMISSION", 47 "INTERNAL", "MARSHAL", "INITIALIZE", "NO_IMPLEMENT", "BAD_TYPECODE", "BAD_OPERATION", "NO_RESOURCES", 48 "NO_RESPONSE", "PERSIST_STORE", "BAD_INV_ORDER", "TRANSIENT", "FREE_MEM", "INV_IDENT", "INV_FLAG", 49 "INTF_REPOS", "BAD_CONTEXT", "OBJ_ADAPTER", "DATA_CONVERSION", "OBJECT_NOT_EXIST", "TRANSACTION_REQUIRED", 50 "TRANSACTION_ROLLEDBACK", "INVALID_TRANSACTION", "INV_POLICY", "CODESET_INCOMPATIBLE", "REBIND", 51 "TIMEOUT", "TRANSACTION_UNAVAILABLE", "BAD_QOS", "INVALID_ACTIVITY", "ACTIVITY_COMPLETED", 52 "ACTIVITY_REQUIRED" }); 53 54 /** 55 * Read the minor codes from the input file and 56 * write out a resource file. 57 * 58 * @param inFile the file to read the codes from. 59 * @param outDir the directory to write the resource file to. 60 * @throws FileNotFoundException if the input file can not be found. 61 * @throws IOException if an I/O error occurs. 62 */ 63 private void makeResource(String inFile, String outDir) 64 throws FileNotFoundException, IOException { 65 writeResource(outDir, new Input(inFile)); 66 } 67 68 /** 69 * Create a new Java source file using the specified Scheme input file, 70 * and writing the result to the given output directory. 71 * 72 * @param inFile the file to read the data from. 73 * @param outDir the directory to write the Java class to. 74 * @throws FileNotFoundException if the input file can not be found. 75 * @throws IOException if an I/O error occurs. 76 */ 77 private void makeClass(String inFile, String outDir) 78 throws FileNotFoundException, IOException { 79 writeClass(inFile, outDir, new Input(inFile)); 80 } 81 82 /** 83 * Writes out a Java source file using the data from the given 84 * {@link Input} object. The result is written to {@code outDir}. 85 * The name of the input file is just used in the header of the 86 * resulting source file. 87 * 88 * @param inFile the name of the file the data was read from. 89 * @param outDir the directory to write the Java class to. 90 * @param input the parsed input data. 91 * @throws FileNotFoundException if the output file can't be written. 92 */ 93 private void writeClass(String inFile, String outDir, Input input) 94 throws FileNotFoundException { 95 String packageName = input.getPackageName(); 96 String className = input.getClassName(); 97 String groupName = input.getGroupName(); 98 Queue<InputException> exceptions = input.getExceptions(); 99 FileOutputStream file = new FileOutputStream(outDir + File.separator + className + ".java"); 100 IndentingPrintWriter pw = new IndentingPrintWriter(file); 101 102 writeClassHeader(inFile, groupName, pw); 103 pw.printMsg("package @ ;", packageName); 104 pw.println(); 105 pw.println("import java.util.logging.Logger ;"); 106 pw.println("import java.util.logging.Level ;"); 107 pw.println(); 108 pw.println("import org.omg.CORBA.OMGVMCID ;"); 109 pw.println( "import com.sun.corba.se.impl.util.SUNVMCID ;"); 110 pw.println( "import org.omg.CORBA.CompletionStatus ;"); 111 pw.println( "import org.omg.CORBA.SystemException ;"); 112 pw.println(); 113 pw.println( "import com.sun.corba.se.spi.orb.ORB ;"); 114 pw.println(); 115 pw.println( "import com.sun.corba.se.spi.logging.LogWrapperFactory;"); 116 pw.println(); 117 pw.println( "import com.sun.corba.se.spi.logging.LogWrapperBase;"); 118 pw.println(); 119 writeImports(exceptions, pw); 120 pw.println(); 121 pw.indent(); 122 pw.printMsg("public class @ extends LogWrapperBase {", className); 123 pw.println(); 124 pw.printMsg("public @( Logger logger )", className); 125 pw.indent(); 126 pw.println( "{"); 127 pw.undent(); 128 pw.println( "super( logger ) ;"); 129 pw.println( "}"); 130 pw.println(); 131 pw.flush(); 132 writeFactoryMethod(className, groupName, pw); 133 writeExceptions(groupName, exceptions, className, pw); 134 pw.undent(); 135 pw.println( ); 136 pw.println( "}"); 137 pw.flush(); 138 pw.close(); 139 } 140 141 /** 142 * Writes out the header of a Java source file. 143 * 144 * @param inFile the input file the file was generated from. 145 * @param groupName the group of exceptions the Java source file is for. 146 * @param pw the print writer used to write the output. 147 */ 148 private void writeClassHeader(String inFile, String groupName, 149 IndentingPrintWriter pw) { 150 if (groupName.equals("OMG")) 151 pw.println("// Log wrapper class for standard exceptions"); 152 else 153 pw.printMsg("// Log wrapper class for Sun private system exceptions in group @", 154 groupName); 155 pw.println("//"); 156 pw.printMsg("// Generated by MC.java version @, DO NOT EDIT BY HAND!", VERSION); 157 pw.printMsg("// Generated from input file @ on @", inFile, new Date()); 158 pw.println(); 159 } 160 161 /** 162 * Write out the import list for the exceptions. 163 * 164 * @param groups the exceptions that were parsed. 165 * @param pw the {@link IndentingPrintWriter} for writing to the file. 166 */ 167 private void writeImports(Queue<InputException> exceptions, 168 IndentingPrintWriter pw) { 169 if (exceptions == null) 170 return; 171 for (InputException e : exceptions) 172 pw.println("import org.omg.CORBA." + e.getName() + " ;"); 173 } 174 175 /** 176 * Write out the factory method for this group of exceptions. 177 * 178 * @param className the name of the generated class. 179 * @param groupName the name of this group of exceptions. 180 * @param pw the {@link IndentingPrintWriter} for writing to the file. 181 */ 182 private void writeFactoryMethod(String className, String groupName, 183 IndentingPrintWriter pw) { 184 pw.indent(); 185 pw.println( "private static LogWrapperFactory factory = new LogWrapperFactory() {"); 186 pw.println( "public LogWrapperBase create( Logger logger )" ); 187 pw.indent(); 188 pw.println( "{"); 189 pw.undent(); 190 pw.printMsg("return new @( logger ) ;", className); 191 pw.undent(); 192 pw.println( "}" ); 193 pw.println( "} ;" ); 194 pw.println(); 195 pw.printMsg("public static @ get( ORB orb, String logDomain )", className); 196 pw.indent(); 197 pw.println( "{"); 198 pw.indent(); 199 pw.printMsg( "@ wrapper = ", className); 200 pw.indent(); 201 pw.printMsg( "(@) orb.getLogWrapper( logDomain, ", className); 202 pw.undent(); 203 pw.undent(); 204 pw.printMsg( "\"@\", factory ) ;", groupName); 205 pw.undent(); 206 pw.println( "return wrapper ;" ); 207 pw.println( "} " ); 208 pw.println(); 209 pw.printMsg( "public static @ get( String logDomain )", className); 210 pw.indent(); 211 pw.println( "{"); 212 pw.indent(); 213 pw.printMsg( "@ wrapper = ", className); 214 pw.indent(); 215 pw.printMsg( "(@) ORB.staticGetLogWrapper( logDomain, ", className); 216 pw.undent(); 217 pw.undent(); 218 pw.printMsg( "\"@\", factory ) ;", groupName); 219 pw.undent(); 220 pw.println( "return wrapper ;" ); 221 pw.println( "} " ); 222 pw.println(); 223 } 224 225 /** 226 * Writes out the exceptions themselves. 227 * 228 * @param groupName the name of this group of exceptions. 229 * @param exceptions the exceptions to write out. 230 * @param className the name of the generated class. 231 * @param pw the {@link IndentingPrintWriter} for writing to the file. 232 */ 233 private void writeExceptions(String groupName, Queue<InputException> exceptions, 234 String className, IndentingPrintWriter pw) { 235 for (InputException e : exceptions) { 236 pw.println("///////////////////////////////////////////////////////////"); 237 pw.printMsg("// @", e.getName()); 238 pw.println("///////////////////////////////////////////////////////////"); 239 pw.println(); 240 for (InputCode c : e.getCodes()) 241 writeMethods(groupName, e.getName(), c.getName(), c.getCode(), 242 c.getLogLevel(), className, StringUtil.countArgs(c.getMessage()), pw); 243 pw.flush(); 244 } 245 } 246 247 /** 248 * Writes out the methods for a particular error. 249 * 250 * @param groupName the name of this group of exceptions. 251 * @param exceptionName the name of this particular exception. 252 * @param errorName the name of this particular error. 253 * @param code the minor code for this particular error. 254 * @param ident the name of the error in mixed-case identifier form. 255 * @param level the level at which to place log messages. 256 * @param className the name of the class for this group of exceptions. 257 * @param numParams the number of parameters the detail message takes. 258 * @param pw the print writer for writing to the file. 259 */ 260 private void writeMethods(String groupName, String exceptionName, String errorName, 261 int code, String level, String className, int numParams, 262 IndentingPrintWriter pw) { 263 String ident = StringUtil.toMixedCase(errorName); 264 pw.printMsg("public static final int @ = @ ;", errorName, getBase(groupName, code)); 265 pw.println(); 266 pw.flush(); 267 writeMethodStatusCause(groupName, exceptionName, errorName, ident, level, 268 numParams, className, pw); 269 pw.println(); 270 pw.flush(); 271 writeMethodStatus(exceptionName, ident, numParams, pw); 272 pw.println(); 273 pw.flush(); 274 writeMethodCause(exceptionName, ident, numParams, pw); 275 pw.println(); 276 pw.flush(); 277 writeMethodNoArgs(exceptionName, ident, numParams, pw); 278 pw.println(); 279 pw.flush(); 280 } 281 282 /** 283 * Writes out a method for an error that takes a 284 * {@link org.omg.CORBA.CompletionStatus} and a cause. 285 * 286 * @param groupName the name of this group of exceptions. 287 * @param exceptionName the name of this particular exception. 288 * @param errorName the name of this particular error. 289 * @param ident the name of the error in mixed-case identifier form. 290 * @param logLevel the level at which to place log messages. 291 * @param numParams the number of parameters the detail message takes. 292 * @param className the name of the class for this group of exceptions. 293 * @param pw the print writer for writing to the file. 294 */ 295 private void writeMethodStatusCause(String groupName, String exceptionName, 296 String errorName, String ident, 297 String logLevel, int numParams, 298 String className, IndentingPrintWriter pw) { 299 pw.indent(); 300 pw.printMsg( "public @ @( CompletionStatus cs, Throwable t@) {", exceptionName, 301 ident, makeDeclArgs(true, numParams)); 302 pw.printMsg( "@ exc = new @( @, cs ) ;", exceptionName, exceptionName, errorName); 303 pw.indent(); 304 pw.println( "if (t != null)" ); 305 pw.undent(); 306 pw.println( "exc.initCause( t ) ;" ); 307 pw.println(); 308 pw.indent(); 309 pw.printMsg( "if (logger.isLoggable( Level.@ )) {", logLevel); 310 if (numParams > 0) { 311 pw.printMsg( "Object[] parameters = new Object[@] ;", numParams); 312 for (int a = 0; a < numParams; ++a) 313 pw.printMsg("parameters[@] = arg@ ;", a, a); 314 } else 315 pw.println( "Object[] parameters = null ;"); 316 pw.indent(); 317 pw.printMsg( "doLog( Level.@, \"@.@\",", logLevel, groupName, ident); 318 pw.undent(); 319 pw.undent(); 320 pw.printMsg( "parameters, @.class, exc ) ;", className); 321 pw.println( "}"); 322 pw.println(); 323 324 pw.undent(); 325 pw.println( "return exc ;"); 326 pw.println( "}"); 327 } 328 329 /** 330 * Writes out a method for an error that takes a 331 * {@link org.omg.CORBA.CompletionStatus}. 332 * 333 * @param exceptionName the name of this particular exception. 334 * @param ident the name of the error in mixed-case identifier form. 335 * @param numParams the number of parameters the detail message takes. 336 * @param pw the print writer for writing to the file. 337 */ 338 private void writeMethodStatus(String exceptionName, String ident, 339 int numParams, IndentingPrintWriter pw) { 340 pw.indent(); 341 pw.printMsg("public @ @( CompletionStatus cs@) {", exceptionName, 342 ident, makeDeclArgs(true, numParams)); 343 pw.undent(); 344 pw.printMsg("return @( cs, null@ ) ;", ident, makeCallArgs(true, numParams)); 345 pw.println("}"); 346 } 347 348 /** 349 * Writes out a method for an error that takes a cause. 350 * 351 * @param exceptionName the name of this particular exception. 352 * @param ident the name of the error in mixed-case identifier form. 353 * @param numParams the number of parameters the detail message takes. 354 * @param pw the print writer for writing to the file. 355 */ 356 private void writeMethodCause(String exceptionName, String ident, 357 int numParams, IndentingPrintWriter pw) { 358 pw.indent(); 359 pw.printMsg("public @ @( Throwable t@) {", exceptionName, ident, 360 makeDeclArgs(true, numParams)); 361 pw.undent(); 362 pw.printMsg("return @( CompletionStatus.COMPLETED_NO, t@ ) ;", ident, 363 makeCallArgs(true, numParams)); 364 pw.println("}"); 365 } 366 367 /** 368 * Writes out a method for an error that takes no arguments. 369 * 370 * @param exceptionName the name of this particular exception. 371 * @param ident the name of the error in mixed-case identifier form. 372 * @param numParams the number of parameters the detail message takes. 373 * @param pw the print writer for writing to the file. 374 */ 375 private void writeMethodNoArgs(String exceptionName, String ident, 376 int numParams, IndentingPrintWriter pw) { 377 378 pw.indent(); 379 pw.printMsg("public @ @( @) {", exceptionName, ident, 380 makeDeclArgs(false, numParams)); 381 pw.undent(); 382 pw.printMsg("return @( CompletionStatus.COMPLETED_NO, null@ ) ;", 383 ident, makeCallArgs(true, numParams)); 384 pw.println("}"); 385 } 386 387 /** 388 * Returns a list of comma-separated arguments with type declarations. 389 * 390 * @param leadingComma true if the list should start with a comma. 391 * @param numArgs the number of arguments to generate. 392 * @return the generated string. 393 */ 394 private String makeDeclArgs(boolean leadingComma, int numArgs) { 395 return makeArgString("Object arg", leadingComma, numArgs); 396 } 397 398 /** 399 * Returns a list of comma-separated arguments without type declarations. 400 * 401 * @param leadingComma true if the list should start with a comma. 402 * @param numArgs the number of arguments to generate. 403 * @return the generated string. 404 */ 405 private String makeCallArgs(boolean leadingComma, int numArgs) { 406 return makeArgString("arg", leadingComma, numArgs); 407 } 408 409 /** 410 * Returns a list of comma-separated arguments. 411 * 412 * @param prefixString the string with which to prefix each argument. 413 * @param leadingComma true if the list should start with a comma. 414 * @param numArgs the number of arguments to generate. 415 * @return the generated string. 416 */ 417 private String makeArgString(String prefixString, boolean leadingComma, 418 int numArgs) { 419 if (numArgs == 0) 420 return " "; 421 if (numArgs == 1) { 422 if (leadingComma) 423 return ", " + prefixString + (numArgs - 1); 424 else 425 return " " + prefixString + (numArgs - 1); 426 } 427 return makeArgString(prefixString, leadingComma, numArgs - 1) + 428 ", " + prefixString + (numArgs - 1); 429 } 430 431 /** 432 * Returns the {@link String} containing the calculation of the 433 * error code. 434 * 435 * @param groupName the group of exception to which the code belongs. 436 * @param code the minor code number representing the exception within the group. 437 * @return the unique error code. 438 */ 439 private String getBase(String groupName, int code) { 440 if (groupName.equals("OMG")) 441 return "OMGVMCID.value + " + code; 442 else 443 return "SUNVMCID.value + " + (code + getSunBaseNumber(groupName)); 444 } 445 446 /** 447 * Returns the base number for Sun-specific exceptions. 448 * 449 * @return the base number. 450 */ 451 private int getSunBaseNumber(String groupName) { 452 return 200 * SUN_EXCEPTION_GROUPS.indexOf(groupName); 453 } 454 455 /** 456 * Writes out a resource file using the data from the given 457 * {@link Input} object. The result is written to {@code outDir}. 458 * 459 * @param outDir the directory to write the Java class to. 460 * @param input the parsed input data. 461 * @throws FileNotFoundException if the output file can't be written. 462 */ 463 private void writeResource(String outDir, Input input) 464 throws FileNotFoundException { 465 FileOutputStream file = new FileOutputStream(outDir + File.separator + 466 input.getClassName() + ".resource"); 467 IndentingPrintWriter pw = new IndentingPrintWriter(file); 468 String groupName = input.getGroupName(); 469 for (InputException e : input.getExceptions()) { 470 String exName = e.getName(); 471 for (InputCode c : e.getCodes()) { 472 String ident = StringUtil.toMixedCase(c.getName()); 473 pw.printMsg("@.@=\"@: (@) @\"", groupName, ident, 474 getMessageID(groupName, exName, c.getCode()), exName, c.getMessage()); 475 } 476 pw.flush(); 477 } 478 pw.close(); 479 } 480 481 /** 482 * Returns the message ID corresponding to the given group name, 483 * exception name and error code. 484 * 485 * @param groupName the name of the group of exceptions. 486 * @param exception the name of the particular exception. 487 * @param code an error code from the given exception. 488 * @return the message ID. 489 */ 490 private String getMessageID(String groupName, String exceptionName, int code) { 491 if (groupName.equals("OMG")) 492 return getStandardMessageID(exceptionName, code); 493 else 494 return getSunMessageID(groupName, exceptionName, code); 495 } 496 497 /** 498 * Returns the standard (OMG) message ID corresponding to the given 499 * exception name and error code. 500 * 501 * @param exceptionName the name of the particular exception. 502 * @param code an error code from the given exception. 503 * @return the message ID. 504 */ 505 private String getStandardMessageID(String exceptionName, int code) { 506 return new Formatter().format("IOP%s0%04d", getExceptionID(exceptionName), 507 code).toString(); 508 } 509 510 /** 511 * Returns the Sun message ID corresponding to the given group name, 512 * exception name and error code. 513 * 514 * @param groupName the name of the group of exceptions. 515 * @param exceptionName the name of the particular exception. 516 * @param code an error code from the given exception. 517 * @return the message ID. 518 */ 519 private String getSunMessageID(String groupName, String exceptionName, int code) { 520 return new Formatter().format("IOP%s1%04d", getExceptionID(exceptionName), 521 getSunBaseNumber(groupName) + code).toString(); 522 } 523 524 /** 525 * Returns the exception ID corresponding to the given exception name. 526 * 527 * @param exceptionName the name of the particular exception. 528 * @return the message ID. 529 */ 530 private String getExceptionID(String exceptionName) { 531 return new Formatter().format("%03d", EXCEPTIONS.indexOf(exceptionName)).toString(); 532 } 533 534 /** 535 * Entry point for running the generator from the command 536 * line. Users can specify either "make-class" or "make-resource" 537 * as the first argument to generate the specified type of file. 538 * 539 * @param args the command-line arguments. 540 * @throws FileNotFoundException if the input file can not be found. 541 * @throws IOException if an I/O error occurs. 542 */ 543 public static void main(String[] args) 544 throws FileNotFoundException, IOException 545 { 546 if (args.length < 3) 547 { 548 System.err.println("(make-class|make-resource) <input file> <output dir>"); 549 System.exit(-1); 550 } 551 if (args[0].equals("make-class")) 552 new MC().makeClass(args[1], args[2]); 553 else if (args[0].equals("make-resource")) 554 new MC().makeResource(args[1], args[2]); 555 else 556 System.err.println("Invalid command: " + args[0]); 557 } 558 559} 560