Package net.xeoh.plugins.base.impl.classpath.locator

Source Code of net.xeoh.plugins.base.impl.classpath.locator.ClassPathLocator

/*
* ClasspathLocator.java
*
* Copyright (c) 2009, Ralf Biedert All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the author nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package net.xeoh.plugins.base.impl.classpath.locator;

import static net.jcores.jre.CoreKeeper.$;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import net.jcores.jre.interfaces.functions.F1;
import net.xeoh.plugins.base.PluginManager;
import net.xeoh.plugins.base.diagnosis.channels.tracing.SpawnerTracer;
import net.xeoh.plugins.base.impl.PluginManagerImpl;
import net.xeoh.plugins.base.impl.classpath.cache.JARCache;
import net.xeoh.plugins.base.options.AddPluginsFromOption;
import net.xeoh.plugins.base.options.addpluginsfrom.OptionSearchAround;
import net.xeoh.plugins.base.util.PluginConfigurationUtil;
import net.xeoh.plugins.diagnosis.local.Diagnosis;
import net.xeoh.plugins.diagnosis.local.util.DiagnosisChannelUtil;

/**
* Used to find classpaths, JARs and their contents.
*
* @author Ralf Biedert
*/
public class ClassPathLocator {

    /** Cache to lookup elements */
    private final JARCache cache;

    /** Mainly used to access the config. */
    private PluginManagerImpl pluginManager;


    /**
     * @param pluginManager
     * @param cache
     */
    public ClassPathLocator(PluginManagerImpl pluginManager, JARCache cache) {
        this.pluginManager = pluginManager;
        this.cache = cache;
    }

    /**
     * Given a top level entry, finds a list of class path locations below the given
     * entry. The top level entry can either be a folder, or it can be a JAR directly.
     *
     * @param toplevel The top level URI to start from.
     * @return A list of class path locations.
     */
    public Collection<AbstractClassPathLocation> findBelow(URI toplevel) {

        final Collection<AbstractClassPathLocation> rval = new ArrayList<AbstractClassPathLocation>();
        final File startPoint = new File(toplevel);

        // First, check if the entry represents a multi-plugin (in that case we don't add
        // anything else)
        if ($(startPoint).filter(".*\\.plugin?$").get(0) != null) {
            rval.add(AbstractClassPathLocation.newClasspathLocation(this.cache, toplevel.toString(), toplevel));
            return rval;
        }

        // Check if this is a directory or a file
        if (startPoint.isDirectory()) {
            final File[] listFiles = startPoint.listFiles();

            boolean hasJARs = false;

            for (File file : listFiles) {
                if (file.getAbsolutePath().endsWith(".jar")) {
                    rval.add(AbstractClassPathLocation.newClasspathLocation(this.cache, file.toURI().toString(), file.toURI()));
                    hasJARs = true;
                }

                if ($(file).filter(".*\\.plugin?$").get(0) != null) {
                    rval.add(AbstractClassPathLocation.newClasspathLocation(this.cache, file.toURI().toString(), file.toURI()));
                    hasJARs = true;
                }
            }

            // If we have JARs, we already added them
            if (hasJARs) return rval;

            // If we have no JARs, this is probably a classpath, in this case warn that
            // the method is not recommended
            if (toplevel.toString().contains("/bin/") || toplevel.toString().contains("class")) {
                System.err.println("Adding plugins in 'raw' classpaths, such as 'bin/' or 'classes/' is not recommended. Please use classpath://* instead (the video is a bit outdated in this respect).");
            }
            rval.add(AbstractClassPathLocation.newClasspathLocation(this.cache, toplevel.toString(), toplevel));
            return rval;
        }

        // If this is directly a JAR, add this
        if (startPoint.isFile() && startPoint.getAbsolutePath().endsWith(".jar")) {
            rval.add(AbstractClassPathLocation.newClasspathLocation(this.cache, toplevel.toString(), toplevel));
            return rval;
        }

        return rval;
    }
   
   
   
    /**
     * Gets all contributing classpaths for a given class by traversing all parent-classloader.
     *
     * @since 1.1
     * @param clazz The class to get all classloaders for.
     * @return A list of all contributing classloaders.
     */
    protected List<String> allClasspathsFor(Class<?> clazz) {
        final DiagnosisChannelUtil<String> channel = new DiagnosisChannelUtil<String>(this.pluginManager.getPlugin(Diagnosis.class).channel(SpawnerTracer.class));
        final List<String> rval = $.list();

        channel.status("allclasspathsfor/start", "class", clazz.toString());
       
        // In case JSPF has been loaded from an URL class loader as well (Issue #29)
        URLClassLoader ourloader = $(clazz.getClassLoader()).cast(URLClassLoader.class).get(0);
        while (ourloader != null) {
            // Removed check for system classloader, might need its elements as well
            channel.status("allclasspathsfor/urlloader");
            rval.addAll($(ourloader.getURLs()).file().forEach(new F1<File, String>() {
                @Override
                public String f(File arg0) {
                    channel.status("allclasspathsfor/urlloader/path", "path", arg0);
                    return arg0.getAbsolutePath();
                }
            }).list());
            ourloader = $(ourloader.getParent()).cast(URLClassLoader.class).get(0);
        }
       
        channel.status("allclasspathsfor/end");
       
        return $(rval).unique().list();
    }
   

    /**
     * Finds all locations inside the current classpath.
     * @param options
     *
     * @return A list of all locations in the current classpath.
     */
    @SuppressWarnings("boxing")
    public Collection<AbstractClassPathLocation> findInCurrentClassPath(AddPluginsFromOption[] options) {
        final DiagnosisChannelUtil<String> channel = new DiagnosisChannelUtil<String>(this.pluginManager.getPlugin(Diagnosis.class).channel(SpawnerTracer.class));
       
        channel.status("findinclasspath/start");
        final Collection<AbstractClassPathLocation> rval = new ArrayList<AbstractClassPathLocation>();

        // Get our current classpath (TODO: Better get this using
        // ClassLoader.getSystemClassLoader()?)
        final boolean filter = new PluginConfigurationUtil(this.pluginManager.getPluginConfiguration()).getBoolean(PluginManager.class, "classpath.filter.default.enabled", true);
        final String blacklist[] = new PluginConfigurationUtil(this.pluginManager.getPluginConfiguration()).getString(PluginManager.class, "classpath.filter.default.pattern", "/jre/lib/;/jdk/lib/;/lib/rt.jar").split(";");
        final String pathSep = System.getProperty("path.separator");
        final String classpath = System.getProperty("java.class.path");
        final List<URL> toFilter = new ArrayList<URL>();

        // Get the starting point
        final Class<?> startPoint = $(options).get(OptionSearchAround.class, new OptionSearchAround(getClass())).getClazz();
       
        // Get all classpaths
        List<String> classpaths = $(classpath.split(pathSep)).list();
        classpaths.addAll(allClasspathsFor(startPoint));
        classpaths = $(classpaths).unique().list();

        // Check if we should filter, if yes, get topmost classloader so we know
        // what to filter out
        if (filter) {
            channel.status("findinclasspath/filter");

            ClassLoader loader = ClassLoader.getSystemClassLoader();
            while (loader != null && loader.getParent() != null)
                loader = loader.getParent();

            // Get 'blacklist' and add it to our filterlist
            if (loader != null && loader instanceof URLClassLoader) {
                URL[] urls = ((URLClassLoader) loader).getURLs();
                for (URL url : urls) {
                    channel.status("findinclasspath/filter/add", "item", url);
                    toFilter.add(url);
                }
            }
        }

        // Process all possible locations
        for (String string : classpaths) {
            if(string == null) continue;
           
            try {
                final URL url = new File(string).toURI().toURL();
               
                channel.status("findinclasspath/add", "raw", string, "url", url);

                // Check if the url was already contained
                if (toFilter.contains(url) || blacklisted(blacklist, url)) {
                    channel.status("findinclasspath/add/blacklisted", "raw", string, "url", url);
                    continue;
                }

                // And eventually add the location
                rval.add(AbstractClassPathLocation.newClasspathLocation(this.cache, "#classpath", new File(string).toURI()));
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }

        return rval;
    }

    /**
     * Checks if the given URL is blacklisted
     *
     * @param blacklist
     * @param url
     * @return
     */
    private boolean blacklisted(String[] blacklist, URL url) {
        // Default sanity check
        if (blacklist == null || blacklist.length == 0 || blacklist[0].length() == 0)
            return false;

        // Go thorugh blacklist
        for (String string : blacklist) {
            if (url.toString().contains(string)) return true;
        }

        return false;
    }
}
TOP

Related Classes of net.xeoh.plugins.base.impl.classpath.locator.ClassPathLocator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.