All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.util.maven.jbuilding.jar.ClientJarProvider Maven / Gradle / Ivy

There is a newer version: 1.0.37
Show newest version
/**
 * OW2 Util
 * Copyright (C) 2008 Bull S.A.S.
 * Contact: [email protected]
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id: ClientJarProvider.java 4389 2008-12-15 13:48:57Z alitokmen $
 * --------------------------------------------------------------------------
 */

package org.ow2.util.maven.jbuilding.jar;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import org.ow2.util.archive.api.ArchiveException;
import org.ow2.util.archive.api.IArchive;
import org.ow2.util.archive.impl.ArchiveManager;
import org.ow2.util.ee.deploy.api.deployable.IDeployable;
import org.ow2.util.ee.deploy.impl.helper.DeployableHelper;
import org.ow2.util.ee.deploy.impl.helper.UnpackDeployableHelper;
import org.ow2.util.url.URLUtils;

/**
 * Generates a big jar with the bundles content.
 * @author Guillaume Sauthier
 */
public class ClientJarProvider {

    /**
     * Source directories.
     */
    private List watched;

    /**
     * Source directories.
     */
    private List sources;

    /**
     * Target file to create if inexistant or outdated.
     */
    private File target;

    /**
     * Generated jar content.
     */
    private List content;

    /**
     * Excluded patterns.
     */
    private List exclusions;

    /**
     * Default constructor.
     */
    public ClientJarProvider() {
        this.watched = new ArrayList();
        this.sources = new ArrayList();
        this.content = new ArrayList();
        this.exclusions = new ArrayList();
    }

    /**
     * @throws Exception if unable to create the ClassLoader
     */
    public void createClientJarFile(final String version, final String mainClass) throws Exception {

        // Is there a target somewhere ?
        if (!target.exists() || isOutOfDate()) {
            // non existant or out of date
            // re-creates it
            createTargetJarFile(version, mainClass);
        }
    }

    /**
     * Initialize the client jar file.
     * @throws IOException if libraries pack/unpack fails.
     */
    private void createTargetJarFile(final String version, final String mainClass) throws IOException {

        // Delete the existing outdated file if there was one.
        if (target.exists()) {
            target.delete();
        }

        // Build the META_INF/MANIFEST.MF
        content.add("META-INF/MANIFEST.MF");
        Manifest m = new Manifest();
        Attributes attr = m.getMainAttributes();
        attr.put(Attributes.Name.MANIFEST_VERSION, "1.0"); // mandatory!
        attr.put(Attributes.Name.IMPLEMENTATION_VERSION, version); // for getVersion()
        if (mainClass != null) {
            attr.put(Attributes.Name.MAIN_CLASS, mainClass); // set the main class.
        }


        // Create the target file
        OutputStream os = new FileOutputStream(target);
        JarOutputStream jos = new JarOutputStream(os, m);

        // Iterates over the watched directories
        for (File directory : watched) {

            // Only accept file ending with .jar
            File[] childs = directory.listFiles(new FileFilter() {

                public boolean accept(final File pathname) {
                    return pathname.isFile()
                           && pathname.getName().endsWith(".jar")
                           && !pathname.equals(target);
                }

            });

            // Iterates over the bundles
            for (int i = 0; i < childs.length; i++) {
                File bundle = childs[i];

                // Add the bundle content in the client.jar
                processJarFile(bundle, jos);
            }

        }

        // Iterates over the jar sources
        for (File jar : sources) {
            processJarFile(jar, jos);
        }

        // Finish the client.jar
        jos.flush();
        jos.close();

    }

    /**
     * Extract the jar file content in the client.jar.
     * @param bundle Jar file to be processed.
     * @param jos Output
     * @throws IOException if some pack/unpack operations were not run successfully
     */
    @SuppressWarnings("unchecked")
    private void processJarFile(final File bundle, final JarOutputStream jos) throws IOException
    {
        // Look inside of the bundle for all .jar
        JarFile jf = new JarFile(bundle);

        // Pack this jar
        pack(jf, jos);

        // Browse the manifest for ClassPath entries
        Manifest manifest = jf.getManifest();

        String bundleClasspath = manifest.getMainAttributes().getValue("Bundle-Classpath");
        if (bundleClasspath != null) {

            // need to unpack it
            IDeployable dep = null;
            try {
                IArchive archive = ArchiveManager.getInstance().getArchive(bundle);
                dep = DeployableHelper.getDeployable(archive);
                dep = UnpackDeployableHelper.unpack(dep, "unpacked");
            } catch (Exception e) {
                IOException ioe = new IOException("Unable to unpack " + bundle);
                ioe.initCause(e);
                throw ioe;
            }


            // Got a Bundle: add its inner classpath
            String[] pathElements = bundleClasspath.split(",");

            for (int j = 0; j < pathElements.length; j++) {
                String path = pathElements[j];

                // Do not manage '.'
                if (!".".equals(path)) {
                    URL url = null;
                    try {
                        url = dep.getArchive().getResource(path);
                    } catch (ArchiveException e) {
                        IOException ioe = new IOException("Unable to get resource " + path + " from " + bundle);
                        ioe.initCause(e);
                        throw ioe;
                    }

                    // unpack the jar content.
                    pack(new JarFile(URLUtils.urlToFile(url)), jos);
                }
            }
        }

        // Do not forget to close
        jf.close();
    }

    /**
     * Pack the source content.
     * @param source Jar file.
     * @param jos the output stream
     * @throws IOException if pack fail
     */
    private void pack(final JarFile source, final JarOutputStream jos) throws IOException {

        // Pack all the source entries
        for (Enumeration e = source.entries(); e.hasMoreElements();) {
            JarEntry entry = e.nextElement();

            // Do not copy jar files, excluded content or already added entries
            if (!entry.getName().endsWith(".jar")
                && !content.contains(entry.getName())
                && !match(entry.getName())) {

                InputStream is = source.getInputStream(entry);

                JarEntry je = new JarEntry(entry.getName());
                jos.putNextEntry(je);

                // Copy the content
                int read = 0;
                final int MAX = 4096;
                byte[] buffer = new byte[MAX];
                while ((read = is.read(buffer)) != -1) {
                    jos.write(buffer, 0, read);
                }

                content.add(entry.getName());
                is.close();
            }
        }
    }

    /**
     * Simple pattern matching method (startsWith).
     * @param name name to be matched against exclusions patterns.
     * @return true if the name match, false otherwise
     */
    private boolean match(final String name) {
        for (String pattern : this.exclusions) {
            boolean match = name.startsWith(pattern);
            if (match) {
                return true;
            }
        }
        return false;
    }

    /**
     * @return true if the target if older than one of its sources.
     */
    private boolean isOutOfDate() {

        final long lastTargetChange = target.lastModified();
        boolean aligned = true;

        // Iterates over the watched directories
        for (File directory : watched) {

            // Only accept file ending with .jar
            File[] newer = directory.listFiles(new FileFilter() {

                public boolean accept(final File pathname) {
                    return pathname.isFile()
                           && pathname.getName().endsWith(".jar")
                           && pathname.lastModified() > lastTargetChange;
                }

            });

            if (newer.length != 0) {
                // newer files
                aligned &= false;
            }
        }

        // Iterates over the sources files
        for (File source : sources) {

            boolean newer = source.getName().endsWith(".jar")
                             && source.lastModified() > lastTargetChange;

            if (newer) {
                // newer files
                aligned &= false;
            }
        }

        return !aligned;
    }

    /**
     * Add a directory whose contained jar files will be processed.
     * @param dir watched directory
     */
    public void addWatchDirectory(final File dir) {
        watched.add(dir);
    }

    /**
     * Add a jar file name to be processed.
     * @param source source jar file name
     */
    public void addSourceFile(final File source) {
        sources.add(source);
    }

    /**
     * Set the target File.
     * @param target target File
     */
    public void setTargetJarFile(final File target) {
        this.target = target;
    }

    /**
     * Add an exclusion pattern.
     * @param pattern exclusion pattern
     */
    public void addExclusionPattern(final String pattern) {
        this.exclusions.add(pattern);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy