de.lightful.maven.plugins.drools.impl.dependencies.DependencyLoader.java Source code

Java tutorial

Introduction

Here is the source code for de.lightful.maven.plugins.drools.impl.dependencies.DependencyLoader.java

Source

/*******************************************************************************
 * Copyright (c) 2009-2012 Ansgar Konermann
 *
 * This file is part of the "Maven 3 Drools Support" Package.
 *
 * 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 de.lightful.maven.plugins.drools.impl.dependencies;

import de.lightful.maven.plugins.drools.impl.WellKnownNames;
import de.lightful.maven.plugins.drools.knowledgeio.KnowledgeIoFactory;
import de.lightful.maven.plugins.drools.knowledgeio.KnowledgeModuleReader;
import de.lightful.maven.plugins.drools.knowledgeio.LogStream;
import de.lightful.maven.plugins.drools.knowledgeio.metadata.KnowledgePackageFormatter;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseConfiguration;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderConfiguration;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.definition.KnowledgePackage;
import org.fest.util.Arrays;
import org.sonatype.aether.RepositoryException;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.collection.CollectRequest;
import org.sonatype.aether.collection.CollectResult;
import org.sonatype.aether.collection.DependencyCollectionException;
import org.sonatype.aether.graph.Dependency;
import org.sonatype.aether.graph.DependencyFilter;
import org.sonatype.aether.graph.DependencyNode;
import org.sonatype.aether.repository.RemoteRepository;
import org.sonatype.aether.resolution.ArtifactRequest;
import org.sonatype.aether.resolution.ArtifactResult;
import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.util.filter.AndDependencyFilter;
import org.sonatype.aether.util.graph.FilteringDependencyVisitor;
import org.sonatype.aether.util.graph.PostorderNodeListGenerator;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

public class DependencyLoader {

    public static final String EMPTY_CLASSIFIER = "";
    private LogStream<?> debug;
    private LogStream<?> info;
    private LogStream<?> warn;
    private LogStream<?> error;

    private ArtifactHandlerManager artifactHandlerManager;
    private RepositorySystem repositorySystem;

    public KnowledgeBuilder createKnowledgeBuilderForRuleCompilation(MavenProject project,
            RepositorySystemSession session, List<RemoteRepository> repositories) throws MojoFailureException {
        try {
            final CollectResult collectResult = collectAllDependencies(project, session, repositories);
            final List<Artifact> knowledgeModulesInLoadOrder = resolveKnowledgeModuleArtifacts(collectResult,
                    session, repositories);
            final List<Artifact> jarArtifactsInLoadOrder = resolveJarArtifacts(collectResult, session,
                    repositories);

            URLClassLoader classLoader = createCompileClassLoader(jarArtifactsInLoadOrder);
            info.nl().nl().write("Using class loader with these URLs:").nl();
            int i = 1;
            for (URL url : classLoader.getURLs()) {
                info.write("    #" + i++ + ": ").write(url.toString()).nl();
            }
            KnowledgeBuilderConfiguration configuration = KnowledgeBuilderFactory
                    .newKnowledgeBuilderConfiguration(new Properties(), classLoader);
            KnowledgeBase existingKnowledge = createKnowledgeBaseFromDependencies(classLoader,
                    knowledgeModulesInLoadOrder);
            return KnowledgeBuilderFactory.newKnowledgeBuilder(existingKnowledge, configuration);
        } catch (DependencyResolutionRequiredException e) {
            throw new MojoFailureException(
                    "Internal error: declared resolution of compile-scoped dependencies, but got exception!", e);
        } catch (MalformedURLException e) {
            throw new MojoFailureException("Got malformed URL for compile classpath element.", e);
        } catch (IOException e) {
            throw new MojoFailureException("Error while creating drools KnowledgeBuilder.", e);
        } catch (RepositoryException e) {
            throw new MojoFailureException("Repository backend failed.", e);
        }
    }

    private List<Artifact> resolveJarArtifacts(CollectResult collectResult, RepositorySystemSession session,
            List<RemoteRepository> repositories) throws RepositoryException {
        final List<DependencyNode> droolsDependencies = getJavaDependencies(collectResult.getRequest().getRoot(),
                collectResult);
        return resolveArtifacts(droolsDependencies, session, repositories);
    }

    private List<Artifact> resolveKnowledgeModuleArtifacts(CollectResult collectResult,
            RepositorySystemSession session, List<RemoteRepository> repositories) throws RepositoryException {
        final List<DependencyNode> droolsDependencies = getDroolsDependencies(collectResult.getRequest().getRoot(),
                collectResult);
        return resolveArtifacts(droolsDependencies, session, repositories);
    }

    private List<Artifact> resolveArtifacts(List<DependencyNode> dependencyNodes,
            RepositorySystemSession repositorySession, List<RemoteRepository> remoteProjectRepositories)
            throws RepositoryException {
        List<Artifact> artifacts = new ArrayList<Artifact>(dependencyNodes.size());
        for (DependencyNode dependencyNode : dependencyNodes) {
            ArtifactRequest request = new ArtifactRequest();
            request.setDependencyNode(dependencyNode);
            request.setRepositories(remoteProjectRepositories);
            final ArtifactResult artifactResult = repositorySystem.resolveArtifact(repositorySession, request);
            artifacts.add(artifactResult.getArtifact());
        }
        return artifacts;
    }

    private CollectResult collectAllDependencies(MavenProject mavenProject,
            RepositorySystemSession repositorySession, List<RemoteRepository> remoteProjectRepositories)
            throws MojoFailureException {
        CollectRequest collectRequest = new CollectRequest();
        collectRequest.setRoot(createDependencyFrom(mavenProject));
        collectRequest.setRepositories(remoteProjectRepositories);

        CollectResult collectResult;
        try {
            collectResult = repositorySystem.collectDependencies(repositorySession, collectRequest);
            dumpDependencyTree(collectResult);
        } catch (DependencyCollectionException e) {
            throw new MojoFailureException("Unable to collect dependencies", e);
        }
        return collectResult;
    }

    private List<DependencyNode> getJavaDependencies(Dependency rootDependency, CollectResult collectResult) {
        return getDependenciesInPostorder(collectResult, createFilterForJarDependencies(rootDependency));
    }

    private DependencyFilter createFilterForJarDependencies(Dependency rootDependency) {
        DependencyFilter excludeRootNode = new FilterRootNode(rootDependency);
        DependencyFilter acceptOnlyDroolsModules = new AcceptOnlyJars(artifactHandlerManager);
        return new AndDependencyFilter(excludeRootNode, acceptOnlyDroolsModules);
    }

    private List<DependencyNode> getDroolsDependencies(Dependency rootDependency, CollectResult collectResult) {
        return getDependenciesInPostorder(collectResult, createFilterForDroolsDependencies(rootDependency));
    }

    private List<DependencyNode> getDependenciesInPostorder(CollectResult collectResult,
            DependencyFilter filterForDroolsDependencies) {
        PostorderNodeListGenerator nodeListGenerator = new PostorderNodeListGenerator();
        FilteringDependencyVisitor filterForDroolsNodes = new FilteringDependencyVisitor(nodeListGenerator,
                filterForDroolsDependencies);
        DependencyNode rootNode = collectResult.getRoot();
        rootNode.accept(filterForDroolsNodes);
        return nodeListGenerator.getNodes();
    }

    private AndDependencyFilter createFilterForDroolsDependencies(Dependency rootDependency) {
        DependencyFilter excludeRootNode = new FilterRootNode(rootDependency);
        DependencyFilter acceptOnlyDroolsModules = new AcceptOnlyDroolsModules(artifactHandlerManager);
        return new AndDependencyFilter(excludeRootNode, acceptOnlyDroolsModules);
    }

    private KnowledgeBase createKnowledgeBaseFromDependencies(URLClassLoader classLoader,
            List<Artifact> knowledgeModules) throws MojoFailureException {
        final KnowledgeBaseConfiguration configuration = KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null,
                classLoader);
        final KnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase(configuration);

        for (Artifact knowledgeModule : knowledgeModules) {
            addKnowledgeModule(knowledgeBase, knowledgeModule, classLoader);
        }

        return knowledgeBase;
    }

    private Dependency createDependencyFrom(MavenProject project) {
        final String artifactType = project.getPackaging();
        org.sonatype.aether.artifact.Artifact artifact = new DefaultArtifact(project.getGroupId(),
                project.getArtifactId(), EMPTY_CLASSIFIER, fileExtensionOf(artifactType), project.getVersion());
        return new Dependency(artifact, WellKnownNames.SCOPE_COMPILE);
    }

    private String fileExtensionOf(String artifactType) {
        return artifactHandlerManager.getArtifactHandler(artifactType).getExtension();
    }

    private void dumpDependencyTree(CollectResult collectResult) {
        info.write("Resolved dependencies of " + collectResult.getRoot().toString() + ".").nl();
    }

    private void addKnowledgeModule(KnowledgeBase knowledgeBase, Artifact compileArtifact,
            URLClassLoader classLoader) throws MojoFailureException {
        final Collection<KnowledgePackage> knowledgePackages = loadKnowledgePackages(compileArtifact, classLoader);
        knowledgeBase.addKnowledgePackages(knowledgePackages);
        info.write("Loaded drools dependency " + coordinatesOf(compileArtifact)).nl();
        info.write("  Contains packages:").nl();
        KnowledgePackageFormatter.dumpKnowledgePackages(info, knowledgePackages);
    }

    private Collection<KnowledgePackage> loadKnowledgePackages(Artifact compileArtifact, URLClassLoader classLoader)
            throws MojoFailureException {
        final KnowledgeIoFactory factory = new KnowledgeIoFactory();
        final Collection<KnowledgePackage> knowledgePackages;
        try {
            final KnowledgeModuleReader reader = factory
                    .createKnowledgeModuleReader(new FileInputStream(compileArtifact.getFile()), classLoader);
            knowledgePackages = reader.readKnowledgePackages();
        } catch (IOException e) {
            throw new MojoFailureException(
                    "Unable to load compile-scoped dependency " + coordinatesOf(compileArtifact), e);
        } catch (ClassNotFoundException e) {
            throw new MojoFailureException(
                    "Unable to load compile-scoped dependency " + coordinatesOf(compileArtifact), e);
        }
        return knowledgePackages;
    }

    private String coordinatesOf(Artifact artifact) {
        return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getExtension() + ":"
                + artifact.getVersion();
    }

    private URLClassLoader createCompileClassLoader(List<Artifact> artifacts)
            throws DependencyResolutionRequiredException, IOException {

        ArrayList<URL> classpathUrls = new ArrayList<URL>();
        for (Artifact artifact : artifacts) {
            URL classpathElementUrl = artifact.getFile().toURI().toURL();
            classpathUrls.add(classpathElementUrl);
        }
        final URL[] urls = classpathUrls.toArray(new URL[classpathUrls.size()]);
        debug.write("Passing URLs to new URLClassLoader instance: ").write(Arrays.format(urls)).nl();
        URLClassLoader classLoader = new URLClassLoader(urls) {
            private ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
            private ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                debug.write("Loading class '" + name + "'").nl();

                try {
                    final Class<?> loadedClass = super.loadClass(name);
                    debug.write("    loaded class [" + loadedClass + "] from JAR dependencies.").nl();
                    return loadedClass;
                } catch (ClassNotFoundException oe) {
                    if (name.startsWith("org.drools")) {
                        final Class<?> loadedClass = contextClassLoader.loadClass(name);
                        debug.write("    loaded class [" + loadedClass + "] from contextClassLoader (Plugin).")
                                .nl();
                        return loadedClass;
                    } else {
                        final Class<?> loadedClass = systemClassLoader.loadClass(name);
                        debug.write("    loaded class [" + loadedClass + "] from systemClassLoader ("
                                + systemClassLoader.toString() + ")").nl();
                        return loadedClass;
                    }
                }
            }

            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                debug.write("Finding class '" + name + "'").nl();
                final Class<?> foundClass = super.findClass(name);
                debug.write("Finding class '" + name + "': found class [" + foundClass + "]").nl();
                return foundClass;
            }
        };

        debug.write("Adding classpath URLs to classloader:").nl();
        for (URL classpathUrl : classpathUrls) {
            debug.write("   | " + classpathUrl).nl();
        }
        debug.write("   #").nl();
        return classLoader;
    }

    private void dumpArtifactInfo(int i, Artifact artifact) {
        debug.write("Dependency Artifact #" + i + ": GroupId=" + artifact.getGroupId()).nl();
        debug.write("Dependency Artifact #" + i + ": ArtifactId=" + artifact.getArtifactId()).nl();
        debug.write("Dependency Artifact #" + i + ": Type=" + artifact.getExtension()).nl();
        debug.write("Dependency Artifact #" + i + ": Classifier=" + artifact.getClassifier()).nl();
        debug.write("Dependency Artifact #" + i + ": BaseVersion=" + artifact.getBaseVersion()).nl();
        debug.write("Dependency Artifact #" + i + ": Version=" + artifact.getVersion()).nl();
        final File artifactFile = artifact.getFile();
        if (artifactFile != null) {
            debug.write("Dependency Artifact #" + i + ": File=" + artifactFile.getAbsolutePath()).nl();
        } else {
            debug.write("Dependency Artifact #" + i + ": File={null}").nl();
        }
    }

    private static class FilterRootNode implements DependencyFilter {

        private final Dependency rootDependency;

        public FilterRootNode(Dependency rootDependency) {
            this.rootDependency = rootDependency;
        }

        public boolean accept(DependencyNode node, List<DependencyNode> parents) {
            return node.getDependency() != rootDependency;
        }
    }

    private static class AcceptOnlyDroolsModules implements DependencyFilter {

        private ArtifactHandlerManager artifactHandlerManager;

        public AcceptOnlyDroolsModules(ArtifactHandlerManager artifactHandlerManager) {
            this.artifactHandlerManager = artifactHandlerManager;
        }

        public boolean accept(DependencyNode node, List<DependencyNode> parents) {
            final ArtifactHandler artifactHandler = artifactHandlerManager
                    .getArtifactHandler(WellKnownNames.ARTIFACT_TYPE_DROOLS_KNOWLEDGE_MODULE);
            final String knowledgeModuleExtension = artifactHandler.getExtension();
            return node.getDependency().getArtifact().getExtension().equals(knowledgeModuleExtension);
        }
    }

    private class AcceptOnlyJars implements DependencyFilter {

        private ArtifactHandlerManager artifactHandlerManager;

        public AcceptOnlyJars(ArtifactHandlerManager artifactHandlerManager) {
            this.artifactHandlerManager = artifactHandlerManager;
        }

        public boolean accept(DependencyNode node, List<DependencyNode> parents) {
            final ArtifactHandler artifactHandler = artifactHandlerManager
                    .getArtifactHandler(WellKnownNames.ARTIFACT_TYPE_JAR);
            final String jarFileExtension = artifactHandler.getExtension();
            return node.getDependency().getArtifact().getExtension().equals(jarFileExtension);
        }
    }
}