View Javadoc
1   /**
2    * This file Copyright (c) 2011-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.objectfactory.guice;
35  
36  import info.magnolia.objectfactory.CandidateParameterResolver;
37  import info.magnolia.objectfactory.ComponentFactory;
38  import info.magnolia.objectfactory.ComponentProvider;
39  import info.magnolia.objectfactory.MgnlInstantiationException;
40  import info.magnolia.objectfactory.NoSuchComponentException;
41  import info.magnolia.objectfactory.ObjectManufacturer;
42  import info.magnolia.objectfactory.ParameterResolver;
43  
44  import java.util.Arrays;
45  import java.util.Collections;
46  import java.util.Map;
47  
48  import javax.inject.Inject;
49  import javax.inject.Provider;
50  
51  import org.slf4j.Logger;
52  import org.slf4j.LoggerFactory;
53  
54  import com.google.inject.Injector;
55  import com.google.inject.Key;
56  
57  
58  /**
59   * ComponentProvider implementation based on Guice.
60   *
61   * @see ComponentProvider
62   * @see GuiceComponentProviderBuilder
63   */
64  public class GuiceComponentProvider implements ComponentProvider {
65  
66      private static Logger logger = LoggerFactory.getLogger(GuiceComponentProvider.class);
67  
68      @Inject
69      private Injector injector;
70      private ObjectManufacturer manufacturer;
71      private final Map<Key, Class> typeMappings;
72      private final GuiceComponentProvider parentComponentProvider;
73  
74      public GuiceComponentProviderice/GuiceComponentProvider.html#GuiceComponentProvider">GuiceComponentProvider(Map<Key, Class> typeMappings, GuiceComponentProvider parentComponentProvider) {
75          this.parentComponentProvider = parentComponentProvider;
76          this.typeMappings = typeMappings;
77      }
78  
79      @Override
80      public <T> Class<? extends T> getImplementation(Class<T> type) {
81          return getImplementation(Key.get(type));
82      }
83  
84      @SuppressWarnings("unchecked")
85      public <T> Class<? extends T> getImplementation(Key<T> type) {
86          Class<?> implementation = typeMappings.get(type);
87          if (implementation == null) {
88              if (parentComponentProvider != null) {
89                  return parentComponentProvider.getImplementation(type);
90              }
91              return (Class<? extends T>) type.getTypeLiteral().getRawType();
92          }
93          if (ComponentFactory.class.isAssignableFrom(implementation)) {
94              return (Class<? extends T>) type.getTypeLiteral().getRawType();
95          }
96          return (Class<? extends T>) implementation;
97      }
98  
99      @Override
100     @Deprecated
101     public <T> T getSingleton(Class<T> type) {
102         return getComponent(type);
103     }
104 
105     @Override
106     public <T> T getComponent(Class<T> type) throws NoSuchComponentException {
107         if (!GuiceUtils.hasExplicitBindingFor(injector, type)) {
108             throw new NoSuchComponentException("No component configuration for type [" + type.getName() + "] found. Please add a configuration to your module descriptor.");
109         }
110         return injector.getInstance(type);
111     }
112 
113     @Override
114     public <T> T newInstance(Class<T> type, Object... parameters) {
115         return newInstanceWithParameterResolvers(type, new CandidateParameterResolver(parameters));
116     }
117 
118     @Override
119     public <T> T newInstanceWithParameterResolvers(Class<T> type, ParameterResolver... parameterResolvers) {
120         return newInstanceWithParameterResolvers(Key.get(type), parameterResolvers);
121     }
122 
123     public <T> T newInstanceWithParameterResolvers(Key<T> type, ParameterResolver... parameterResolvers) {
124         try {
125             if (this.manufacturer == null) {
126                 this.manufacturer = new ObjectManufacturer();
127             }
128             Class<? extends T> implementation = getImplementation(type);
129             if (implementation == null) {
130                 logger.warn("Failed to resolve implementation for {}. Perhaps it is not defined. The only types defined for this container are {}.", type, typeMappings);
131             }
132 
133             parameterResolvers = concat(parameterResolvers, new GuiceParameterResolver(this));
134             T instance = (T) manufacturer.newInstance(implementation, parameterResolvers);
135             injectMembers(instance);
136             return instance;
137         } catch (Exception e) {
138             throw new MgnlInstantiationException("Failed to create instance of [" + type.getTypeLiteral().getRawType() + "]", e);
139         }
140     }
141 
142     private ParameterResolver./info/magnolia/objectfactory/ParameterResolver.html#ParameterResolver">ParameterResolver./info/magnolia/objectfactory/ParameterResolver.html#ParameterResolver">ParameterResolver[] concat(ParameterResolver./info/magnolia/objectfactory/ParameterResolver.html#ParameterResolver">ParameterResolver[] array, ParameterResolver extra) {
143         ParameterResolver[] newArray = Arrays.copyOf(array, array.length + 1);
144         newArray[array.length] = extra;
145         return newArray;
146     }
147 
148     public Injector getInjector() {
149         return injector;
150     }
151 
152     public <T> Provider<T> getProvider(Class<T> type) {
153         if (!GuiceUtils.hasExplicitBindingFor(injector, type)) {
154             return null;
155         }
156         return injector.getProvider(type);
157     }
158 
159     public void injectMembers(Object instance) {
160         injector.injectMembers(instance);
161     }
162 
163     public final Map<Key, Class> getTypeMappings() {
164         return Collections.unmodifiableMap(this.typeMappings);
165     }
166 
167     public void destroy() {
168         /*
169 
170        Destroy using @PreDestroy is disabled because the implementation acquires instances for lazy-init singletons
171        only to destroy them. It also tries to acquire instances that have non-existing scopes leading to exceptions
172        being thrown. This usually results in shutdown of the application being interrupted before having a chance to
173        properly close down JackRabbit. With (at least) the derby persistence manager this results in threads not being
174        closed down properly and therefore Tomcat stalls at shutdown.
175 
176         */
177     }
178 
179     @Override
180     public GuiceComponentProvider getParent() {
181         return parentComponentProvider;
182     }
183 }