org.wisdom.maven.utils.WebJars.java Source code

Java tutorial

Introduction

Here is the source code for org.wisdom.maven.utils.WebJars.java

Source

/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.maven.utils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
import org.slf4j.LoggerFactory;
import org.wisdom.maven.mojos.AbstractWisdomMojo;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import static org.ow2.chameleon.core.utils.BundleHelper.isBundle;

/**
 * Utility methods to handle webjars.
 */
public class WebJars {
    /**
     * A regex extracting the library name and version from Zip Entry names.
     */
    public static final Pattern WEBJAR_REGEX = Pattern.compile(".*META-INF/resources/webjars/([^/]+)/([^/]+)/.*");
    /**
     * The directory within jar file where webjar resources are located.
     */
    public static final String WEBJAR_LOCATION = "META-INF/resources/webjars/";

    /**
     * A regex to extract the different part of the path of a file from a library included in a webjar.
     */
    public static final Pattern WEBJAR_INTERNAL_PATH_REGEX = Pattern.compile("([^/]+)/([^/]+)/(.*)");

    /**
     * Manage webjars dependencies.
     * <p>
     * This process is executed as follows:
     * <ol>
     * <li>web jars that are also bundles are ignored</li>
     * <li>web jars libraries from a 'provided' dependency (in the 'provided' scope) are copied to the /assets/lib
     * directory.</li>
     * <li>web jars libraries from a 'compile' dependency (in the 'compile' scope) are copied to the application
     * directory.</li>
     * <li>Transitive are also analyzed if enabled (enabled by default).</li>
     * </ol>
     *
     * @param mojo       the mojo
     * @param graph      the dependency graph builder
     * @param transitive whether or not we include the transitive dependencies.
     * @param unpackWebJars whether or not webjars should be extracted to target/webjars
     * @throws java.io.IOException when a web jar cannot be handled correctly
     */
    public static void manageWebJars(AbstractWisdomMojo mojo, DependencyGraphBuilder graph, boolean transitive,
            boolean unpackWebJars) throws IOException {
        File webjars = new File(mojo.getWisdomRootDirectory(), "assets/libs");
        final File application = new File(mojo.getWisdomRootDirectory(), "application");

        Set<Artifact> artifacts = DependencyCopy.getArtifactsToConsider(mojo, graph, transitive, null);

        for (Artifact artifact : artifacts) {
            if (DependencyCopy.SCOPE_COMPILE.equalsIgnoreCase(artifact.getScope())
                    || DependencyCopy.SCOPE_PROVIDED.equalsIgnoreCase(artifact.getScope())) {
                File file = artifact.getFile();

                // Check it's a 'jar file'
                if (!file.getName().endsWith(".jar")) {
                    mojo.getLog()
                            .debug("Dependency " + file.getName() + " is not a web jar, it's not even a jar file");
                    continue;
                }

                // Check that it's a web jar.
                if (!isWebJar(file)) {
                    mojo.getLog().debug("Dependency " + file.getName() + " is not a web jar.");
                    continue;
                }

                // Check that it's not a bundle.
                if (isBundle(file)) {
                    mojo.getLog().debug("Dependency " + file.getName() + " is a web jar, but it's also a bundle, "
                            + "to ignore it.");
                    continue;
                }

                // It's a web jar.
                if (DependencyCopy.SCOPE_COMPILE.equalsIgnoreCase(artifact.getScope())) {
                    mojo.getLog()
                            .info("Copying web jar library " + file.getName() + " to the application directory");
                    FileUtils.copyFileToDirectory(file, application);

                    // Check whether or not it must be unpacked to target/webjars.
                    if (unpackWebJars) {
                        extract(mojo, file, new File(mojo.buildDirectory, "webjars"), true);
                    }
                    // NOTE: webjars from the 'provided' scope are not unpacked in target/webjars as they are in
                    // target/wisdom/assets/libs.
                } else {
                    mojo.getLog().info("Extracting web jar libraries from " + file.getName() + " to "
                            + webjars.getAbsolutePath());
                    extract(mojo, file, webjars, false);
                }
            }
        }
    }

    /**
     * Checks whether the given file is a WebJar or not (http://www.webjars.org/documentation).
     * The check is based on the presence of {@literal META-INF/resources/webjars/} directory in the jar file.
     *
     * @param file the file.
     * @return {@literal true} if it's a bundle, {@literal false} otherwise.
     */
    public static boolean isWebJar(File file) {
        Set<String> found = new LinkedHashSet<>();
        if (file.isFile() && file.getName().endsWith(".jar")) {
            JarFile jar = null;
            try {
                jar = new JarFile(file);

                // Fast return if the base structure is not there
                if (jar.getEntry(WEBJAR_LOCATION) == null) {
                    return false;
                }

                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    Matcher matcher = WEBJAR_REGEX.matcher(entry.getName());
                    if (matcher.matches()) {
                        found.add(matcher.group(1) + "-" + matcher.group(2));
                    }
                }
            } catch (IOException e) {
                LoggerFactory.getLogger(DependencyCopy.class)
                        .error("Cannot check if the file {} is a webjar, " + "cannot open it", file.getName(), e);
                return false;
            } finally {
                final JarFile finalJar = jar;
                IOUtils.closeQuietly(new Closeable() {
                    @Override
                    public void close() throws IOException {
                        if (finalJar != null) {
                            finalJar.close();
                        }
                    }
                });
            }

            for (String lib : found) {
                LoggerFactory.getLogger(DependencyCopy.class).info("Web Library found in {} : {}", file.getName(),
                        lib);
            }

            return !found.isEmpty();
        }

        return false;
    }

    private static void extract(final AbstractWisdomMojo mojo, File in, File out, boolean stripVersion)
            throws IOException {
        ZipFile file = new ZipFile(in);
        try {
            Enumeration<? extends ZipEntry> entries = file.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();
                if (entry.getName().startsWith(WEBJAR_LOCATION) && !entry.isDirectory()) {
                    // Compute destination.
                    File output = new File(out, entry.getName().substring(WEBJAR_LOCATION.length()));
                    if (stripVersion) {
                        String path = entry.getName().substring(WEBJAR_LOCATION.length());
                        Matcher matcher = WEBJAR_INTERNAL_PATH_REGEX.matcher(path);
                        if (matcher.matches()) {
                            output = new File(out, matcher.group(1) + "/" + matcher.group(3));
                        } else {
                            mojo.getLog().warn(path
                                    + " does not match the regex - did not strip the version for this" + " file");
                        }
                    }
                    InputStream stream = null;
                    try {
                        stream = file.getInputStream(entry);
                        output.getParentFile().mkdirs();
                        FileUtils.copyInputStreamToFile(stream, output);
                    } catch (IOException e) {
                        mojo.getLog().error("Cannot unpack " + entry.getName() + " from " + file.getName(), e);
                        throw e;
                    } finally {
                        IOUtils.closeQuietly(stream);
                    }
                }
            }
        } finally {
            IOUtils.closeQuietly(file);
        }
    }
}