com.stratuscom.harvester.deployer.CommandLineAppRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.stratuscom.harvester.deployer.CommandLineAppRunner.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.stratuscom.harvester.deployer;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileType;
import com.stratuscom.harvester.ConfigurationException;
import com.stratuscom.harvester.Context;
import com.stratuscom.harvester.FileUtility;
import com.stratuscom.harvester.Init;
import com.stratuscom.harvester.Injected;
import com.stratuscom.harvester.InjectionStyle;
import com.stratuscom.harvester.MBeanRegistrar;
import com.stratuscom.harvester.MessageNames;
import com.stratuscom.harvester.Name;
import com.stratuscom.harvester.Utils;
import java.io.File;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.vfs2.FileSystemException;

/**
 *
 * A runner task that looks at the command line to determine the name of an
 * application to run from a deployment folder. Generally used to run "client"
 * apps where the name of the app is supplied on the command line, for instance
 * the browser app or the admin client app.
 */
public class CommandLineAppRunner {

    private static final Logger log = Logger.getLogger(CommandLineAppRunner.class.getName(),
            MessageNames.BUNDLE_NAME);

    @Injected
    ResourceBundle messages;

    @Injected
    public String[] commandLineArguments = null;

    @Injected(style = InjectionStyle.BY_TYPE)
    Context context = null;

    private String deployDirectory = com.stratuscom.harvester.Strings.DEFAULT_DEPLOY_DIRECTORY;

    @Injected(style = InjectionStyle.BY_TYPE)
    private FileUtility fileUtility = null;

    @Injected(style = InjectionStyle.BY_TYPE)
    private StarterServiceDeployer deployer;

    @Injected(style = InjectionStyle.BY_TYPE)
    private MBeanRegistrar mbeanRegistrar;

    @Name
    private String myName = null;

    private List<ApplicationEnvironment> applicationEnvironments = new ArrayList<ApplicationEnvironment>();

    public String getDeployDirectory() {
        return deployDirectory;
    }

    public void setDeployDirectory(String deployDirectory) {
        this.deployDirectory = deployDirectory;
    }

    FileObject deploymentDirectoryFile = null;

    private String clientAppName = null;

    public String getClientAppName() {
        return clientAppName;
    }

    /**
     * Set the client app that should be loaded. If not provided, client app
     * name is taken from the first parameter.
     *
     * @param clientApp
     */
    public void setClientAppName(String clientApp) {
        this.clientAppName = clientApp;
    }

    @Init
    public void init() {
        try {
            tryInitialize();
        } catch (Throwable ex) {
            log.log(Level.SEVERE, MessageNames.STARTUP_DEPLOYER_FAILED_INIT, ex);
            throw new ConfigurationException(ex, MessageNames.STARTUP_DEPLOYER_FAILED_INIT);
        }
    }

    /**
     * If clientAppName has been set, then we're running a predetermined app as
     * a result of the entry in Config.xml. In that case, we're not going to
     * bother with any '-with' options.
     *
     * @throws IOException
     * @throws ParseException
     * @throws org.apache.commons.cli.ParseException
     */
    private void tryInitialize() throws IOException, ParseException, org.apache.commons.cli.ParseException {
        log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);

        /*
         Establish the deployment directory.
         */
        deploymentDirectoryFile = fileUtility.getProfileDirectory().resolveFile(deployDirectory);
        if (deploymentDirectoryFile == null || deploymentDirectoryFile.getType() != FileType.FOLDER) {
            log.log(Level.WARNING, MessageNames.NO_DEPLOYMENT_DIRECTORY,
                    new Object[] { deployDirectory, fileUtility.getProfileDirectory() });
        }
        /*
         * Find the name of the client we need to deploy.  
         */
        /* First argument was the profile name.  Second argument is the name of 
         * the client app to run.  All the rest are parameters to the client
         * app.
         */
        if (clientAppName == null && commandLineArguments.length < 2) {
            System.out.println(messages.getString(MessageNames.CLIENT_APP_USAGE));
            System.exit(1);
        }
        String[] clientAppArgs = new String[0];
        String additionalApps = Strings.EMPTY;
        if (clientAppName == null) {
            String[] argsWithoutProfile = new String[commandLineArguments.length - 1];
            System.arraycopy(commandLineArguments, 1, argsWithoutProfile, 0, argsWithoutProfile.length);
            CommandLine cl = CommandLineParsers.parseCommandLineAppRunnerLine(argsWithoutProfile);
            // At this point, any remaining args after -with are in getArgs()
            // The first of those is the app name.
            clientAppName = cl.getArgs()[0];
            clientAppArgs = new String[cl.getArgs().length - 1];
            System.arraycopy(cl.getArgs(), 1, clientAppArgs, 0, clientAppArgs.length);
            if (cl.hasOption(CommandLineParsers.WITH)) {
                additionalApps = cl.getOptionValue(CommandLineParsers.WITH);
            }
        } else {
            clientAppArgs = new String[commandLineArguments.length - 1];
            System.arraycopy(commandLineArguments, 1, clientAppArgs, 0, clientAppArgs.length);
        }
        if (!Strings.EMPTY.equals(additionalApps)) {
            startAdditionalApps(additionalApps);
        }

        /*
         See if the clientAppName happens to be a 'jar' name and refers to a 
         jar file.  If so, that's the service archive.
         */
        FileObject serviceArchive = null;
        if (isAppArchive(clientAppName)) {
            serviceArchive = fileUtility.resolveFile(clientAppName);
        } else {
            serviceArchive = findServiceArchiveForName(clientAppName);
        }

        if (serviceArchive == null) {
            System.err.println(
                    MessageFormat.format(messages.getString(MessageNames.NO_SUCH_CLIENT_APP), clientAppName));
            System.exit(1);
        }
        // Deploy the service
        deployServiceArchive(serviceArchive, clientAppArgs);
        // Run the main method with the remaining command line parameters.
    }

    private FileObject findServiceArchiveForName(String appName) throws FileSystemException {
        // Locate the service archive that has the client's name.
        // First get all the jar files.
        List<FileObject> serviceArchives = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
                com.stratuscom.harvester.Strings.JAR);
        //Then find the one that starts with the client name
        for (FileObject fo : serviceArchives) {
            if (fo.getName().getBaseName().startsWith(appName + com.stratuscom.harvester.Strings.DASH)) {
                return fo;
            }
        }
        return null;
    }

    boolean isAppArchive(String appName) {
        return appName.endsWith(com.stratuscom.harvester.Strings.JAR) && (new File(appName)).isFile()
                && (new File(appName)).canRead();
    }

    /**
     * Start the apps indicated in the command line's '-with' argument.
     *
     * @param appList
     */
    private void startAdditionalApps(String appList) throws FileSystemException {
        //Split on comma
        String[] additionalApps = appList.split(Strings.COMMA);
        for (String app : additionalApps) {
            log.log(Level.INFO, MessageNames.STARTING_WITH_SERVICE, app);
            FileObject serviceArchive = findServiceArchiveForName(app);
            if (serviceArchive == null) {
                System.err.println(
                        MessageFormat.format(messages.getString(MessageNames.NO_SUCH_CLIENT_APP), clientAppName));
                System.exit(1);
            }
            deployServiceArchive(serviceArchive, new String[0]);
        }
    }

    private void deployServiceArchive(FileObject archiveFile, String[] commandLineArgs) {
        try {
            /* Try the archive in all the deployers to see if someone can 
             * handle it. For now there's only one.
             */

            /*
             * Create the ApplicationEnvironment for the archive.
             */
            ServiceLifeCycle deployedApp = deployer.deployServiceArchive(myName, archiveFile);

            deployedApp.startWithArgs(commandLineArgs);
        } catch (Throwable t) {
            log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, archiveFile.toString());
            log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
        }
    }
}