001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2010–2011 ApexIdentity Inc.
015 * Portions Copyright 2011-2014 ForgeRock AS.
016 */
017
018package org.forgerock.openig.util;
019
020import java.net.URL;
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.ServiceLoader;
026
027/**
028 * Provides methods for dynamically loading classes.
029 */
030public final class Loader {
031
032    /** Static methods only. */
033    private Loader() {
034    }
035
036    /**
037     * Returns the class loader that should be used consistently throughout the application.
038     *
039     * @return the class loader that should be used consistently throughout the application.
040     */
041    public static ClassLoader getClassLoader() {
042        return Thread.currentThread().getContextClassLoader();
043    }
044
045    /**
046     * Returns the {@code Class} object associated with the class or interface with the given
047     * name, or {@code null} if the class could not be returned for any reason.
048     *
049     * @param name the fully qualified name of the desired class.
050     * @return the Class object for the class with the specified name.
051     */
052    public static Class<?> getClass(String name) {
053        try {
054            return Class.forName(name, true, getClassLoader());
055        } catch (Throwable t) {
056            return null;
057        }
058    }
059
060    /**
061     * Creates a new instance of a named class. The class is instantiated as if by a
062     * {@code new} expression with an empty argument list. If the class cannot be instantiated
063     * for any reason, {@code null} is returned.
064     *
065     * @param name the fully qualified name of the class to instantiate.
066     * @return the newly instantiated object, or {@code null} if it could not be instantiated.
067     */
068    public static Object newInstance(String name) {
069        try {
070            return getClass(name).newInstance();
071        } catch (Throwable t) {
072            return null;
073        }
074    }
075
076    /**
077     * Creates a new instance of a named class. The class is instantiated as if by a
078     * {@code new} expression with an empty argument list. If the class cannot be instantiated
079     * for any reason, {@code null} is returned.
080     *
081     * @param name the fully qualified name of the class to instantiate.
082     * @param type the class of the type of object to instantiate.
083     * @param <T> class type
084     * @return the newly instantiated object, or {@code null} if it could not be instantiated.
085     */
086    @SuppressWarnings("unchecked")
087    public static <T> T newInstance(String name, Class<T> type) {
088        Object object = newInstance(name);
089        if (object != null && !type.isInstance(object)) {
090            object = null;
091        }
092        return (T) object;
093    }
094
095    /**
096     * Loads services of a particular type into a map. Such services implement the
097     * {@link Indexed} interface to provide a key to index the service by in the map.
098     *
099     * @param keyType the class type of the key to be indexed in the map.
100     * @param serviceType the class type of services to load.
101     * @param <K> key type
102     * @param <V> service type
103     * @return a map containing the loaded services, indexed by the services' keys.
104     */
105    public static <K, V extends Indexed<K>> Map<K, V> loadMap(Class<K> keyType, Class<V> serviceType) {
106        HashMap<K, V> map = new HashMap<K, V>();
107        for (V v : ServiceLoader.load(serviceType, getClassLoader())) {
108            map.put(v.getKey(), v);
109        }
110        return map;
111    }
112
113    /**
114     * Loads services of a particular type into a list.
115     *
116     * @param serviceType the class type of services to load.
117     * @param <E> service type
118     * @return a list containing the loaded services.
119     */
120    public static <E> List<E> loadList(Class<E> serviceType) {
121        ArrayList<E> list = new ArrayList<E>();
122        for (E e : ServiceLoader.load(serviceType, getClassLoader())) {
123            list.add(e);
124        }
125        return list;
126    }
127
128    /**
129     * Finds the resource with the given name.
130     *
131     * @param name the resource name.
132     * @return A {@code URL} object for reading the resource, or {@code null} if the resource could not be found.
133     * @see ClassLoader#getResource(java.lang.String)
134     */
135    public static URL getResource(String name) {
136        return getClassLoader().getResource(name);
137    }
138}