org.richfaces.cdk.rd.mojo.ResourceDependencyMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.richfaces.cdk.rd.mojo.ResourceDependencyMojo.java

Source

/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * 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
 */
package org.richfaces.cdk.rd.mojo;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.digester.Digester;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.VFS;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.MavenMetadataSource;
import org.codehaus.classworlds.ClassRealm;
import org.codehaus.classworlds.ClassWorld;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.velocity.VelocityComponent;
import org.richfaces.cdk.rd.Components;
import org.richfaces.cdk.rd.generator.ResourceAssembler;
import org.richfaces.cdk.rd.generator.ResourcesGenerator;
import org.richfaces.cdk.rd.generator.ScriptAssembler;
import org.richfaces.cdk.rd.generator.StyleAssembler;
import org.richfaces.cdk.rd.handler.ComponentsHandler;
import org.richfaces.cdk.rd.utils.PluginUtils;

/**
 * @author Anton Belevich
 * @goal assembly-resources
 * @phase generate-resources
 *   
 */
public class ResourceDependencyMojo extends AbstractMojo {

    /**
     * Top maven project.
     * 
     * @parameter expression="${project}"
     * @readonly
     */
    MavenProject project;

    /**
     * Used to look up Artifacts in the remote repository.
     * 
     * @component
     */
    private ArtifactFactory factory;

    /**
     * Used to look up Artifacts in the remote repository.
     * 
     * @component
     */
    private ArtifactResolver resolver;

    /**
     *
     * @component
     */
    private ArtifactMetadataSource metadataSource;

    /**
     * @component
     */
    protected VelocityComponent velocity;

    /**
     * The local repository.
     * 
     * @parameter expression="${localRepository}"
     */
    private ArtifactRepository localRepository;

    /**
     * webSourceDirectory
     * 
     * @parameter expression="${basedir}/src/main/webapp" 
     */
    private File webSourceDirectory;

    /**
     * scriptFilePath
     * @parameter expression="custom-dependencies"
     */
    private String scriptFilePath;

    /**
     * outputResourceDirectory
     * @parameter expression="${project.build.directory}/generated-resources
     * 
     */
    private File outputResourceDirectory;
    /**
     * styleFilePath
     * @parameter  expression="custom-dependencies"
     */
    private String styleFilePath;

    /**
     * beforeScriptIncludes
     * @parameter
     */
    private List<String> beforeScriptIncludes;

    /** 
     * afterScriptIncludes
     * @parameter
     */
    private List<String> afterScriptIncludes;

    /**
     * beforeStyleIncludes
     * @parameter
     */
    private List<String> beforeStyleIncludes;

    /** 
     * afterStyleIncludes
     * @parameter
     */
    private List<String> afterStyleIncludes;

    /**
     * scriptIncludes
     * @parameter 
     */
    private String[] scriptIncludes;

    /**
     * scriptExcludes
     * @parameter
     */
    private String[] scriptExcludes;

    /**
     * styleIncludes
     * @parameter
     */
    private String[] styleIncludes;

    /**
     * styleExcludes 
     * @parameter
     */
    private String[] styleExcludes;

    /**
     * namespaceIncludes
     * @parameter
     */
    private String[] namespaceIncludes;

    /**
     * namespaceExcludes
     * @parameter
     */
    private String[] namespaceExcludes;

    /**
     * componentIncludes
     * @parameter 
     */
    private String[] componentIncludes;

    /**
     * componentExcludes
     * @parameter
     */
    private String[] componentExcludes;

    /**
     * xmlConfigPatterns
     * @parameter 
     */
    private String[] xmlConfigPatterns;

    /**
     * xhtmlIncludes
     * @parameter
     */
    private String[] xhtmlIncludes;

    /**
     * xhtmlExcludes
     * @parameter
     */
    private String[] xhtmlExcludes;

    public void execute() throws MojoExecutionException, MojoFailureException {

        try {
            Set<Artifact> artifacts = resolveDependenciesArtifacts();

            Digester defaultDigester = createDigester();

            Map<String, Components> components = new HashMap<String, Components>();

            if (xmlConfigPatterns == null) {
                xmlConfigPatterns = PluginUtils.DEFAULT_CONFIG_PATTERNS;
            }

            for (Artifact artifact : artifacts) {
                FileObject jar = resolveArtifact(artifact);
                getLog().info("Process jar: " + jar.getName().getFriendlyURI());
                FileObject[] configs = PluginUtils.resolveConfigsFromJar(jar, xmlConfigPatterns);

                if (configs.length == 0) {
                    getLog().info("no dependecy files found");
                } else {
                    getLog().info("next dependency files found");
                    for (FileObject config : configs) {
                        getLog().info(config.getName().getBaseName());
                    }
                }

                components.putAll(PluginUtils.processConfigs(configs, defaultDigester));
            }

            if (!webSourceDirectory.exists()) {
                webSourceDirectory.mkdirs();
            }

            ComponentsHandler handler = findComponents(webSourceDirectory, components, xhtmlIncludes,
                    xhtmlExcludes);

            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
            ClassLoader contextClassLoader = createClassLoader();
            Thread.currentThread().setContextClassLoader(contextClassLoader);

            if (contextClassLoader != null) {

                Set<String> scripts = handler.getScripts();

                scriptFilePath = scriptFilePath.endsWith(".js") ? scriptFilePath : scriptFilePath + ".js";
                File scriptFile = new File(outputResourceDirectory, scriptFilePath);
                if (!scriptFile.exists()) {
                    File parent = scriptFile.getParentFile();
                    if (parent != null && !parent.exists()) {
                        parent.mkdirs();
                    }
                }

                ScriptAssembler scriptAssembler = new ScriptAssembler(getLog());

                if (!scripts.isEmpty()) {
                    getLog().info("Start merge scripts to the: " + scriptFile.getPath());
                    mergeResources(scriptFile, scriptAssembler, beforeScriptIncludes, afterScriptIncludes, scripts);
                }

                Set<String> styles = handler.getStyles();

                styleFilePath = styleFilePath.endsWith(".xcss") ? styleFilePath : styleFilePath + ".xcss";

                File styleFile = new File(outputResourceDirectory, styleFilePath);
                File parent = styleFile.getParentFile();
                if (parent != null && !parent.exists()) {
                    parent.mkdirs();
                }

                StyleAssembler styleAssembler = new StyleAssembler(getLog());
                styleAssembler.setVelocityComponent(velocity);

                if (!styles.isEmpty()) {
                    getLog().info("Start merge styles to the: " + styleFile.getPath());
                    mergeResources(styleFile, styleAssembler, beforeStyleIncludes, afterStyleIncludes, styles);
                }

                Resource resource = new Resource();
                resource.setDirectory(outputResourceDirectory.getPath());
                project.addResource(resource);
            }

            Thread.currentThread().setContextClassLoader(oldClassLoader);

        } catch (Exception e) {
            getLog().error("Error generate resource", e);
            throw new MojoExecutionException(e.getMessage(), e);
        }

    }

    public void mergeResources(File assembly, ResourceAssembler assembler, List<String> beforeIncludes,
            List<String> afterIncludes, Collection<String> resources) {
        ResourcesGenerator styleGenerator = new ResourcesGenerator(getLog());
        styleGenerator.setAssembler(assembler);
        styleGenerator.setIncludesAfter(afterIncludes);
        styleGenerator.setIncludesBefore(beforeIncludes);
        styleGenerator.setResources(resources);
        styleGenerator.setAssemblyFile(assembly);
        styleGenerator.doAssembly();
        styleGenerator.writeToFile();
    }

    protected Set<Artifact> resolveDependenciesArtifacts() throws Exception {

        ArtifactResolutionResult result = null;

        List<Dependency> dependencies = project.getDependencies();

        Set<Artifact> artifacts = MavenMetadataSource.createArtifacts(factory, dependencies, null, null, project);
        artifacts.add(project.getArtifact());

        result = resolver.resolveTransitively(artifacts, project.getArtifact(), Collections.EMPTY_LIST,
                localRepository, metadataSource);
        return result.getArtifacts();
    }

    public ComponentsHandler findComponents(File webSourceDir, Map<String, Components> components,
            String[] includes, String[] excludes) throws Exception {

        if (includes == null) {
            includes = PluginUtils.DEFAULT_PROCESS_INCLUDES;
        }

        if (excludes == null) {
            excludes = new String[0];
        }

        DirectoryScanner scanner = new DirectoryScanner();
        scanner.setBasedir(webSourceDir);
        scanner.setIncludes(includes);
        scanner.setExcludes(excludes);
        scanner.addDefaultExcludes();
        getLog().info("search *.xhtml files");
        scanner.scan();

        String[] collectedFiles = scanner.getIncludedFiles();

        for (String collectedFile : collectedFiles) {
            getLog().info(collectedFile + " found");
        }

        ComponentsHandler handler = new ComponentsHandler(getLog());
        handler.setComponents(components);
        handler.setScriptIncludes(scriptIncludes);
        handler.setScriptExcludes(scriptExcludes);
        handler.setStyleIncludes(styleIncludes);
        handler.setStyleExcludes(styleExcludes);
        handler.setComponentIncludes(componentIncludes);
        handler.setComponentExcludes(componentExcludes);
        handler.setNamespaceIncludes(namespaceIncludes);
        handler.setNamespaceExcludes(namespaceExcludes);

        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        saxParserFactory.setNamespaceAware(true);

        Log log = getLog();
        for (String processFile : collectedFiles) {
            SAXParser saxParser = saxParserFactory.newSAXParser();
            File file = new File(webSourceDir, processFile);
            if (file.exists()) {

                if (log.isDebugEnabled()) {
                    log.debug("start process file: " + file.getPath());
                }

                try {
                    saxParser.parse(file, handler);
                } catch (Exception e) {
                    if (log.isDebugEnabled()) {
                        log.error("Error process file: " + file.getPath() + "\n" + e.getMessage(), e);
                    } else {
                        log.error("Error process file: " + file.getPath() + "\n" + e.getMessage());
                    }
                }
            }
        }

        return handler;
    }

    protected FileObject resolveArtifact(Artifact artifact) {
        FileObject jarFileObjects = null;

        if (artifact != null) {

            try {
                resolver.resolve(artifact, Collections.EMPTY_LIST, localRepository);
                if (getLog().isDebugEnabled()) {
                    getLog().debug("artifact " + artifact.getFile().toURI() + " is resolved");
                }
            } catch (ArtifactResolutionException e) {
                getLog().error(
                        "Error with resolve artifact " + artifact.getFile().getPath() + "\n" + e.getMessage(), e);
            } catch (ArtifactNotFoundException e) {
                getLog().error("Not found artifact " + artifact.getFile().toURI() + "\n" + e.getMessage(), e);
            }

            File file = artifact.getFile();

            try {
                FileSystemManager manager = VFS.getManager();
                jarFileObjects = manager.resolveFile("jar:" + file.toURI());
            } catch (FileSystemException e) {
                getLog().error("Error during processing file: " + file.toURI() + "\n" + e.getMessage(), e);
            }

        }

        return jarFileObjects;
    }

    public Digester createDigester() {
        // default digester for *.component-dependencies.xml
        return PluginUtils.createDefaultDigester();
    }

    protected ClassLoader createClassLoader() throws Exception {

        ClassLoader classLoader = null;

        Set<Artifact> artifacts = resolveDependenciesArtifacts();

        //create a new classloading space
        ClassWorld world = new ClassWorld();

        //use the existing ContextClassLoader in a realm of the classloading space
        ClassRealm realm = world.newRealm("org.richfaces.cdk", Thread.currentThread().getContextClassLoader());

        //create another realm for the app jars
        ClassRealm childRealm = realm.createChildRealm("jar");

        for (Artifact jar : artifacts) {
            try {
                childRealm.addConstituent(jar.getFile().toURL());
            } catch (MalformedURLException e) {
                getLog().error("Artifact url " + jar.getFile() + " is invalid");
            }
        }

        // add project classes, scripts, styles etc ...
        List<Resource> compileClasspathElements = project.getCompileClasspathElements();
        addResources(childRealm, compileClasspathElements);

        List<Resource> scripts = project.getScriptSourceRoots();
        addResources(childRealm, scripts);

        List<Resource> resources = project.getResources();
        addResources(childRealm, resources);

        childRealm.addConstituent(webSourceDirectory.toURI().toURL());

        //make the child realm the ContextClassLoader
        classLoader = childRealm.getClassLoader();
        return classLoader;
    }

    private void addResources(ClassRealm realm, List resources) {

        if (realm != null && resources != null) {

            for (Object path : resources) {
                URL url = null;
                String formatted = null;

                if (path instanceof String) {
                    formatted = (String) path;
                } else if (path instanceof Resource) {
                    formatted = ((Resource) path).getDirectory();
                }

                if (formatted != null) {
                    File file = new File(formatted);

                    try {
                        url = file.toURI().toURL();
                    } catch (MalformedURLException e) {
                        getLog().error("Resource url " + file.getPath() + " is invalid");
                    }

                    realm.addConstituent(url);
                }
            }

        }

    }

}