alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Generator.java)

This example Java source code file (Generator.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

batchenvironment, classdefinition, classfile, classpath, compoundtype, contextstack, file, generator, hashset, identifier, indentingwriter, ioexception, outputtype, string, util

The Generator.java Java example source code

/*
 * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * Licensed Materials - Property of IBM
 * RMI-IIOP v1.0
 * Copyright IBM Corp. 1998 1999  All Rights Reserved
 *
 */


package sun.rmi.rmic.iiop;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
import sun.tools.java.Identifier;
import sun.tools.java.ClassPath;
import sun.tools.java.ClassFile;
import sun.tools.java.ClassNotFound;
import sun.tools.java.ClassDefinition;
import sun.tools.java.ClassDeclaration;
import sun.rmi.rmic.IndentingWriter;
import sun.rmi.rmic.Main;
import sun.rmi.rmic.iiop.Util;
import java.util.HashSet;

/**
 * Generator provides a small framework from which IIOP-specific
 * generators can inherit.  Common logic is implemented here which uses
 * both abstract methods as well as concrete methods which subclasses may
 * want to override. The following methods must be present in any subclass:
 * <pre>
 *      Default constructor
 *              CompoundType getTopType(BatchEnvironment env, ClassDefinition cdef);
 *      int parseArgs(String argv[], int currentIndex);
 *      boolean requireNewInstance();
 *              OutputType[] getOutputTypesFor(CompoundType topType,
 *                                     HashSet alreadyChecked);
 *              String getFileNameExtensionFor(OutputType outputType);
 *              void writeOutputFor (   OutputType outputType,
 *                              HashSet alreadyChecked,
 *                                                              IndentingWriter writer) throws IOException;
 * </pre>
 * @author      Bryan Atsatt
 */
public abstract class Generator implements      sun.rmi.rmic.Generator,
                                                sun.rmi.rmic.iiop.Constants {

    protected boolean alwaysGenerate = false;
    protected BatchEnvironment env = null;
    protected ContextStack contextStack = null;
    private boolean trace = false;
    protected boolean idl = false;

    /**
     * Examine and consume command line arguments.
     * @param argv The command line arguments. Ignore null
     * and unknown arguments. Set each consumed argument to null.
     * @param error Report any errors using the main.error() methods.
     * @return true if no errors, false otherwise.
     */
    public boolean parseArgs(String argv[], Main main) {
        for (int i = 0; i < argv.length; i++) {
            if (argv[i] != null) {
                if (argv[i].equalsIgnoreCase("-always") ||
                    argv[i].equalsIgnoreCase("-alwaysGenerate")) {
                    alwaysGenerate = true;
                    argv[i] = null;
                } else if (argv[i].equalsIgnoreCase("-xtrace")) {
                    trace = true;
                    argv[i] = null;
                }
            }
        }
        return true;
    }

    /**
     * Return true if non-conforming types should be parsed.
     * @param stack The context stack.
     */
    protected abstract boolean parseNonConforming(ContextStack stack);

    /**
     * Create and return a top-level type.
     * @param cdef The top-level class definition.
     * @param stack The context stack.
     * @return The compound type or null if is non-conforming.
     */
    protected abstract CompoundType getTopType(ClassDefinition cdef, ContextStack stack);

    /**
     * Return an array containing all the file names and types that need to be
     * generated for the given top-level type.  The file names must NOT have an
     * extension (e.g. ".java").
     * @param topType The type returned by getTopType().
     * @param alreadyChecked A set of Types which have already been checked.
     *  Intended to be passed to Type.collectMatching(filter,alreadyChecked).
     */
    protected abstract OutputType[] getOutputTypesFor(CompoundType topType,
                                                      HashSet alreadyChecked);

    /**
     * Return the file name extension for the given file name (e.g. ".java").
     * All files generated with the ".java" extension will be compiled. To
     * change this behavior for ".java" files, override the compileJavaSourceFile
     * method to return false.
     * @param outputType One of the items returned by getOutputTypesFor(...)
     */
    protected abstract String getFileNameExtensionFor(OutputType outputType);

    /**
     * Write the output for the given OutputFileName into the output stream.
     * @param name One of the items returned by getOutputTypesFor(...)
     * @param alreadyChecked A set of Types which have already been checked.
     *  Intended to be passed to Type.collectMatching(filter,alreadyChecked).
     * @param writer The output stream.
     */
    protected abstract void writeOutputFor(OutputType outputType,
                                                HashSet alreadyChecked,
                                                IndentingWriter writer) throws IOException;

    /**
     * Return true if a new instance should be created for each
     * class on the command line. Subclasses which return true
     * should override newInstance() to return an appropriately
     * constructed instance.
     */
    protected abstract boolean requireNewInstance();

    /**
     * Return true if the specified file needs generation.
     */
    public boolean requiresGeneration (File target, Type theType) {

        boolean result = alwaysGenerate;

        if (!result) {

            // Get a ClassFile instance for base source or class
            // file.  We use ClassFile so that if the base is in
            // a zip file, we can still get at it's mod time...

            ClassFile baseFile;
            ClassPath path = env.getClassPath();
            String className = theType.getQualifiedName().replace('.',File.separatorChar);

            // First try the source file...

            baseFile = path.getFile(className + ".source");

            if (baseFile == null) {

                // Then try class file...

                baseFile = path.getFile(className + ".class");
            }

            // Do we have a baseFile?

            if (baseFile != null) {

                // Yes, grab baseFile's mod time...

                long baseFileMod = baseFile.lastModified();

                // Get a File instance for the target. If it is a source
                // file, create a class file instead since the source file
                // will frequently be deleted...

                String targetName = IDLNames.replace(target.getName(),".java",".class");
                String parentPath = target.getParent();
                File targetFile = new File(parentPath,targetName);

                // Does the target file exist?

                if (targetFile.exists()) {

                    // Yes, so grab it's mod time...

                    long targetFileMod = targetFile.lastModified();

                    // Set result...

                    result = targetFileMod < baseFileMod;

                } else {

                    // No, so we must generate...

                    result = true;
                }
            } else {

                // No, so we must generate...

                result = true;
            }
        }

        return result;
    }

    /**
     * Create and return a new instance of self. Subclasses
     * which need to do something other than default construction
     * must override this method.
     */
    protected Generator newInstance() {
        Generator result = null;
        try {
            result = (Generator) getClass().newInstance();
        }
        catch (Exception e){} // Should ALWAYS work!

        return result;
    }

    /**
     * Default constructor for subclasses to use.
     */
    protected Generator() {
    }

    /**
     * Generate output. Any source files created which need compilation should
     * be added to the compiler environment using the addGeneratedFile(File)
     * method.
     *
     * @param env       The compiler environment
     * @param cdef      The definition for the implementation class or interface from
     *              which to generate output
     * @param destDir   The directory for the root of the package hierarchy
     *                          for generated files. May be null.
     */
    public void generate(sun.rmi.rmic.BatchEnvironment env, ClassDefinition cdef, File destDir) {

        this.env = (BatchEnvironment) env;
        contextStack = new ContextStack(this.env);
        contextStack.setTrace(trace);

        // Make sure the environment knows whether or not to parse
        // non-conforming types. This will clear out any previously
        // parsed types if necessary...

        this.env.setParseNonConforming(parseNonConforming(contextStack));

        // Get our top level type...

        CompoundType topType = getTopType(cdef,contextStack);
        if (topType != null) {

            Generator generator = this;

            // Do we need to make a new instance?

            if (requireNewInstance()) {

                                // Yes, so make one.  'this' instance is the one instantiated by Main
                                // and which knows any needed command line args...

                generator = newInstance();
            }

            // Now generate all output files...

            generator.generateOutputFiles(topType, this.env, destDir);
        }
    }

    /**
     * Create and return a new instance of self. Subclasses
     * which need to do something other than default construction
     * must override this method.
     */
    protected void generateOutputFiles (CompoundType topType,
                                        BatchEnvironment env,
                                        File destDir) {

        // Grab the 'alreadyChecked' HashSet from the environment...

        HashSet alreadyChecked = env.alreadyChecked;

        // Ask subclass for a list of output types...

        OutputType[] types = getOutputTypesFor(topType,alreadyChecked);

        // Process each file...

        for (int i = 0; i < types.length; i++) {
            OutputType current = types[i];
            String className = current.getName();
            File file = getFileFor(current,destDir);
            boolean sourceFile = false;

            // Do we need to generate this file?

            if (requiresGeneration(file,current.getType())) {

                // Yes. If java source file, add to environment so will be compiled...

                if (file.getName().endsWith(".java")) {
                    sourceFile = compileJavaSourceFile(current);

                                // Are we supposeded to compile this one?

                    if (sourceFile) {
                        env.addGeneratedFile(file);
                    }
                }

                // Now create an output stream and ask subclass to fill it up...

                try {
                   IndentingWriter out = new IndentingWriter(
                                                              new OutputStreamWriter(new FileOutputStream(file)),INDENT_STEP,TAB_SIZE);

                    long startTime = 0;
                    if (env.verbose()) {
                        startTime = System.currentTimeMillis();
                    }

                    writeOutputFor(types[i],alreadyChecked,out);
                    out.close();

                    if (env.verbose()) {
                        long duration = System.currentTimeMillis() - startTime;
                        env.output(Main.getText("rmic.generated", file.getPath(), Long.toString(duration)));
                    }
                    if (sourceFile) {
                        env.parseFile(new ClassFile(file));
                    }
                } catch (IOException e) {
                    env.error(0, "cant.write", file.toString());
                    return;
                }
            } else {

                // No, say so if we need to...

                if (env.verbose()) {
                    env.output(Main.getText("rmic.previously.generated", file.getPath()));
                }
            }
        }
    }

    /**
     * Return the File object that should be used as the output file
     * for the given OutputType.
     * @param outputType The type to create a file for.
     * @param destinationDir The directory to use as the root of the
     * package heirarchy.  May be null, in which case the current
     * classpath is searched to find the directory in which to create
     * the output file.  If that search fails (most likely because the
     * package directory lives in a zip or jar file rather than the
     * file system), the current user directory is used.
     */
    protected File getFileFor(OutputType outputType, File destinationDir) {
        // Calling this method does some crucial initialization
        // in a subclass implementation. Don't skip it.
        Identifier id = getOutputId(outputType);
        File packageDir = null;
        if(idl){
            packageDir = Util.getOutputDirectoryForIDL(id,destinationDir,env);
        } else {
            packageDir = Util.getOutputDirectoryForStub(id,destinationDir,env);
        }
        String classFileName = outputType.getName() + getFileNameExtensionFor(outputType);
        return new File(packageDir, classFileName);
    }

    /**
     * Return an identifier to use for output.
     * @param outputType the type for which output is to be generated.
     * @return the new identifier. This implementation returns the input parameter.
     */
    protected Identifier getOutputId (OutputType outputType) {
        return outputType.getType().getIdentifier();
    }

    /**
     * Return true if the given file should be compiled.
     * @param outputType One of the items returned by getOutputTypesFor(...) for
     *   which getFileNameExtensionFor(OutputType) returned ".java".
     */
    protected boolean compileJavaSourceFile (OutputType outputType) {
        return true;
    }

    //_____________________________________________________________________
    // OutputType is a simple wrapper for a name and a Type
    //_____________________________________________________________________

    public class OutputType {
        private String name;
        private Type type;

        public OutputType (String name, Type type) {
            this.name = name;
            this.type = type;
        }

        public String getName() {
            return name;
        }

        public Type getType() {
            return type;
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Generator.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.