001/*
002 The Injector class is responsible for loading implementation based on a
003 interface.
004
005 Copyright (c) 2011-2018 The Regents of the University of California.
006 All rights reserved.
007 Permission is hereby granted, without written agreement and without
008 license or royalty fees, to use, copy, modify, and distribute this
009 software and its documentation for any purpose, provided that the above
010 copyright notice and the following two paragraphs appear in all copies
011 of this software.
012
013 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
014 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
015 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
016 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
017 SUCH DAMAGE.
018
019 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
020 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
021 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
022 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
023 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
024 ENHANCEMENTS, OR MODIFICATIONS.
025
026 PT_COPYRIGHT_VERSION_2
027 COPYRIGHTENDKEY
028 */
029
030package ptolemy.actor.injection;
031
032import java.util.HashMap;
033
034///////////////////////////////////////////////////////////////////
035//// Injector
036/**
037 * The Injector class is responsible for loading implementation based
038 * on a interface. The mappings from the interface to implementation
039 * must be loaded prior to that.
040 *
041 * @author Anar Huseynov, Erwin de Ley
042 * @version $Id$
043 * @since Ptolemy II 10.0
044 * @Pt.ProposedRating Red (ahuseyno)
045 * @Pt.AcceptedRating Red (ahuseyno)
046 */
047public class Injector {
048
049    ///////////////////////////////////////////////////////////////////
050    ////                         public methods                    ////
051
052    /**
053     * Get implementation for the provided interface based on the
054     * mappings loaded into the injector.
055     * Class<T> is the implementation.
056     *
057     * @param type The interface type to load.
058     * @return The implementation of the interface.
059     */
060    public <T> T getInstance(Class<T> type) {
061        Class<T> implementation = (Class<T>) _resolvedInterfaceToImplementationMap
062                .get(type);
063        if (implementation != null) {
064            try {
065                return implementation.newInstance();
066            } catch (InstantiationException e) {
067                throw new IllegalStateException(
068                        "Problem instantiating type " + implementation, e);
069            } catch (IllegalAccessException e) {
070                throw new IllegalStateException(
071                        "Problem instantiating type " + implementation, e);
072            }
073        } else {
074            try {
075                PtolemyModule module = _interfaceToImplementationMap
076                        .get(type.getName());
077                String implementationName = module.getBindings()
078                        .get(type.getName());
079                ClassLoader loader = module.getClassLoader() != null
080                        ? module.getClassLoader()
081                        : getClass().getClassLoader();
082                if (implementationName != null) {
083                    try {
084                        Class<?> implementationClass = loader
085                                .loadClass(implementationName);
086                        _resolvedInterfaceToImplementationMap.put(type,
087                                implementationClass);
088                        return (T) implementationClass.newInstance();
089                    } catch (ClassNotFoundException e) {
090                        throw new IllegalStateException(
091                                "Problem loading type " + implementationName,
092                                e);
093                    } catch (InstantiationException e) {
094                        throw new IllegalStateException(
095                                "Problem instantiating type "
096                                        + implementationName,
097                                e);
098                    } catch (IllegalAccessException e) {
099                        throw new IllegalStateException(
100                                "Problem instantiating type "
101                                        + implementationName,
102                                e);
103                    }
104                }
105            } catch (NullPointerException e) {
106                // skip, the exception is thrown below
107            }
108        }
109        throw new IllegalStateException("Implementation for the interface "
110                + type + " was not found. " + "Perhaps\n" + type.getName() + "="
111                + type.getName()
112                + "\nneeds to be added to the implementations class mappings file ptolemy/actor/*.properties such as ptolemy/actor/ActorModule.properties or some other injector file.");
113
114    }
115
116    /**
117     * Load the interface to implementation mappings into the injector.
118     *
119     * @param module The interface to implementation mapping.
120     */
121    public void loadMappings(PtolemyModule module) {
122        for (String interfaceType : module.getBindings().keySet()) {
123            _interfaceToImplementationMap.put(interfaceType, module);
124        }
125    }
126
127    ///////////////////////////////////////////////////////////////////
128    ////                         private variables                 ////
129    /**
130     * The resolved interface to the implementation class mappings.
131     */
132    private HashMap<Class<?>, Class<?>> _resolvedInterfaceToImplementationMap = new HashMap<Class<?>, Class<?>>();
133
134    /**
135     * The resolved interface to the implementation class mappings.
136     */
137    private HashMap<String, PtolemyModule> _interfaceToImplementationMap = new HashMap<String, PtolemyModule>();
138}