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.NoSuchComponentException;
40  import info.magnolia.objectfactory.ObjectManufacturer;
41  import info.magnolia.objectfactory.ParameterResolver;
42  
43  import java.util.Arrays;
44  import java.util.Collections;
45  import java.util.Map;
46  
47  import javax.inject.Inject;
48  import javax.inject.Provider;
49  
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  import com.google.inject.Injector;
54  import com.google.inject.Key;
55  
56  
57  /**
58   * ComponentProvider implementation based on Guice.
59   *
60   * @see ComponentProvider
61   * @see GuiceComponentProviderBuilder
62   */
63  public class GuiceComponentProvider implements ComponentProvider {
64  
65      private static Logger logger = LoggerFactory.getLogger(GuiceComponentProvider.class);
66  
67      @Inject
68      private Injector injector;
69      private ObjectManufacturer manufacturer;
70      private final Map<Key, Class> typeMappings;
71      private final GuiceComponentProvider parentComponentProvider;
72  
73      public GuiceComponentProvider(Map<Key, Class> typeMappings, GuiceComponentProvider parentComponentProvider) {
74          this.parentComponentProvider = parentComponentProvider;
75          this.typeMappings = typeMappings;
76      }
77  
78      @Override
79      public <T> Class<? extends T> getImplementation(Class<T> type) {
80          return getImplementation(Key.get(type));
81      }
82  
83      @SuppressWarnings("unchecked")
84      public <T> Class<? extends T> getImplementation(Key<T> type) {
85          Class<?> implementation = typeMappings.get(type);
86          if (implementation == null) {
87              if (parentComponentProvider != null) {
88                  return parentComponentProvider.getImplementation(type);
89              }
90              return (Class<? extends T>) type.getTypeLiteral().getRawType();
91          }
92          if (ComponentFactory.class.isAssignableFrom(implementation)) {
93              return (Class<? extends T>) type.getTypeLiteral().getRawType();
94          }
95          return (Class<? extends T>) implementation;
96      }
97  
98      @Override
99      @Deprecated
100     public <T> T getSingleton(Class<T> type) {
101         return getComponent(type);
102     }
103 
104     @Override
105     public <T> T getComponent(Class<T> type) throws NoSuchComponentException {
106         if (!GuiceUtils.hasExplicitBindingFor(injector, type)) {
107             throw new NoSuchComponentException("No component configuration for type [" + type.getName() + "] found. Please add a configuration to your module descriptor.");
108         }
109         return injector.getInstance(type);
110     }
111 
112     @Override
113     public <T> T newInstance(Class<T> type, Object... parameters) {
114         return newInstanceWithParameterResolvers(type, new CandidateParameterResolver(parameters));
115     }
116 
117     @Override
118     public <T> T newInstanceWithParameterResolvers(Class<T> type, ParameterResolver... parameterResolvers) {
119         return newInstanceWithParameterResolvers(Key.get(type), parameterResolvers);
120     }
121 
122     public <T> T newInstanceWithParameterResolvers(Key<T> type, ParameterResolver... parameterResolvers) {
123         if (this.manufacturer == null) {
124             this.manufacturer = new ObjectManufacturer();
125         }
126         Class<? extends T> implementation = getImplementation(type);
127         if (implementation == null) {
128             logger.warn("Failed to resolve implementation for {}. Perhaps it is not defined. The only types defined for this container are {}.", type, typeMappings);
129         }
130 
131         parameterResolvers = concat(parameterResolvers, new GuiceParameterResolver(injector));
132         T instance = (T) manufacturer.newInstance(implementation, parameterResolvers);
133         injectMembers(instance);
134         return instance;
135     }
136 
137     private ParameterResolver[] concat(ParameterResolver[] array, ParameterResolver extra) {
138         ParameterResolver[] newArray = Arrays.copyOf(array, array.length + 1);
139         newArray[array.length] = extra;
140         return newArray;
141     }
142 
143     public Injector getInjector() {
144         return injector;
145     }
146 
147     public <T> Provider<T> getProvider(Class<T> type) {
148         if (!GuiceUtils.hasExplicitBindingFor(injector, type)) {
149             return null;
150         }
151         return injector.getProvider(type);
152     }
153 
154     public void injectMembers(Object instance) {
155         injector.injectMembers(instance);
156     }
157 
158     public final Map<Key, Class> getTypeMappings() {
159         return Collections.unmodifiableMap(this.typeMappings);
160     }
161 
162     public void destroy() {
163         /*
164 
165        Destroy using @PreDestroy is disabled because the implementation acquires instances for lazy-init singletons
166        only to destroy them. It also tries to acquire instances that have non-existing scopes leading to exceptions
167        being thrown. This usually results in shutdown of the application being interrupted before having a chance to
168        properly close down JackRabbit. With (at least) the derby persistence manager this results in threads not being
169        closed down properly and therefore Tomcat stalls at shutdown.
170 
171         */
172     }
173 
174     @Override
175     public GuiceComponentProvider getParent() {
176         return parentComponentProvider;
177     }
178 }