001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2005-2005 Julian Hyde
008// Copyright (C) 2005-2012 Pentaho
009// All Rights Reserved.
010*/
011package mondrian.util;
012
013import org.apache.commons.collections.iterators.EnumerationIterator;
014
015import java.io.IOException;
016import java.lang.reflect.*;
017import java.net.URL;
018import java.util.*;
019
020/**
021 * Instantiates a class.
022 *
023 * <p>Has same effect as calling {@link Class#forName(String)},  but uses the
024 * appropriate {@link ClassLoader}.</p>
025 */
026public interface ClassResolver {
027
028    /** Equivalent of {@link Class#forName(String, boolean, ClassLoader)}. */
029    <T> Class<T> forName(String className, boolean initialize)
030        throws ClassNotFoundException;
031
032    /**
033     * Instantiates a class and constructs an instance using the given
034     * arguments.
035     *
036     * @param className Class name
037     * @param args Arguments
038     * @param <T> Desired type
039     * @throws ClassCastException if resulting object is not an instance of T
040     */
041    <T> T instantiateSafe(String className, Object... args);
042
043    /** Equivalent of {@link ClassLoader#getResources(String)}. */
044    Iterable<URL> getResources(String lookupName) throws IOException;
045
046    /** Default resolver. */
047    ClassResolver INSTANCE = new ThreadContextClassResolver();
048
049    /** Implementation of {@link ClassResolver} that calls
050     * {@link Thread#getContextClassLoader()} on the current thread. */
051    class ThreadContextClassResolver extends AbstractClassResolver {
052        protected ClassLoader getClassLoader() {
053            return Thread.currentThread().getContextClassLoader();
054        }
055    }
056
057    /** Partial implementation of {@link ClassResolver}. Derived class just
058     * needs to implement {@link #getClassLoader()}. */
059    abstract class AbstractClassResolver implements ClassResolver {
060        public <T> T instantiateSafe(String className, Object... args) {
061            try {
062                final Class<T> clazz = forName(className, true);
063                if (args.length == 0) {
064                    return clazz.newInstance();
065                } else {
066                    Class[] types = new Class[args.length];
067                    for (int i = 0; i < args.length; i++) {
068                        types[i] = args[i].getClass();
069                    }
070                    final Constructor<T> constructor =
071                        clazz.getConstructor(types);
072                    return constructor.newInstance(args);
073                }
074            } catch (InstantiationException e) {
075                throw new RuntimeException(e);
076            } catch (IllegalAccessException e) {
077                throw new RuntimeException(e);
078            } catch (NoSuchMethodException e) {
079                throw new RuntimeException(e);
080            } catch (InvocationTargetException e) {
081                throw new RuntimeException(e);
082            } catch (ClassNotFoundException e) {
083                throw new RuntimeException(e);
084            }
085        }
086
087        public <T> Class<T> forName(String className, boolean initialize)
088            throws ClassNotFoundException
089        {
090            //noinspection unchecked
091            return (Class<T>) Class.forName(
092                className,
093                initialize,
094                getClassLoader());
095        }
096
097        /** Returns the class loader to use for the current operation. May be
098         * null. */
099        protected abstract ClassLoader getClassLoader();
100
101        /** Returns the class loader to use for the current operation, never
102         * null. */
103        protected ClassLoader getClassLoaderNotNull() {
104            final ClassLoader classLoader = getClassLoader();
105            return classLoader != null
106                ? classLoader
107                : getClass().getClassLoader();
108        }
109
110        public Iterable<URL> getResources(String name) throws IOException {
111            final Enumeration<URL> resources =
112                getClassLoaderNotNull().getResources(name);
113            //noinspection unchecked
114            return new IteratorIterable<URL>(
115                new EnumerationIterator(resources));
116        }
117    }
118}
119
120// End ClassResolver.java