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