fr.jayasoft.ivy.Main.java Source code

Java tutorial

Introduction

Here is the source code for fr.jayasoft.ivy.Main.java

Source

/*
 * This file is subject to the license found in LICENCE.TXT in the root directory of the project.
 * 
 * version 1.4
 */
package fr.jayasoft.ivy;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.Path;

import fr.jayasoft.ivy.report.ResolveReport;
import fr.jayasoft.ivy.url.CredentialsStore;
import fr.jayasoft.ivy.url.URLHandler;
import fr.jayasoft.ivy.url.URLHandlerDispatcher;
import fr.jayasoft.ivy.url.URLHandlerRegistry;
import fr.jayasoft.ivy.util.DefaultMessageImpl;
import fr.jayasoft.ivy.util.Message;
import fr.jayasoft.ivy.xml.XmlModuleDescriptorWriter;
import fr.jayasoft.ivy.xml.XmlReportParser;

/**
 * class used to launch ivy as a standalone tool
 * arguments are :
 * -conf <conffile> : indicates the path to the ivy configuration file
 *                  ivyconf.xml is assumed if not given
 * -cache <cachedir> : indicates the path to the cache directory
 *                   cache is assumed if not given
 * -ivy <ivyfile> : indicates the path to the ivy file to use
 *                  ivy.xml is assumed if not given
 * -retrieve <retrievepattern> : when used, retrieve is also done using the given retrievepattern
 * -revision <revision> : the revision with which the module should be published, required to publish
 * -status <status> :   the status with which the module should be published, 
 *                      release is assumed if not given
 * -publish <publishpattern> :  the pattern used to publish the resolved ivy file, 
 *                              ivy-[revision].xml is assumed if not given
 */
public class Main {
    private static Options getOptions() {
        Option conf = OptionBuilder.withArgName("conffile").hasArg()
                .withDescription("use given file for configuration").create("conf");
        Option cache = OptionBuilder.withArgName("cachedir").hasArg()
                .withDescription("use given directory for cache").create("cache");
        Option ivyfile = OptionBuilder.withArgName("ivyfile").hasArg().withDescription("use given file as ivy file")
                .create("ivy");
        Option dependency = OptionBuilder.withArgName("organisation module revision").hasArgs()
                .withDescription(
                        "use this instead of ivy file to do the rest of the work with this as a dependency.")
                .create("dependency");
        Option confs = OptionBuilder.withArgName("configurations").hasArgs()
                .withDescription("resolve given configurations").create("confs");
        Option retrieve = OptionBuilder.withArgName("retrievepattern").hasArg()
                .withDescription("use given pattern as retrieve pattern").create("retrieve");
        Option cachepath = OptionBuilder.withArgName("cachepathfile").hasArg().withDescription(
                "outputs a classpath consisting of all dependencies in cache (including transitive ones) of the given ivy file to the given cachepathfile")
                .create("cachepath");
        Option revision = OptionBuilder.withArgName("revision").hasArg()
                .withDescription("use given revision to publish the module").create("revision");
        Option status = OptionBuilder.withArgName("status").hasArg()
                .withDescription("use given status to publish the module").create("status");
        Option deliver = OptionBuilder.withArgName("ivypattern").hasArg()
                .withDescription("use given pattern as resolved ivy file pattern").create("deliverto");
        Option publishResolver = OptionBuilder.withArgName("resolvername").hasArg()
                .withDescription("use given resolver to publish to").create("publish");
        Option publishPattern = OptionBuilder.withArgName("artpattern").hasArg()
                .withDescription("use given pattern to find artifacts to publish").create("publishpattern");
        Option realm = OptionBuilder.withArgName("realm").hasArg().withDescription("use given realm for HTTP AUTH")
                .create("realm");
        Option host = OptionBuilder.withArgName("host").hasArg().withDescription("use given host for HTTP AUTH")
                .create("host");
        Option username = OptionBuilder.withArgName("username").hasArg()
                .withDescription("use given username for HTTP AUTH").create("username");
        Option passwd = OptionBuilder.withArgName("passwd").hasArg()
                .withDescription("use given password for HTTP AUTH").create("passwd");
        Option main = OptionBuilder.withArgName("main").hasArg()
                .withDescription("the main class to runtime process").create("main");
        Option args = OptionBuilder.withArgName("args").hasArgs()
                .withDescription("the arguments to runtime process").create("args");

        Options options = new Options();

        options.addOption("debug", false, "set message level to debug");
        options.addOption("verbose", false, "set message level to verbose");
        options.addOption("warn", false, "set message level to warn");
        options.addOption("error", false, "set message level to error");
        options.addOption("novalidate", false, "do not validate ivy files against xsd");
        options.addOption("useOrigin", false,
                "use original artifact location with local resolvers instead of copying to the cache");
        options.addOption("sync", false, "in conjonction with -retrieve, does a synced retrieve");
        options.addOption("m2compatible", false, "use maven2 compatibility");
        options.addOption("?", false, "display this help");
        options.addOption(conf);
        options.addOption(confs);
        options.addOption(cache);
        options.addOption(ivyfile);
        options.addOption(dependency);
        options.addOption(retrieve);
        options.addOption(cachepath);
        options.addOption(revision);
        options.addOption(status);
        options.addOption(deliver);
        options.addOption(publishResolver);
        options.addOption(publishPattern);
        options.addOption(realm);
        options.addOption(host);
        options.addOption(username);
        options.addOption(passwd);
        options.addOption(main);
        options.addOption(args);

        return options;
    }

    public static void main(String[] args) throws Exception {
        Options options = getOptions();

        CommandLineParser parser = new GnuParser();
        try {
            // parse the command line arguments
            CommandLine line = parser.parse(options, args);

            if (line.hasOption("?")) {
                usage(options);
                return;
            }

            if (line.hasOption("debug")) {
                Message.init(new DefaultMessageImpl(Message.MSG_DEBUG));
            } else if (line.hasOption("verbose")) {
                Message.init(new DefaultMessageImpl(Message.MSG_VERBOSE));
            } else if (line.hasOption("warn")) {
                Message.init(new DefaultMessageImpl(Message.MSG_WARN));
            } else if (line.hasOption("error")) {
                Message.init(new DefaultMessageImpl(Message.MSG_ERR));
            } else {
                Message.init(new DefaultMessageImpl(Message.MSG_INFO));
            }

            boolean validate = line.hasOption("novalidate") ? false : true;

            Ivy ivy = new Ivy();
            ivy.addAllVariables(System.getProperties());
            if (line.hasOption("m2compatible")) {
                ivy.setVariable("ivy.default.configuration.m2compatible", "true");
            }

            configureURLHandler(line.getOptionValue("realm", null), line.getOptionValue("host", null),
                    line.getOptionValue("username", null), line.getOptionValue("passwd", null));

            String confPath = line.getOptionValue("conf", "");
            if ("".equals(confPath)) {
                ivy.configureDefault();
            } else {
                File conffile = new File(confPath);
                if (!conffile.exists()) {
                    error(options, "ivy configuration file not found: " + conffile);
                } else if (conffile.isDirectory()) {
                    error(options, "ivy configuration file is not a file: " + conffile);
                }
                ivy.configure(conffile);
            }

            File cache = new File(
                    ivy.substitute(line.getOptionValue("cache", ivy.getDefaultCache().getAbsolutePath())));
            if (!cache.exists()) {
                cache.mkdirs();
            } else if (!cache.isDirectory()) {
                error(options, cache + " is not a directory");
            }

            String[] confs;
            if (line.hasOption("confs")) {
                confs = line.getOptionValues("confs");
            } else {
                confs = new String[] { "*" };
            }

            File ivyfile;
            if (line.hasOption("dependency")) {
                String[] dep = line.getOptionValues("dependency");
                if (dep.length != 3) {
                    error(options,
                            "dependency should be expressed with exactly 3 arguments: organisation module revision");
                }
                ivyfile = File.createTempFile("ivy", ".xml");
                ivyfile.deleteOnExit();
                DefaultModuleDescriptor md = DefaultModuleDescriptor
                        .newDefaultInstance(ModuleRevisionId.newInstance(dep[0], dep[1] + "-caller", "working"));
                DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md,
                        ModuleRevisionId.newInstance(dep[0], dep[1], dep[2]), false, false, true);
                for (int i = 0; i < confs.length; i++) {
                    dd.addDependencyConfiguration("default", confs[i]);
                }
                md.addDependency(dd);
                XmlModuleDescriptorWriter.write(md, ivyfile);
                confs = new String[] { "default" };
            } else {
                ivyfile = new File(ivy.substitute(line.getOptionValue("ivy", "ivy.xml")));
                if (!ivyfile.exists()) {
                    error(options, "ivy file not found: " + ivyfile);
                } else if (ivyfile.isDirectory()) {
                    error(options, "ivy file is not a file: " + ivyfile);
                }
            }

            ResolveReport report = ivy.resolve(ivyfile.toURL(), null, confs, cache, null, validate, false, true,
                    line.hasOption("useOrigin"), null);
            if (report.hasError()) {
                System.exit(1);
            }
            ModuleDescriptor md = report.getModuleDescriptor();

            if (confs.length == 1 && "*".equals(confs[0])) {
                confs = md.getConfigurationsNames();
            }
            if (line.hasOption("retrieve")) {
                String retrievePattern = ivy.substitute(line.getOptionValue("retrieve"));
                if (retrievePattern.indexOf("[") == -1) {
                    retrievePattern = retrievePattern + "/lib/[conf]/[artifact].[ext]";
                }
                ivy.retrieve(md.getModuleRevisionId().getModuleId(), confs, cache, retrievePattern, null, null,
                        line.hasOption("sync"), line.hasOption("useOrigin"));
            }
            if (line.hasOption("cachepath")) {
                outputCachePath(ivy, cache, md, confs, line.getOptionValue("cachepath", "ivycachepath.txt"));
            }

            if (line.hasOption("revision")) {
                ivy.deliver(md.getResolvedModuleRevisionId(), ivy.substitute(line.getOptionValue("revision")),
                        cache, ivy.substitute(line.getOptionValue("deliverto", "ivy-[revision].xml")),
                        ivy.substitute(line.getOptionValue("status", "release")), null,
                        new DefaultPublishingDRResolver(), validate);
                if (line.hasOption("publish")) {
                    ivy.publish(md.getResolvedModuleRevisionId(), ivy.substitute(line.getOptionValue("revision")),
                            cache,
                            ivy.substitute(line.getOptionValue("publishpattern",
                                    "distrib/[type]s/[artifact]-[revision].[ext]")),
                            line.getOptionValue("publish"),
                            ivy.substitute(line.getOptionValue("deliverto", "ivy-[revision].xml")), validate);

                }
            }
            if (line.hasOption("main")) {
                invoke(ivy, cache, md, confs, line.getOptionValue("main"), line.getOptionValues("args"));
            }
        } catch (ParseException exp) {
            // oops, something went wrong
            System.err.println("Parsing failed.  Reason: " + exp.getMessage());

            usage(options);
        }
    }

    private static void outputCachePath(Ivy ivy, File cache, ModuleDescriptor md, String[] confs, String outFile) {
        try {
            String pathSeparator = System.getProperty("path.separator");
            StringBuffer buf = new StringBuffer();
            XmlReportParser parser = new XmlReportParser();
            Collection all = new LinkedHashSet();
            for (int i = 0; i < confs.length; i++) {
                Artifact[] artifacts = parser.getArtifacts(md.getModuleRevisionId().getModuleId(), confs[i], cache);
                all.addAll(Arrays.asList(artifacts));
            }
            for (Iterator iter = all.iterator(); iter.hasNext();) {
                Artifact artifact = (Artifact) iter.next();
                buf.append(ivy.getArchiveFileInCache(cache, artifact).getCanonicalPath());
                if (iter.hasNext()) {
                    buf.append(pathSeparator);
                }
            }
            PrintWriter writer = new PrintWriter(new FileOutputStream(outFile));
            writer.println(buf.toString());
            writer.close();
            System.out.println("cachepath output to " + outFile);

        } catch (Exception ex) {
            throw new RuntimeException("impossible to build ivy cache path: " + ex.getMessage(), ex);
        }
    }

    private static void invoke(Ivy ivy, File cache, ModuleDescriptor md, String[] confs, String mainclass,
            String[] args) {
        List urls = new ArrayList();

        try {
            XmlReportParser parser = new XmlReportParser();
            Collection all = new LinkedHashSet();
            for (int i = 0; i < confs.length; i++) {
                Artifact[] artifacts = parser.getArtifacts(md.getModuleRevisionId().getModuleId(), confs[i], cache);
                all.addAll(Arrays.asList(artifacts));
            }
            for (Iterator iter = all.iterator(); iter.hasNext();) {
                Artifact artifact = (Artifact) iter.next();

                urls.add(ivy.getArchiveFileInCache(cache, artifact).toURL());
            }
        } catch (Exception ex) {
            throw new RuntimeException("impossible to build ivy cache path: " + ex.getMessage(), ex);
        }

        URLClassLoader classLoader = new URLClassLoader((URL[]) urls.toArray(new URL[urls.size()]),
                Main.class.getClassLoader());

        try {
            Class c = classLoader.loadClass(mainclass);

            Method mainMethod = c.getMethod("main", new Class[] { String[].class });

            // Split up arguments 
            mainMethod.invoke(null, new Object[] { args });
        } catch (ClassNotFoundException cnfe) {
            throw new RuntimeException("Could not find class: " + mainclass, cnfe);
        } catch (SecurityException e) {
            throw new RuntimeException("Could not find main method: " + mainclass, e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Could not find main method: " + mainclass, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("No permissions to invoke main method: " + mainclass, e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Unexpected exception invoking main method: " + mainclass, e);
        }
    }

    private static void configureURLHandler(String realm, String host, String username, String passwd) {
        CredentialsStore.INSTANCE.addCredentials(realm, host, username, passwd);

        URLHandlerDispatcher dispatcher = new URLHandlerDispatcher();
        URLHandler httpHandler = URLHandlerRegistry.getHttp();
        dispatcher.setDownloader("http", httpHandler);
        dispatcher.setDownloader("https", httpHandler);
        URLHandlerRegistry.setDefault(dispatcher);
    }

    private static void error(Options options, String msg) {
        System.err.println(msg);
        usage(options);
        System.exit(1);
    }

    private static void usage(Options options) {
        // automatically generate the help statement
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("ivy", options);
    }

}