hermes.impl.LoaderSupport.java Source code

Java tutorial

Introduction

Here is the source code for hermes.impl.LoaderSupport.java

Source

/* 
 * Copyright 2003,2004 Colin Crist
 *
 * 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 hermes.impl;

import hermes.browser.HermesBrowser;
import hermes.config.ClasspathConfig;
import hermes.config.PropertyConfig;
import hermes.config.PropertySetConfig;
import hermes.util.TextUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import javax.jms.ConnectionFactory;
import javax.swing.ProgressMonitor;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;

/**
 * Helper for mucking about with ClassLoaders
 * 
 * @author colincrist@hermesjms.com
 * @version $Id: LoaderSupport.java,v 1.29 2006/07/13 07:35:31 colincrist Exp $
 */
public class LoaderSupport {
    private static final Logger log = Logger.getLogger(LoaderSupport.class);

    public static class DebugClassLoader extends URLClassLoader {
        /**
         * @param arg0
         */
        public DebugClassLoader(URL[] arg0) {
            super(arg0);
        }

        /**
         * @param arg0
         * @param arg1
         */
        public DebugClassLoader(URL[] arg0, ClassLoader arg1) {
            super(arg0, arg1);
        }

        /**
         * @param arg0
         * @param arg1
         * @param arg2
         */
        public DebugClassLoader(URL[] arg0, ClassLoader arg1, URLStreamHandlerFactory arg2) {
            super(arg0, arg1, arg2);
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
         */
        protected synchronized Class loadClass(String arg0, boolean arg1) throws ClassNotFoundException {
            if (arg0.startsWith("hermes.ext")) {
                log.debug("loadClass(" + arg0 + ", " + arg1 + ") from " + toString());
            }

            return super.loadClass(arg0, arg1);
        }

        public String toString() {
            StringBuffer rval = new StringBuffer();

            rval.append("DebugClassLoader: ");

            for (int i = 0; i < getURLs().length; i++) {
                URL url = getURLs()[i];

                rval.append(url.toString());

                if (i != getURLs().length - 1) {
                    rval.append(", ");
                }
            }

            if (getParent() instanceof DebugClassLoader) {
                rval.append(", parent=" + getParent().toString());
            }

            return rval.toString();
        }

        protected Class findClass(String name) throws ClassNotFoundException {
            return super.findClass(name);
        }
    }

    /**
     * Return ClassLoader given the list of ClasspathConfig instances. The
     * resulting loader can then be used to instantiate providers from those
     * libraries.
     */
    static ClassLoader createClassLoader(List loaderConfigs, URL[] extraUrls, ClassLoader classLoader)
            throws IOException {
        int index = 0;
        int size = loaderConfigs.size();

        if (extraUrls != null) {
            size += extraUrls.length;
        }

        URL[] urls = new URL[size];
        StringBuffer debug = new StringBuffer("URLClassLoader: ");

        for (Iterator iter = loaderConfigs.iterator(); iter.hasNext();) {
            ClasspathConfig lConfig = (ClasspathConfig) iter.next();

            URL url = null;

            if (lConfig.getJar().startsWith("http")) {
                url = new URL(TextUtils.replaceClasspathVariables(lConfig.getJar()));
            } else {
                url = new File(TextUtils.replaceClasspathVariables(lConfig.getJar())).toURL();

            }

            urls[index++] = url;

            debug.append(url.toString());

            if (iter.hasNext()) {
                debug.append(", ");
            }
        }

        if (extraUrls != null) {
            for (int i = 0; i < extraUrls.length; i++) {
                urls[index++] = extraUrls[i];
                debug.append(", " + extraUrls[i].toString());
            }
        }

        log.debug(debug.toString());

        return new DebugClassLoader(urls, classLoader);
    }

    static ClassLoader createClassLoader(List loaderConfigs, ClassLoader classLoader) throws IOException {
        return createClassLoader(loaderConfigs, null, classLoader);

    }

    /**
     * Return ClassLoader given the list of ClasspathConfig instances. The
     * resulting loader can then be used to instantiate providers from those
     * libraries.
     */
    static List lookForFactories(final List loaderConfigs, final ClassLoader baseLoader) throws IOException {
        final List rval = new ArrayList();

        for (Iterator iter = loaderConfigs.iterator(); iter.hasNext();) {
            final ClasspathConfig lConfig = (ClasspathConfig) iter.next();

            if (lConfig.getFactories() != null) {
                log.debug("using cached " + lConfig.getFactories());

                for (StringTokenizer tokens = new StringTokenizer(lConfig.getFactories(), ","); tokens
                        .hasMoreTokens();) {
                    rval.add(tokens.nextToken());
                }
            } else if (lConfig.isNoFactories()) {
                log.debug("previously scanned " + lConfig.getJar());
            } else {
                Runnable r = new Runnable() {
                    public void run() {
                        final List localFactories = new ArrayList();
                        boolean foundFactory = false;
                        StringBuffer factoriesAsString = null;

                        try {
                            log.debug("searching " + lConfig.getJar());

                            ClassLoader l = createClassLoader(loaderConfigs, baseLoader);
                            JarFile jarFile = new JarFile(lConfig.getJar());
                            ProgressMonitor monitor = null;
                            int entryNumber = 0;

                            if (HermesBrowser.getBrowser() != null) {
                                monitor = new ProgressMonitor(HermesBrowser.getBrowser(),
                                        "Looking for factories in " + lConfig.getJar(), "Scanning...", 0,
                                        jarFile.size());
                                monitor.setMillisToDecideToPopup(0);
                                monitor.setMillisToPopup(0);
                                monitor.setProgress(0);
                            }

                            for (Enumeration iter = jarFile.entries(); iter.hasMoreElements();) {
                                ZipEntry entry = (ZipEntry) iter.nextElement();
                                entryNumber++;

                                if (monitor != null) {
                                    monitor.setProgress(entryNumber);
                                    monitor.setNote("Checking entry " + entryNumber + " of " + jarFile.size());
                                }

                                if (entry.getName().endsWith(".class")) {
                                    String s = entry.getName().substring(0, entry.getName().indexOf(".class"));

                                    s = s.replaceAll("/", ".");

                                    try {
                                        if (s.startsWith("hermes.browser") || s.startsWith("hermes.impl")
                                                || s.startsWith("javax.jms")) {
                                            // NOP
                                        } else {
                                            Class clazz = l.loadClass(s);

                                            if (!clazz.isInterface()) {

                                                if (implementsOrExtends(clazz, ConnectionFactory.class)) {

                                                    foundFactory = true;
                                                    localFactories.add(s);

                                                    if (factoriesAsString == null) {
                                                        factoriesAsString = new StringBuffer();
                                                        factoriesAsString.append(clazz.getName());
                                                    } else {
                                                        factoriesAsString.append(",").append(clazz.getName());
                                                    }
                                                    log.debug("found " + clazz.getName());
                                                }
                                            }

                                            /**
                                             * TODO: remove Class clazz = l.loadClass(s);
                                             * Class[] interfaces = clazz.getInterfaces();
                                             * for (int i = 0; i < interfaces.length; i++) {
                                             * if
                                             * (interfaces[i].equals(TopicConnectionFactory.class) ||
                                             * interfaces[i].equals(QueueConnectionFactory.class) ||
                                             * interfaces[i].equals(ConnectionFactory.class)) {
                                             * foundFactory = true; localFactories.add(s);
                                             * if (factoriesAsString == null) {
                                             * factoriesAsString = new
                                             * StringBuffer(clazz.getName()); } else {
                                             * factoriesAsString.append(",").append(clazz.getName()); }
                                             * log.debug("found " + clazz.getName()); } }
                                             */
                                        }
                                    } catch (Throwable t) {
                                        // NOP
                                    }
                                }
                            }
                        } catch (IOException e) {
                            log.error("unable to access jar/zip " + lConfig.getJar() + ": " + e.getMessage(), e);
                        }

                        if (!foundFactory) {
                            lConfig.setNoFactories(true);
                        } else {
                            lConfig.setFactories(factoriesAsString.toString());
                            rval.addAll(localFactories);
                        }

                    }
                };

                r.run();

            }
        }

        return rval;
    }

    /**
     * Indicates if a class or interface implements or extends the specified
     * interfaces or classes. If the specified <CODE>Class</CODE> is a class,
     * this method will recursively test if this class, its superclass or one of
     * the implemented interfaces of this class implements the specified
     * interface.<BR>
     * If the specified <CODE>Class</CODE> is an interface, this method will
     * recursively test if this interface or one of the implemented interfaces of
     * this interface implements the specified interface.<BR>
     * 
     * @param clazz
     *           the class or interface in question
     * @param testInterface
     *           the class or interface to test against
     * @return <CODE>true</CODE> if the specified interfaces is implemented by
     *         this class or one of its super-classes or interfaces
     */
    public static boolean implementsOrExtends(Class clazz, Class testInterface) {
        Class[] implementedInterfaces = clazz.getInterfaces();

        // test interface
        if (clazz.equals(testInterface)) {
            return true; // possibly the end of the recursion
        }

        for (int i = 0; i < implementedInterfaces.length; i++) {
            if (implementsOrExtends(implementedInterfaces[i], testInterface)) {
                return true; // recursion
            }
        }

        // maybe the superclass implements this interface ?
        Class superClass = clazz.getSuperclass();
        if (superClass != null && implementsOrExtends(superClass, testInterface)) {
            return true; // recursion
        }

        return false;
    }

    public static void populateBean(Object bean, PropertySetConfig propertySet)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException {
        if (propertySet != null) {
            Set appliedProperties = new HashSet();

            for (Iterator iter = propertySet.getProperty().iterator(); iter.hasNext();) {
                PropertyConfig propertyConfig = (PropertyConfig) iter.next();

                if (appliedProperties.contains(propertyConfig.getName())) {
                    iter.remove();
                } else {
                    try {

                        BeanUtils.setProperty(bean, propertyConfig.getName(),
                                TextUtils.replaceClasspathVariables(propertyConfig.getValue()));

                        appliedProperties.add(propertyConfig.getName());

                        log.debug("set " + bean.getClass().getName() + " " + propertyConfig.getName() + "="
                                + TextUtils.replaceClasspathVariables(propertyConfig.getValue()));
                    } catch (InvocationTargetException t) {
                        log.error(
                                "unable to set property name=" + propertyConfig.getName() + " value="
                                        + propertyConfig.getValue() + " on object of class "
                                        + bean.getClass().getName() + ": " + t.getCause().getMessage(),
                                t.getCause());
                    }
                }
            }
        }
    }
}