src/share/classes/sun/rmi/rmic/iiop/Generator.java

Wed, 28 Mar 2012 02:50:50 -0700

author
mbankal
date
Wed, 28 Mar 2012 02:50:50 -0700
changeset 371
e324dfb90c9e
parent 158
91006f157c46
child 748
6845b95cba6b
permissions
-rw-r--r--

7079902: Refine CORBA data models
Reviewed-by: coffeys

     1 /*
     2  * Copyright (c) 1998, 2007, 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  */
    26 /*
    27  * Licensed Materials - Property of IBM
    28  * RMI-IIOP v1.0
    29  * Copyright IBM Corp. 1998 1999  All Rights Reserved
    30  *
    31  */
    34 package sun.rmi.rmic.iiop;
    36 import java.io.File;
    37 import java.io.FileOutputStream;
    38 import java.io.OutputStreamWriter;
    39 import java.io.IOException;
    40 import sun.tools.java.Identifier;
    41 import sun.tools.java.ClassPath;
    42 import sun.tools.java.ClassFile;
    43 import sun.tools.java.ClassNotFound;
    44 import sun.tools.java.ClassDefinition;
    45 import sun.tools.java.ClassDeclaration;
    46 import sun.rmi.rmic.IndentingWriter;
    47 import sun.rmi.rmic.Main;
    48 import sun.rmi.rmic.iiop.Util;
    49 import java.util.HashSet;
    51 /**
    52  * Generator provides a small framework from which IIOP-specific
    53  * generators can inherit.  Common logic is implemented here which uses
    54  * both abstract methods as well as concrete methods which subclasses may
    55  * want to override. The following methods must be present in any subclass:
    56  * <pre>
    57  *      Default constructor
    58  *              CompoundType getTopType(BatchEnvironment env, ClassDefinition cdef);
    59  *      int parseArgs(String argv[], int currentIndex);
    60  *      boolean requireNewInstance();
    61  *              OutputType[] getOutputTypesFor(CompoundType topType,
    62  *                                     HashSet alreadyChecked);
    63  *              String getFileNameExtensionFor(OutputType outputType);
    64  *              void writeOutputFor (   OutputType outputType,
    65  *                              HashSet alreadyChecked,
    66  *                                                              IndentingWriter writer) throws IOException;
    67  * </pre>
    68  * @author      Bryan Atsatt
    69  */
    70 public abstract class Generator implements      sun.rmi.rmic.Generator,
    71                                                 sun.rmi.rmic.iiop.Constants {
    73     protected boolean alwaysGenerate = false;
    74     protected BatchEnvironment env = null;
    75     protected ContextStack contextStack = null;
    76     private boolean trace = false;
    77     protected boolean idl = false;
    79     /**
    80      * Examine and consume command line arguments.
    81      * @param argv The command line arguments. Ignore null
    82      * and unknown arguments. Set each consumed argument to null.
    83      * @param error Report any errors using the main.error() methods.
    84      * @return true if no errors, false otherwise.
    85      */
    86     public boolean parseArgs(String argv[], Main main) {
    87         for (int i = 0; i < argv.length; i++) {
    88             if (argv[i] != null) {
    89                 if (argv[i].equalsIgnoreCase("-always") ||
    90                     argv[i].equalsIgnoreCase("-alwaysGenerate")) {
    91                     alwaysGenerate = true;
    92                     argv[i] = null;
    93                 } else if (argv[i].equalsIgnoreCase("-xtrace")) {
    94                     trace = true;
    95                     argv[i] = null;
    96                 }
    97             }
    98         }
    99         return true;
   100     }
   102     /**
   103      * Return true if non-conforming types should be parsed.
   104      * @param stack The context stack.
   105      */
   106     protected abstract boolean parseNonConforming(ContextStack stack);
   108     /**
   109      * Create and return a top-level type.
   110      * @param cdef The top-level class definition.
   111      * @param stack The context stack.
   112      * @return The compound type or null if is non-conforming.
   113      */
   114     protected abstract CompoundType getTopType(ClassDefinition cdef, ContextStack stack);
   116     /**
   117      * Return an array containing all the file names and types that need to be
   118      * generated for the given top-level type.  The file names must NOT have an
   119      * extension (e.g. ".java").
   120      * @param topType The type returned by getTopType().
   121      * @param alreadyChecked A set of Types which have already been checked.
   122      *  Intended to be passed to Type.collectMatching(filter,alreadyChecked).
   123      */
   124     protected abstract OutputType[] getOutputTypesFor(CompoundType topType,
   125                                                       HashSet alreadyChecked);
   127     /**
   128      * Return the file name extension for the given file name (e.g. ".java").
   129      * All files generated with the ".java" extension will be compiled. To
   130      * change this behavior for ".java" files, override the compileJavaSourceFile
   131      * method to return false.
   132      * @param outputType One of the items returned by getOutputTypesFor(...)
   133      */
   134     protected abstract String getFileNameExtensionFor(OutputType outputType);
   136     /**
   137      * Write the output for the given OutputFileName into the output stream.
   138      * @param name One of the items returned by getOutputTypesFor(...)
   139      * @param alreadyChecked A set of Types which have already been checked.
   140      *  Intended to be passed to Type.collectMatching(filter,alreadyChecked).
   141      * @param writer The output stream.
   142      */
   143     protected abstract void writeOutputFor(OutputType outputType,
   144                                                 HashSet alreadyChecked,
   145                                                 IndentingWriter writer) throws IOException;
   147     /**
   148      * Return true if a new instance should be created for each
   149      * class on the command line. Subclasses which return true
   150      * should override newInstance() to return an appropriately
   151      * constructed instance.
   152      */
   153     protected abstract boolean requireNewInstance();
   155     /**
   156      * Return true if the specified file needs generation.
   157      */
   158     public boolean requiresGeneration (File target, Type theType) {
   160         boolean result = alwaysGenerate;
   162         if (!result) {
   164             // Get a ClassFile instance for base source or class
   165             // file.  We use ClassFile so that if the base is in
   166             // a zip file, we can still get at it's mod time...
   168             ClassFile baseFile;
   169             ClassPath path = env.getClassPath();
   170             String className = theType.getQualifiedName().replace('.',File.separatorChar);
   172             // First try the source file...
   174             baseFile = path.getFile(className + ".source");
   176             if (baseFile == null) {
   178                 // Then try class file...
   180                 baseFile = path.getFile(className + ".class");
   181             }
   183             // Do we have a baseFile?
   185             if (baseFile != null) {
   187                 // Yes, grab baseFile's mod time...
   189                 long baseFileMod = baseFile.lastModified();
   191                 // Get a File instance for the target. If it is a source
   192                 // file, create a class file instead since the source file
   193                 // will frequently be deleted...
   195                 String targetName = IDLNames.replace(target.getName(),".java",".class");
   196                 String parentPath = target.getParent();
   197                 File targetFile = new File(parentPath,targetName);
   199                 // Does the target file exist?
   201                 if (targetFile.exists()) {
   203                     // Yes, so grab it's mod time...
   205                     long targetFileMod = targetFile.lastModified();
   207                     // Set result...
   209                     result = targetFileMod < baseFileMod;
   211                 } else {
   213                     // No, so we must generate...
   215                     result = true;
   216                 }
   217             } else {
   219                 // No, so we must generate...
   221                 result = true;
   222             }
   223         }
   225         return result;
   226     }
   228     /**
   229      * Create and return a new instance of self. Subclasses
   230      * which need to do something other than default construction
   231      * must override this method.
   232      */
   233     protected Generator newInstance() {
   234         Generator result = null;
   235         try {
   236             result = (Generator) getClass().newInstance();
   237         }
   238         catch (Exception e){} // Should ALWAYS work!
   240         return result;
   241     }
   243     /**
   244      * Default constructor for subclasses to use.
   245      */
   246     protected Generator() {
   247     }
   249     /**
   250      * Generate output. Any source files created which need compilation should
   251      * be added to the compiler environment using the addGeneratedFile(File)
   252      * method.
   253      *
   254      * @param env       The compiler environment
   255      * @param cdef      The definition for the implementation class or interface from
   256      *              which to generate output
   257      * @param destDir   The directory for the root of the package hierarchy
   258      *                          for generated files. May be null.
   259      */
   260     public void generate(sun.rmi.rmic.BatchEnvironment env, ClassDefinition cdef, File destDir) {
   262         this.env = (BatchEnvironment) env;
   263         contextStack = new ContextStack(this.env);
   264         contextStack.setTrace(trace);
   266         // Make sure the environment knows whether or not to parse
   267         // non-conforming types. This will clear out any previously
   268         // parsed types if necessary...
   270         this.env.setParseNonConforming(parseNonConforming(contextStack));
   272         // Get our top level type...
   274         CompoundType topType = getTopType(cdef,contextStack);
   275         if (topType != null) {
   277             Generator generator = this;
   279             // Do we need to make a new instance?
   281             if (requireNewInstance()) {
   283                                 // Yes, so make one.  'this' instance is the one instantiated by Main
   284                                 // and which knows any needed command line args...
   286                 generator = newInstance();
   287             }
   289             // Now generate all output files...
   291             generator.generateOutputFiles(topType, this.env, destDir);
   292         }
   293     }
   295     /**
   296      * Create and return a new instance of self. Subclasses
   297      * which need to do something other than default construction
   298      * must override this method.
   299      */
   300     protected void generateOutputFiles (CompoundType topType,
   301                                         BatchEnvironment env,
   302                                         File destDir) {
   304         // Grab the 'alreadyChecked' HashSet from the environment...
   306         HashSet alreadyChecked = env.alreadyChecked;
   308         // Ask subclass for a list of output types...
   310         OutputType[] types = getOutputTypesFor(topType,alreadyChecked);
   312         // Process each file...
   314         for (int i = 0; i < types.length; i++) {
   315             OutputType current = types[i];
   316             String className = current.getName();
   317             File file = getFileFor(current,destDir);
   318             boolean sourceFile = false;
   320             // Do we need to generate this file?
   322             if (requiresGeneration(file,current.getType())) {
   324                 // Yes. If java source file, add to environment so will be compiled...
   326                 if (file.getName().endsWith(".java")) {
   327                     sourceFile = compileJavaSourceFile(current);
   329                                 // Are we supposeded to compile this one?
   331                     if (sourceFile) {
   332                         env.addGeneratedFile(file);
   333                     }
   334                 }
   336                 // Now create an output stream and ask subclass to fill it up...
   338                 try {
   339                    IndentingWriter out = new IndentingWriter(
   340                                                               new OutputStreamWriter(new FileOutputStream(file)),INDENT_STEP,TAB_SIZE);
   342                     long startTime = 0;
   343                     if (env.verbose()) {
   344                         startTime = System.currentTimeMillis();
   345                     }
   347                     writeOutputFor(types[i],alreadyChecked,out);
   348                     out.close();
   350                     if (env.verbose()) {
   351                         long duration = System.currentTimeMillis() - startTime;
   352                         env.output(Main.getText("rmic.generated", file.getPath(), Long.toString(duration)));
   353                     }
   354                     if (sourceFile) {
   355                         env.parseFile(new ClassFile(file));
   356                     }
   357                 } catch (IOException e) {
   358                     env.error(0, "cant.write", file.toString());
   359                     return;
   360                 }
   361             } else {
   363                 // No, say so if we need to...
   365                 if (env.verbose()) {
   366                     env.output(Main.getText("rmic.previously.generated", file.getPath()));
   367                 }
   368             }
   369         }
   370     }
   372     /**
   373      * Return the File object that should be used as the output file
   374      * for the given OutputType.
   375      * @param outputType The type to create a file for.
   376      * @param destinationDir The directory to use as the root of the
   377      * package heirarchy.  May be null, in which case the current
   378      * classpath is searched to find the directory in which to create
   379      * the output file.  If that search fails (most likely because the
   380      * package directory lives in a zip or jar file rather than the
   381      * file system), the current user directory is used.
   382      */
   383     protected File getFileFor(OutputType outputType, File destinationDir) {
   384         // Calling this method does some crucial initialization
   385         // in a subclass implementation. Don't skip it.
   386         Identifier id = getOutputId(outputType);
   387         File packageDir = null;
   388         if(idl){
   389             packageDir = Util.getOutputDirectoryForIDL(id,destinationDir,env);
   390         } else {
   391             packageDir = Util.getOutputDirectoryForStub(id,destinationDir,env);
   392         }
   393         String classFileName = outputType.getName() + getFileNameExtensionFor(outputType);
   394         return new File(packageDir, classFileName);
   395     }
   397     /**
   398      * Return an identifier to use for output.
   399      * @param outputType the type for which output is to be generated.
   400      * @return the new identifier. This implementation returns the input parameter.
   401      */
   402     protected Identifier getOutputId (OutputType outputType) {
   403         return outputType.getType().getIdentifier();
   404     }
   406     /**
   407      * Return true if the given file should be compiled.
   408      * @param outputType One of the items returned by getOutputTypesFor(...) for
   409      *   which getFileNameExtensionFor(OutputType) returned ".java".
   410      */
   411     protected boolean compileJavaSourceFile (OutputType outputType) {
   412         return true;
   413     }
   415     //_____________________________________________________________________
   416     // OutputType is a simple wrapper for a name and a Type
   417     //_____________________________________________________________________
   419     public class OutputType {
   420         private String name;
   421         private Type type;
   423         public OutputType (String name, Type type) {
   424             this.name = name;
   425             this.type = type;
   426         }
   428         public String getName() {
   429             return name;
   430         }
   432         public Type getType() {
   433             return type;
   434         }
   435     }
   436 }

mercurial