com.cloudbees.sdk.Bees.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudbees.sdk.Bees.java

Source

/*
 * Copyright 2010-2013, CloudBees Inc.
 *
 * Licensed 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.cloudbees.sdk;

import com.cloudbees.api.BeesClientException;
import com.cloudbees.sdk.cli.ACommand;
import com.cloudbees.sdk.cli.CommandScope;
import com.cloudbees.sdk.cli.CommandService;
import com.cloudbees.sdk.cli.DirectoryStructure;
import com.cloudbees.sdk.extensibility.AnnotationLiteral;
import com.cloudbees.sdk.maven.MavenRepositorySystemSessionDecorator;
import com.cloudbees.sdk.maven.RemoteRepositoryDecorator;
import com.cloudbees.sdk.maven.RepositorySystemModule;
import com.cloudbees.sdk.utils.Helper;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.staxnet.appserver.utils.XmlHelper;
import com.staxnet.repository.LocalRepository;
import hudson.util.VersionNumber;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.*;

import javax.inject.Inject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @author Fabian Donze
 * @author Kohsuke Kawaguchi
 */
public class Bees {
    public static String BOOTSTRAP_VERSION = "1.3.2";
    /**
     * Version of the bees CLI.
     */
    public static VersionNumber version = loadVersion();

    private final static String app_template_xml_url = "http://cloudbees-downloads.s3.amazonaws.com/";
    private final static String app_template_xml_name = "sdk/cloudbees-sdk-config-5.xml";
    private final static String app_template_xml_desc = "CloudBees SDK configuration";
    private static final long CHECK_INTERVAL = 1000 * 60 * 60 * 12; // 12 hours
    public final static String CHECK_FILE = "sdk/check-5.dat";
    public static final String SDK_PLUGIN_INSTALL = "plugin:install";

    @Inject
    private CommandService commandService;

    @Inject
    private PluginsToInstallList pluginsToInstallList;

    /**
     * Entry point to all the components.
     */
    private final Injector injector;

    private final ClassLoader extLoader;

    public Bees() throws Exception {
        extLoader = getClass().getClassLoader();
        //  container that includes all the things that make a bees CLI.
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(CommandService.class).to(CommandServiceImpl.class);
                bind(ClassLoader.class).annotatedWith(AnnotationLiteral.of(ExtensionClassLoader.class))
                        .toInstance(extLoader);
                bindScope(CommandScope.class, new CommandScopeImpl());
                bind(RemoteRepositoryDecorator.class).to(RemoteRepositoryDecoratorImpl.class);
                bind(MavenRepositorySystemSessionDecorator.class)
                        .to(CliMavenRepositorySystemSessionDecorator.class);
            }
        }, new RepositorySystemModule());

        this.injector = injector;
        this.injector.injectMembers(this);
        CommandServiceImpl service = (CommandServiceImpl) commandService;
        service.loadCommandProperties();
        if (service.getCount() == 0) {
            throw new RuntimeException("Cannot find bees commands");
        }
    }

    public int run(String[] args) throws Exception {
        reportTime("Bees.run");

        // Load command definitions
        if (args.length == 0)
            args = new String[] { "help" };

        Object context = CommandScopeImpl.begin();
        try {
            // If it is the init command, execute before anything else
            if (args[0].equalsIgnoreCase("init")) {
                // Setup the configuration file
                ACommand setupCommand = commandService.getCommand(args[0]);
                if (setupCommand == null)
                    throw new Error("Panic: init error");
                setupCommand.run(Arrays.asList(args));

                // Initialize the SDK
                initialize(false);

                // Install plugins
                installPlugins(args);

                return 0;
            } else {
                // Initialize the SDK
                initialize(false);

                // Install plugins
                installPlugins(args);

                ACommand command = commandService.getCommand(args[0]);
                if (command == null) {
                    // no such command. print help
                    System.err.println("No such command: " + args[0]);
                    command = commandService.getCommand("help");
                    if (command == null)
                        throw new Error("Panic: command " + args[0]
                                + " was not found, and even the help command was not found");
                }

                int r = command.run(Arrays.asList(args));
                if (r == 99) {
                    initialize(true);
                }
                return r;
            }

        } finally {
            CommandScopeImpl.end(context);
        }
    }

    private String getHome() {
        return System.getProperty("bees.home");
    }

    private void initialize(boolean force) throws Exception {
        LocalRepository localRepository = new LocalRepository();

        String beesRepoPath = localRepository.getRepositoryPath();
        File lastCheckFile = new File(beesRepoPath, CHECK_FILE);
        boolean checkVersion = true;
        Properties p = new Properties();
        if (!force && Helper.loadProperties(lastCheckFile, p)) {
            String str = p.getProperty("last");
            if (str != null) {
                long interval = System.currentTimeMillis() - Long.parseLong(str);
                if (interval < CHECK_INTERVAL)
                    checkVersion = false;
            }
        }

        if (checkVersion) {
            // Check SDK version
            File sdkConfig = getURLAsFile(localRepository, app_template_xml_url + app_template_xml_name,
                    app_template_xml_name, app_template_xml_desc);
            Document doc = XmlHelper.readXMLFromFile(sdkConfig.getCanonicalPath());
            Element e = doc.getDocumentElement();
            String availVersion = e.getAttribute("version");
            String minVersion = e.getAttribute("min-version");

            VersionNumber currentVersion = new VersionNumber(BOOTSTRAP_VERSION);
            VersionNumber availableVersion = new VersionNumber(availVersion);
            VersionNumber minimumVersion = new VersionNumber(minVersion);

            if (currentVersion.compareTo(availableVersion) < 0) {
                System.out.println();
                if (currentVersion.compareTo(minimumVersion) < 0) {
                    throw new AbortException("ERROR - This version of the CloudBees SDK is no longer supported,"
                            + "" + " please install the latest version (" + availVersion + ").");
                } else if (currentVersion.compareTo(availableVersion) < 0) {
                    System.out.println(
                            "WARNING - A new version of the CloudBees SDK is available, please install the latest version ("
                                    + availVersion + ").");
                }

                String hRef = e.getAttribute("href");

                String homeRef = "www.cloudbees.com";
                NodeList nodeList = e.getElementsByTagName("link");
                for (int i = 0; i < nodeList.getLength(); i++) {
                    Node node = nodeList.item(i);
                    NamedNodeMap nodeMap = node.getAttributes();
                    Node rel = nodeMap.getNamedItem("rel");
                    Node href = nodeMap.getNamedItem("href");
                    if (rel != null && rel.getTextContent().trim().equalsIgnoreCase("alternate") && href != null) {
                        homeRef = href.getTextContent();
                    }
                }

                NodeList libsNL = e.getElementsByTagName("libraries");
                Node libsNode = null;
                if (libsNL.getLength() > 0) {
                    libsNode = libsNL.item(0);
                }
                if (libsNode != null) {
                    NodeList libNL = e.getElementsByTagName("library");
                    for (int i = 0; i < libNL.getLength(); i++) {
                        Node node = libNL.item(i);
                        NamedNodeMap nodeMap = node.getAttributes();
                        Node nameNode = nodeMap.getNamedItem("name");
                        Node refNode = nodeMap.getNamedItem("href");
                        if (nameNode != null && refNode != null) {
                            String libName = nameNode.getTextContent();
                            String libUrlString = refNode.getTextContent().trim();
                            int idx = libUrlString.lastIndexOf('/');
                            String libFileName = libUrlString.substring(idx);
                            localRepository.getURLAsFile(libUrlString, "lib1" + libFileName, libName);
                        }
                    }
                }

                System.out.println("  SDK home:     " + homeRef);
                System.out.println("  SDK download: " + hRef);
                System.out.println();
            }

            // Check plugins version
            NodeList pluginsNL = e.getElementsByTagName("plugins");
            Node pluginsNode = null;
            if (pluginsNL.getLength() > 0) {
                pluginsNode = pluginsNL.item(0);
            }
            if (pluginsNode != null) {
                NodeList pluginNL = e.getElementsByTagName("plugin");
                CommandServiceImpl service = (CommandServiceImpl) commandService;
                for (int i = 0; i < pluginNL.getLength(); i++) {
                    Node node = pluginNL.item(i);
                    NamedNodeMap nodeMap = node.getAttributes();
                    Node nameNode = nodeMap.getNamedItem("artifact");
                    if (nameNode != null) {
                        Node n = nodeMap.getNamedItem("required");
                        boolean forceInstall = (n != null && Boolean.parseBoolean(n.getTextContent()));

                        String pluginArtifact = nameNode.getTextContent();
                        GAV gav = new GAV(pluginArtifact);
                        VersionNumber pluginVersion = new VersionNumber(gav.version);
                        Plugin plugin = service.getPlugin(gav.artifactId);
                        if (plugin != null) {
                            forceInstall = false;
                            GAV pgav = new GAV(plugin.getArtifact());
                            VersionNumber currentPluginVersion = new VersionNumber(pgav.version);
                            if (currentPluginVersion.compareTo(pluginVersion) < 0) {
                                Node nf = nodeMap.getNamedItem("force-upgrade");
                                boolean forced = (nf != null && Boolean.parseBoolean(nf.getTextContent()));
                                if (forced) {
                                    forceInstall = true;
                                } else {
                                    System.out.println();
                                    System.out.println("WARNING - A newer version of the [" + gav.artifactId
                                            + "] plugin is available, please update with:");
                                    System.out.println(" > bees plugin:update " + gav.artifactId);
                                    System.out.println();
                                }
                            }
                        }
                        if (forceInstall)
                            pluginsToInstallList.put(gav.artifactId, gav);

                    }
                }
            }

            // Update last check
            p.setProperty("last", "" + System.currentTimeMillis());
            lastCheckFile.getParentFile().mkdirs();
            FileOutputStream fos = new FileOutputStream(lastCheckFile);
            p.store(fos, "CloudBees SDK check");
            fos.close();
        }
    }

    private void installPlugins(String[] args) throws Exception {
        Set<Map.Entry<String, GAV>> set = pluginsToInstallList.entrySet();
        if (set.size() > 0) {
            ACommand installPluginCmd = commandService.getCommand(SDK_PLUGIN_INSTALL);
            Iterator<Map.Entry<String, GAV>> it = set.iterator();
            while (it.hasNext()) {
                Map.Entry<String, GAV> entry = it.next();
                System.out.println("Installing plugin: " + entry.getValue());
                List<String> piArgs;
                if (isVerbose(args))
                    piArgs = Arrays.asList(SDK_PLUGIN_INSTALL, entry.getValue().toString(), "-f", "-v");
                else
                    piArgs = Arrays.asList(SDK_PLUGIN_INSTALL, entry.getValue().toString(), "-f");
                installPluginCmd.run(piArgs);
                pluginsToInstallList.remove(entry.getKey());
            }
            // Reload the plugins commands
            CommandServiceImpl service = (CommandServiceImpl) commandService;
            service.loadCommandProperties();
        }
    }

    private File getURLAsFile(LocalRepository localRepository, String urlStr, String localCachePath,
            String description) throws IOException {
        try {
            DirectoryStructure ds = new DirectoryStructure();
            Properties properties = new Properties();
            if (Helper.loadProperties(new File(ds.localRepository, "bees.config"), properties)) {
                Helper.setJVMProxySettings(properties);
            }
            return localRepository.getURLAsFile(urlStr, localCachePath, description);
        } catch (Exception e) {
            throw (IOException) new IOException("Failed to retrieve " + urlStr).initCause(e);
        }
    }

    public static void main(String[] args) {
        reportTime("Bees");

        boolean verbose = isVerbose(args);
        if (verbose || isHelp(args) || isPluginCmd(args)) {
            System.out.println("# CloudBees SDK version: " + BOOTSTRAP_VERSION);
            System.out.println("# CloudBees Driver version: " + version);
            if (verbose)
                System.out.println(System.getProperties());
        }
        try {
            new Bees().run(args);
        } catch (BeesClientException e) {
            System.err.println();
            String errCode = e.getError().getErrorCode();
            if (errCode != null && errCode.equals("AuthFailure")) {
                if (e.getError().getMessage() != null)
                    System.err.println("ERROR: " + e.getError().getMessage());
                else
                    System.err.println("ERROR: Authentication failure, please check credentials!");
            } else
                System.err.println("ERROR: " + e.getMessage());
            //            e.printStackTrace();
            System.exit(2);
        } catch (UnrecognizedOptionException e) {
            System.err.println();
            System.err.println("ERROR: " + e.getMessage());
            System.exit(2);
        } catch (IllegalArgumentException e) {
            System.err.println();
            System.err.println("ERROR: " + e.getMessage());
            System.exit(2);
        } catch (BeesSecurityException e) {
            System.err.println();
            System.err.println("ERROR: " + e.getMessage());
            System.exit(2);
        } catch (Throwable e) {
            System.err.println();
            System.err.println("ERROR: " + e.getMessage());
            if (isVerbose(args))
                e.printStackTrace();
            System.exit(2);
        }
    }

    /**
     * Parses the version number of SDK from the resource file that Maven produces.
     * <p/>
     * To support running this from IDE and elsewhere, work gracefully if the version
     * is not available or not filtered.
     */
    private static VersionNumber loadVersion() {
        Properties props = new Properties();
        InputStream in = Bees.class.getResourceAsStream("version.properties");
        if (in != null) {
            try {
                props.load(in);
            } catch (IOException e) {
                throw new Error(e);
            } finally {
                IOUtils.closeQuietly(in);
            }
        }
        Object v = props.get("version");
        if (v != null)
            try {
                return new VersionNumber(v.toString());
            } catch (Exception e) {
                // fall through
            }

        return new VersionNumber("0");
    }

    private static boolean isVerbose(String[] args) {
        for (String arg : args) {
            if (arg.equalsIgnoreCase("-v") || arg.equalsIgnoreCase("--verbose"))
                return true;
        }
        return false;
    }

    private static boolean isHelp(String[] args) {
        if (args.length == 0)
            return true;
        for (String arg : args) {
            if (arg.equalsIgnoreCase("help"))
                return true;
        }
        return false;
    }

    private static boolean isPluginCmd(String[] args) {
        if (args.length == 0)
            return false;
        for (String arg : args) {
            if (arg.startsWith("plugin:"))
                return true;
        }
        return false;
    }

    private static void reportTime(String caption) {
        String profile = System.getProperty("profile");
        if (profile != null) {
            System.out.println(caption + ": " + (System.nanoTime() - Long.valueOf(profile)) / 1000000L + "ms");
        }
    }
}