Package org.openquark.cal.services

Source Code of org.openquark.cal.services.StandaloneJarTool

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/*
* StandaloneJarTool.java
* Created: May 17, 2007
* By: Joseph Wong
*/

package org.openquark.cal.services;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.openquark.cal.compiler.MessageLogger;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.compiler.UnableToResolveForeignEntityException;
import org.openquark.cal.compiler.Version;
import org.openquark.cal.internal.machine.lecc.StandaloneJarBuilder;
import org.openquark.cal.internal.machine.lecc.StandaloneJarBuilder.JavaScope;
import org.openquark.cal.internal.machine.lecc.StandaloneJarBuilder.LibraryClassSpec;
import org.openquark.cal.internal.machine.lecc.StandaloneJarBuilder.MainClassSpec;
import org.openquark.cal.internal.runtime.lecc.LECCMachineConfiguration;
import org.openquark.util.SimpleConsoleHandler;

/**
* This class implements a command-line utility for constructing a <em>standalone JAR</em>, which may contain
* application and library classes.
* <p>
* A standalone JAR may package up a CAL application by gathering together all the generated runtime
* classes necessary for running a specific CAL function, and a class containing a
* <code>public static void main(String[] args)</code> method which runs the CAL function directly
* (without having to first initialize a CAL workspace). This makes it possible to package up a CAL
* function into a command-line application.
* <p>
* To run the CAL function using the standalone JAR, simply include the standalone JAR, the CAL
* platform jars, and any required external jars on the classpath, and specify the name of the
* generated class as the one to run. Command line arguments will be passed into the CAL function.
* <p>
* A standalone JAR may also package up one or more library classes - a library class is a non-instatiatable class
* containing static methods corresponding to the functions and data constructors defined in a particular
* CAL module. This makes it possible to expose CAL libraries in Java, by defining API modules in CAL (whose
* functions contain appropriate marshalling from/unmarshalling to foreign types), from which library classes are
* generated.
* <p>
* This utility only works with the LECC machine.
* <p>
* In this version, we support generating standalone applications for CAL functions with the type
* <code>[String] -> ()</code>. In this case, the command line arguments array will be marshalled
* into a CAL list of Strings.
*
* @author Joseph Wong
*/
public final class StandaloneJarTool {

    /** The launch command displayed in the usage help. */
    private static final String LAUNCH_COMMAND = "quarkc";
   
    /** The name of the non-interruptible property. */
    private static final String NON_INTERRUPTIBLE_PROPERTY = "org.openquark.cal.machine.lecc.non_interruptible";

    /**
     * Encapsulates the command line argument list.
     *
     * @author Joseph Wong
     */
    private static class ArgumentList {
       
        /**
         * Exception for representing that there are not enough arguments supplied.
         *
         * @author Joseph Wong
         */
        private static class NotEnoughArgumentsException extends Exception {
           
            private static final long serialVersionUID = -5402072553834237273L;

            /** Constructs an instance of this exception. */
            private NotEnoughArgumentsException() {}
        }
       
        /**
         * Exception for representing that there are too many arguments supplied.
         *
         * @author Joseph Wong
         */
        private static class TooManyArgumentsException extends Exception {
           
            private static final long serialVersionUID = 1154558440221248070L;

            /** Constructs an instance of this exception. */
            private TooManyArgumentsException() {}
        }
       
        /** The arguments in a List. */
        private final List<String> argsList;
       
        /**
         * Constructs an ArgumentList.
         * @param args the arguments to be encapsulated.
         */
        private ArgumentList(final String[] args) {
            argsList = new ArrayList<String>();
           
            // we drop all empty string command-line arguments
            // (these can be supplied on unix platforms via quoted empty strings e.g. '')
            for (final String element : args) {
                if (element.length() > 0) {
                    argsList.add(element);
                }
            }
        }
       
        /**
         * @return the current argument being examined.
         * @throws NotEnoughArgumentsException
         */
        private String getArgument() throws NotEnoughArgumentsException {
            if (argsList.isEmpty()) {
                throw new NotEnoughArgumentsException();
            } else {
                return argsList.get(0);
            }
        }
       
        /**
         * Removes the current argument from the list.
         * @throws NotEnoughArgumentsException
         */
        private void consumeArgument() throws NotEnoughArgumentsException {
            if (argsList.isEmpty()) {
                throw new NotEnoughArgumentsException();
            } else {
                argsList.remove(0);
            }
        }
       
        /**
         * Returns the current argument and removes it from the list.
         * @return the current argument, which is removed.
         * @throws NotEnoughArgumentsException
         */
        private String getAndConsumeArgument() throws NotEnoughArgumentsException {
            if (argsList.isEmpty()) {
                throw new NotEnoughArgumentsException();
            } else {
                return argsList.remove(0);
            }
        }
       
        /**
         * Verifies that there are no more arguments in the list, or throws an exception otherwise.
         *
         * @throws TooManyArgumentsException
         */
        private void noMoreArgumentsAllowed() throws TooManyArgumentsException {
            if (!argsList.isEmpty()) {
                throw new TooManyArgumentsException();
            }
        }
       
        /**
         * @return whether there are more arguments left.
         */
        private boolean hasMoreArguments() {
            return !argsList.isEmpty();
        }
    }
   
    /** Private constructor. This class is not meant to be instantiated. */
    private StandaloneJarTool() {}
   
    /**
     * The main method for the tool.
     * @param args
     */
    public static void main(final String[] args) {

        ////
        /// Set up a logger for printing status messages to standard output
        //
       
        final Logger logger = Logger.getLogger(StandaloneJarTool.class.getName());
        logger.setLevel(Level.FINEST);
        logger.setUseParentHandlers(false);
       
        final SimpleConsoleHandler handler = new SimpleConsoleHandler();
        handler.setLevel(Level.FINE);
        logger.addHandler(handler);

        logger.info(StandaloneJarToolMessages.getString("versionBanner", Version.CURRENT));

        ////
        /// Parsing the command line arguments
        //
       
        try {
            final ArgumentList arguments = new ArgumentList(args);
           
            final String cwsName = arguments.getAndConsumeArgument();
           
            final boolean verbose;
            if (arguments.getArgument().equals("-verbose")) {
                arguments.consumeArgument();
                verbose = true;
            } else {
                verbose = false;
            }
           
            final List<MainClassSpec> mainClassSpecs = new ArrayList<MainClassSpec>();
            final List<LibraryClassSpec> libClassSpecs = new ArrayList<LibraryClassSpec>();
           
            // unsupported option for adding all modules as libraries via -XX:all
            boolean addAllModulesAsLibraries = false;
           
            while (true) {
                final String command = arguments.getArgument();
                if (command.equals("-main")) {
                    arguments.consumeArgument();
                   
                    final String entryPointNameString = arguments.getAndConsumeArgument();
                    final String mainClassName = arguments.getAndConsumeArgument();

                    final QualifiedName entryPointName;
                    try {
                        entryPointName = QualifiedName.makeFromCompoundName(entryPointNameString);

                    } catch (final IllegalArgumentException e) {
                        logger.info(StandaloneJarToolMessages.getString("invalidEntryPointName", entryPointNameString));
                        return;
                    }
                   
                    try {
                        mainClassSpecs.add(MainClassSpec.make(mainClassName, entryPointName));
                       
                    } catch (final StandaloneJarBuilder.InvalidConfigurationException e) {
                        logger.log(Level.INFO, StandaloneJarToolMessages.getString("errorPrefix", e.getMessage()));
                        return;
                    }
                   
                } else if (command.equals("-lib")) {
                    arguments.consumeArgument();
                   
                    final String moduleNameString = arguments.getAndConsumeArgument();
                    final String libClassScope = arguments.getAndConsumeArgument();
                    final String libClassName = arguments.getAndConsumeArgument();
                   
                    final JavaScope scope;
                    try {
                        scope = JavaScope.valueOf(libClassScope.toUpperCase());
                        if (scope == JavaScope.PROTECTED || scope == JavaScope.PRIVATE) {
                            //package and private scopes are not allowed for top-level Java classes.
                            logger.info(StandaloneJarToolMessages.getString("invalidScope", libClassScope));
                            return;
                        }                   
                    } catch (final IllegalArgumentException e) {
                        logger.info(StandaloneJarToolMessages.getString("invalidScope", libClassScope));
                        return;
                    }
                   
                    final ModuleName moduleName = ModuleName.maybeMake(moduleNameString);
                    if (moduleName == null) {
                        logger.info(StandaloneJarToolMessages.getString("invalidModuleName", moduleNameString));
                        return;
                    }
                   
                    try {
                        libClassSpecs.add(LibraryClassSpec.make(scope, libClassName, moduleName));
                       
                    } catch (final StandaloneJarBuilder.InvalidConfigurationException e) {
                        logger.log(Level.INFO, StandaloneJarToolMessages.getString("errorPrefix", e.getMessage()));
                        return;
                    }
                   
                } else if (command.equals("-XX:all")) { // unsupported internal use argument - adds all modules in the program
                    arguments.consumeArgument();

                    addAllModulesAsLibraries = true;
                   
                } else {
                    // not a command... so break out of the loop to process the remainder
                    break;
                }
            }
           
            if (mainClassSpecs.isEmpty() && libClassSpecs.isEmpty() && !addAllModulesAsLibraries) {
                // there must be at least one -main or -lib command specified (or -XX:all)
                throw new ArgumentList.NotEnoughArgumentsException();
            }
           
            final File outputFile = new File(arguments.getAndConsumeArgument());
           
            final File outputSrcZipFile;
            if (arguments.hasMoreArguments()) {
               
                final String command = arguments.getAndConsumeArgument();
                if (command.equals("-src")) {
                    outputSrcZipFile = new File(arguments.getAndConsumeArgument());
                   
                } else {
                    showUsage(logger);
                    return;
                }
            } else {
                outputSrcZipFile = null;
            }
           
            arguments.noMoreArgumentsAllowed();

            if (!LECCMachineConfiguration.nonInterruptibleRuntime()) {
                logger.info(StandaloneJarToolMessages.getString("nonInterruptiblePropertyNotSet", NON_INTERRUPTIBLE_PROPERTY));
            }

            ////
            /// Compile the CAL workspace
            //

            logger.info(StandaloneJarToolMessages.getString("initializingCalWorkspace"));

            final MessageLogger msgLogger = new MessageLogger();

            final BasicCALServices calServices = BasicCALServices.makeCompiled(cwsName, msgLogger);

            if (calServices == null) {
                logger.info(msgLogger.toString());
                return;
            }

            logger.info(StandaloneJarToolMessages.getString("calWorkspaceInitialized"));

            final WorkspaceManager workspaceManager = calServices.getWorkspaceManager();
           
            // process the -XX:all argument
            if (addAllModulesAsLibraries) {
                for (final ModuleName moduleName : workspaceManager.getModuleNamesInProgram()) {
                    try {
                        libClassSpecs.add(LibraryClassSpec.make(JavaScope.PUBLIC, "cal.lib." + moduleName.toSourceText(), moduleName));

                    } catch (final StandaloneJarBuilder.InvalidConfigurationException e) {
                        logger.log(Level.INFO, StandaloneJarToolMessages.getString("errorPrefix", e.getMessage()));
                        return;
                    }
                }
            }

            ////
            /// Set up the progress monitor for displaying status messages to the user.
            //

            final StandaloneJarBuilder.Monitor monitor = new StandaloneJarBuilder.Monitor() {
                public void jarBuildingStarted(final String jarName) {
                    logger.info(StandaloneJarToolMessages.getString("buildingStandaloneJar", jarName));
                }
                public void addingFile(final String fileName) {
                    if (verbose) {
                        logger.info(StandaloneJarToolMessages.getString("addingFile", fileName));
                    }
                }
                public void skippingFunctionWithTypeClassConstraints(final QualifiedName name) {
                    // always display regardless of the verbose flag
                    logger.info(StandaloneJarToolMessages.getString("skippingFunctionWithTypeClassConstraints", name.toSourceText()));
                }
                public void skippingClassMethod(final QualifiedName name) {
                    // always display regardless of the verbose flag
                    logger.info(StandaloneJarToolMessages.getString("skippingClassMethod", name.toSourceText()));
                }
                public void addingSourceFile(final String fileName) {
                    if (verbose) {
                        logger.info(StandaloneJarToolMessages.getString("addingSourceFile", fileName));
                    }
                }
                public void jarBuildingDone(final String jarName, boolean success) {
                    if (success) {
                        logger.info(StandaloneJarToolMessages.getString("doneBuildingStandaloneJar", jarName));
                    } else {
                        logger.info(StandaloneJarToolMessages.getString("failedBuildingStandaloneJar", jarName));
                    }
                }
            };

            ////
            /// Check the arguments and build the JAR
            //

            try {
                StandaloneJarBuilder.buildStandaloneJar(outputFile, outputSrcZipFile, mainClassSpecs, libClassSpecs, workspaceManager, monitor);

            } catch (final IOException e) {
                logger.log(Level.INFO, StandaloneJarToolMessages.getString("ioError"), e);

            } catch (final StandaloneJarBuilder.InvalidConfigurationException e) {
                logger.log(Level.INFO, StandaloneJarToolMessages.getString("errorPrefix", e.getMessage()));

            } catch (final UnableToResolveForeignEntityException e) {
                logger.log(Level.INFO, StandaloneJarToolMessages.getString("foreignResolutionError"), e);
               
            } catch (final StandaloneJarBuilder.InternalProblemException e) {
                logger.log(Level.SEVERE, StandaloneJarToolMessages.getString("internalError"), e);
            }
           
        } catch (final ArgumentList.NotEnoughArgumentsException e) {
            logger.log(Level.INFO, StandaloneJarToolMessages.getString("notEnoughArguments"));
            showUsage(logger);
           
        } catch (final ArgumentList.TooManyArgumentsException e) {
            logger.log(Level.INFO, StandaloneJarToolMessages.getString("tooManyArguments"));
            showUsage(logger);
        }
    }

    /**
     * Shows the usage help.
     * @param logger the Logger to use for showing the usage help.
     */
    private static void showUsage(final Logger logger) {
        logger.info(StandaloneJarToolMessages.getString("usage", LAUNCH_COMMAND));
    }
}
TOP

Related Classes of org.openquark.cal.services.StandaloneJarTool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.