org.trianacode.taskgraph.util.ExtensionFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.trianacode.taskgraph.util.ExtensionFinder.java

Source

/*
 * Copyright 2004 - 2009 University of Cardiff.
 *
 * 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 org.trianacode.taskgraph.util;

import org.apache.commons.logging.Log;
import org.trianacode.config.ModuleClassLoader;
import org.trianacode.enactment.logging.Loggers;
import org.trianacode.taskgraph.tool.ClassLoaders;
import org.trianacode.taskgraph.tool.ToolClassLoader;

import java.io.*;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

/**
 * Implements 1.3 ServiceProvider discovery mechanism. Adds the Java classpath as a search path by default. Other paths
 * can be added. TODO - make this cache entries for a one time hit?
 *
 * @author Andrew Harrison
 * @version $Revision:$
 */

public class ExtensionFinder {

    static Log log = Loggers.CONFIG_LOGGER;

    private static void loadPaths(List<File> searchDirs) {
        String jarPath = ExtensionFinder.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        try {
            String decodedPath = URLDecoder.decode(jarPath, "UTF-8");
            //            System.out.println("This class = " + decodedPath);
            File file = new File(decodedPath);
            if (decodedPath.endsWith(".jar") && file.exists()) {
                searchDirs.add(new File(decodedPath));
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        String cp = System.getProperty("java.class.path");
        String sep = System.getProperty("path.separator");
        if (cp != null && cp.length() > 0) {
            String[] paths = cp.split(sep);
            for (String path : paths) {
                if (path.trim().length() > 0) {
                    File f = new File(path);
                    if (f.exists()) {
                        log.debug("adding search path:" + f.getAbsolutePath());
                        searchDirs.add(f);
                    }
                }
            }
        }
        List<ModuleClassLoader> mod = ClassLoaders.getModuleClassLoaders();

        for (ModuleClassLoader moduleClassLoader : mod) {
            List<String> paths = moduleClassLoader.getClassPathList();
            for (String path : paths) {
                if (path.trim().length() > 0) {
                    File f = new File(path);
                    if (f.exists()) {
                        log.debug("adding search path:" + f.getAbsolutePath());
                        searchDirs.add(f);
                    }
                }
            }
        }
        List<ToolClassLoader> tools = ClassLoaders.getToolClassLoaders();
        for (ToolClassLoader toolLoader : tools) {
            List<String> paths = toolLoader.getClassPathList();
            for (String path : paths) {
                if (path.trim().length() > 0) {
                    File f = new File(path);
                    if (f.exists()) {
                        log.debug("adding search path:" + f.getAbsolutePath());
                        searchDirs.add(f);
                    }
                }
            }
        }
        //        System.out.println("Paths : " + Arrays.toString(searchDirs.toArray()));
    }

    public static Map<Class, Set<Object>> services(List<Class> providers) {
        List<File> searchDirs = new ArrayList<File>();
        loadPaths(searchDirs);
        Map<Class, Set<Object>> ret = new HashMap<Class, Set<Object>>();
        for (File searchDir : searchDirs) {
            Map<Class, Set<Object>> map = getProviders(providers, searchDir);
            for (Class aClass : map.keySet()) {
                Set<Object> objs = ret.get(aClass);
                if (objs == null) {
                    ret.put(aClass, map.get(aClass));
                } else {
                    objs.addAll(map.get(aClass));
                    ret.put(aClass, objs);
                }
            }
        }

        //debug
        //        for( Class thing : ret.keySet()){
        //            System.out.println(thing.getCanonicalName());
        //            for(Object subthing : ret.get(thing)){
        //                System.out.println("   >> " + subthing.getClass().getCanonicalName());
        //            }
        //        }

        return ret;
    }

    public static Set<Object> services(Class provider) {
        List provs = new ArrayList<Class>();
        provs.add(provider);
        Map<Class, Set<Object>> ret = services(provs);
        if (ret != null && ret.get(provider) != null) {
            return ret.get(provider);
        }
        return new HashSet<Object>();
    }

    public static Map<Class, Set<Object>> getProviders(List<Class> providers, File file) {
        log.debug("searching for providers:" + file.getAbsolutePath());
        //        System.out.println("*** Looking for extensions in : " + file.getAbsolutePath());
        Map<Class, Set<Object>> ret = new HashMap<Class, Set<Object>>();
        if (file.isDirectory()) {
            File meta = new File(file, "META-INF");
            if (meta.exists()) {
                File services = new File(meta, "services");
                if (services.exists()) {
                    for (Class provider : providers) {
                        File prov = new File(services, provider.getName());
                        if (prov.exists()) {

                            List<Object> impls = null;
                            try {
                                BufferedReader reader = new BufferedReader(
                                        new InputStreamReader(new FileInputStream(prov)));
                                String line;
                                impls = new ArrayList<Object>();
                                List<String> done = new ArrayList<String>();
                                while ((line = reader.readLine()) != null) {
                                    log.debug("got next service provider:" + line);
                                    log.debug("*** Found : " + line);
                                    try {
                                        if (!done.contains(line)) {
                                            Class cls = ClassLoaders.forName(line);
                                            if (provider.isAssignableFrom(cls)) {
                                                Object p = cls.newInstance();
                                                impls.add(p);
                                            }
                                            done.add(line);
                                        }
                                    } catch (Exception e1) {
                                        log.debug("Exception thrown trying to load service provider class " + line
                                                + ":" + FileUtils.formatThrowable(e1));
                                    }
                                }
                            } catch (IOException e) {
                                log.debug("error thrown while reading file:" + e.getMessage());
                            }
                            if (impls.size() > 0) {
                                Set<Object> exist = ret.get(provider);
                                if (exist == null) {
                                    exist = new HashSet<Object>();
                                }
                                exist.addAll(impls);
                                ret.put(provider, exist);
                            }
                        }
                    }
                }
            }
            File[] children = file.listFiles(new FilenameFilter() {
                public boolean accept(File file, String s) {
                    if (s.endsWith(".jar")) {
                        return true;
                    }
                    return false;
                }
            });
            if (children != null) {
                for (File child : children) {
                    Map<Class, Set<Object>> map = getProviders(providers, child);
                    for (Class aClass : map.keySet()) {
                        Set<Object> objs = ret.get(aClass);
                        if (objs == null) {
                            ret.put(aClass, map.get(aClass));
                        } else {
                            objs.addAll(map.get(aClass));
                            ret.put(aClass, objs);
                        }
                    }
                }
            }
        } else {
            if (file.getName().endsWith(".jar")) {
                try {
                    JarFile jf = new JarFile(file);
                    ZipEntry entry = jf.getEntry("META-INF/services/");
                    if (entry != null) {
                        for (Class provider : providers) {
                            ZipEntry e = jf.getEntry("META-INF/services/" + provider.getName());
                            if (e != null) {
                                InputStream zin = jf.getInputStream(e);
                                BufferedReader reader = new BufferedReader(new InputStreamReader(zin));
                                String line;
                                List<Object> impls = new ArrayList<Object>();
                                List<String> done = new ArrayList<String>();
                                while ((line = reader.readLine()) != null) {
                                    log.debug("got next service provider:" + line);
                                    // check if the class is in this jar
                                    ZipEntry sp = jf.getEntry(line.replace(".", "/") + ".class");
                                    if (sp != null) {
                                        try {
                                            if (!done.contains(line)) {
                                                Class cls = ClassLoaders.forName(line);
                                                if (provider.isAssignableFrom(cls)) {
                                                    Object prov = cls.newInstance();
                                                    impls.add(prov);
                                                }
                                                done.add(line);
                                            }
                                        } catch (Exception e1) {
                                            e1.printStackTrace();
                                            log.debug("Exception thrown trying to load service provider class "
                                                    + line, e1);
                                        }
                                    }
                                }
                                if (impls.size() > 0) {
                                    Set<Object> exist = ret.get(provider);
                                    if (exist == null) {
                                        exist = new HashSet<Object>();
                                    }
                                    exist.addAll(impls);
                                    ret.put(provider, exist);
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    log.debug("Exception thrown trying to load service providers from file " + file, e);
                }
            }

        }
        return ret;
    }

}