View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.cdi.util;
20  
21  import javax.enterprise.context.spi.CreationalContext;
22  import javax.enterprise.inject.Typed;
23  import javax.enterprise.inject.spi.Bean;
24  import javax.enterprise.inject.spi.BeanManager;
25  import java.lang.annotation.Annotation;
26  import java.util.Arrays;
27  import java.util.Set;
28  
29  /**
30   * <p>This class contains utility methods to resolve contextual references
31   * in situations where no injection is available because the
32   * current class is not managed by the CDI Container. This can happen
33   * in e.g. a JPA-2.0 EntityListener, a ServletFilter, a Spring managed
34   * Bean, etc.</p>
35   *
36   * <p><b>Attention:</b> This method is intended for being used in user code at runtime.
37   * If this method gets used during Container boot (in an Extension), non-portable
38   * behaviour results. The CDI specification only allows injection of the
39   * BeanManager during CDI-Container boot time.</p>
40   *
41   * @see BeanManagerProvider
42   */
43  @Typed()
44  public final class BeanProvider
45  {
46      //private static final Logger LOG = Logger.getLogger(BeanProvider.class.getName());
47  
48      /*
49      private static final boolean LOG_DEPENDENT_WARNINGS;
50      static {
51          ProjectStage ps = ProjectStageProducer.getInstance().getProjectStage();
52          LOG_DEPENDENT_WARNINGS = ps.equals(ProjectStage.Development) || ps.equals(ProjectStage.UnitTest);
53      }*/
54  
55      private BeanProvider()
56      {
57          // this is a utility class which doesn't get instantiated.
58      }
59  
60      /**
61       * <p>Get a Contextual Reference by its type and qualifiers.
62       * You can use this method to get contextual references of a given type.
63       * A 'Contextual Reference' is a proxy which will automatically resolve
64       * the correct contextual instance when you access any method.</p>
65       *
66       * <p><b>Attention:</b> You shall not use this method to manually resolve a
67       * &#064;Dependent bean! The reason is that this contextual instances do usually
68       * live in the well-defined lifecycle of their injection point (the bean they got
69       * injected into). But if we manually resolve a &#064;Dependent bean, then it does <b>not</b>
70       * belong to such a well defined lifecycle (because &#064;Dependent it is not
71       * &#064;NormalScoped) and thus will not automatically be
72       * destroyed at the end of the lifecycle. You need to manually destroy this contextual instance via
73       * {@link javax.enterprise.context.spi.Contextual#destroy(Object, javax.enterprise.context.spi.CreationalContext)}.
74       * Thus you also need to manually store the CreationalContext and the Bean you
75       * used to create the contextual instance which this method will not provide.</p>
76       *
77       * @param type the type of the bean in question
78       * @param qualifiers additional qualifiers which further distinct the resolved bean
79       * @param <T> target type
80       * @return the resolved Contextual Reference
81       * @throws IllegalStateException if the bean could not be found.
82       * @see #getContextualReference(Class, boolean, Annotation...)
83       */
84      /*
85      public static <T> T getContextualReference(Class<T> type, Annotation... qualifiers)
86      {
87          return getContextualReference(type, false, qualifiers);
88      }*/
89  
90      /**
91       * {@link #getContextualReference(Class, Annotation...)} which returns <code>null</code> if the
92       * 'optional' parameter is set to <code>true</code>.
93       *
94       * @param type the type of the bean in question
95       * @param optional if <code>true</code> it will return <code>null</code> if no bean could be found or created.
96       *                 Otherwise it will throw an {@code IllegalStateException}
97       * @param qualifiers additional qualifiers which further distinct the resolved bean
98       * @param <T> target type
99       * @return the resolved Contextual Reference
100      * @see #getContextualReference(Class, Annotation...)
101      */
102     /*
103     public static <T> T getContextualReference(Class<T> type, boolean optional, Annotation... qualifiers)
104     {
105         BeanManager beanManager = getBeanManager();
106 
107         return getContextualReference(beanManager, type, optional, qualifiers);
108     }*/
109 
110     /**
111      * {@link #getContextualReference(Class, Annotation...)} which returns <code>null</code> if the
112      * 'optional' parameter is set to <code>true</code>.
113      * This method is intended for usage where the BeanManger is known, e.g. in Extensions.
114      *
115      * @param beanManager the BeanManager to use
116      * @param type the type of the bean in question
117      * @param optional if <code>true</code> it will return <code>null</code> if no bean could be found or created.
118      *                 Otherwise it will throw an {@code IllegalStateException}
119      * @param qualifiers additional qualifiers which further distinct the resolved bean
120      * @param <T> target type
121      * @return the resolved Contextual Reference
122      * @see #getContextualReference(Class, Annotation...)
123      */
124     public static <T> T getContextualReference(BeanManager beanManager,
125                                                Class<T> type,
126                                                boolean optional,
127                                                Annotation... qualifiers)
128     {
129         Set<Bean<?>> beans = beanManager.getBeans(type, qualifiers);
130 
131         if (beans == null || beans.isEmpty())
132         {
133             if (optional)
134             {
135                 return null;
136             }
137 
138             throw new IllegalStateException("Could not find beans for Type=" + type
139                     + " and qualifiers:" + Arrays.toString(qualifiers));
140         }
141 
142         return getContextualReference(type, beanManager, beans);
143     }
144 
145     /**
146      * <p>Get a Contextual Reference by its EL Name.
147      * This only works for beans with the &#064;Named annotation.</p>
148      *
149      * <p><b>Attention:</b> please see the notes on manually resolving &#064;Dependent bean
150      * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!</p>
151      *
152      * @param name     the EL name of the bean
153      * @return the resolved Contextual Reference
154      * @throws IllegalStateException if the bean could not be found.
155      * @see #getContextualReference(String, boolean)
156      */
157     /*
158     public static Object getContextualReference(String name)
159     {
160         return getContextualReference(name, false);
161     }*/
162 
163     /**
164      * <p>Get a Contextual Reference by its EL Name.
165      * This only works for beans with the &#064;Named annotation.</p>
166      *
167      * <p><b>Attention:</b> please see the notes on manually resolving &#064;Dependent bean
168      * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!</p>
169      *
170      * @param name     the EL name of the bean
171      * @param optional if <code>true</code> it will return <code>null</code> if no bean could be found or created.
172      *                 Otherwise it will throw an {@code IllegalStateException}
173      * @return the resolved Contextual Reference
174      */
175     /*
176     public static Object getContextualReference(String name, boolean optional)
177     {
178         return getContextualReference(name, optional, Object.class);
179     }*/
180 
181     /**
182      * <p>Get a Contextual Reference by its EL Name.
183      * This only works for beans with the &#064;Named annotation.</p>
184      *
185      * <p><b>Attention:</b> please see the notes on manually resolving &#064;Dependent bean
186      * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!</p>
187      *
188      *
189      * @param name the EL name of the bean
190      * @param optional if <code>true</code> it will return <code>null</code> if no bean could be found or created.
191      *                 Otherwise it will throw an {@code IllegalStateException}
192      * @param type the type of the bean in question - use {@link #getContextualReference(String, boolean)}
193      *             if the type is unknown e.g. in dyn. use-cases
194      * @param <T> target type
195      * @return the resolved Contextual Reference
196      */
197     /*
198     public static <T> T getContextualReference(String name, boolean optional, Class<T> type)
199     {
200         BeanManager beanManager = getBeanManager();
201         Set<Bean<?>> beans = beanManager.getBeans(name);
202 
203         if (beans == null || beans.isEmpty())
204         {
205             if (optional)
206             {
207                 return null;
208             }
209 
210             throw new IllegalStateException("Could not find beans for Type=" + type
211                     + " and name:" + name);
212         }
213 
214         return getContextualReference(type, beanManager, beans);
215     }*/
216 
217     /**
218      * Get the Contextual Reference for the given bean.
219      *
220      * @param type the type of the bean in question
221      * @param bean bean-definition for the contextual-reference
222      * @param <T> target type
223      * @return the resolved Contextual Reference
224      */
225     /*
226     public static <T> T getContextualReference(Class<T> type, Bean<T> bean)
227     {
228         return getContextualReference(type, getBeanManager(), bean);
229     }*/
230 
231     /*
232     private static <T> T getContextualReference(Class<T> type, BeanManager beanManager, Bean<?> bean)
233     {
234         //noinspection unchecked
235         return getContextualReference(type, beanManager, new HashSet<Bean<?>>((Collection) Arrays.asList(bean)));
236     }
237     */
238 
239     /**
240      * <p>Get a list of Contextual References by type independent of the qualifier
241      * (including dependent scoped beans).
242      *
243      * You can use this method to get all contextual references of a given type.
244      * A 'Contextual Reference' is a proxy which will automatically resolve
245      * the correct contextual instance when you access any method.</p>
246      *
247      * <p><b>Attention:</b> please see the notes on manually resolving &#064;Dependent bean
248      * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!</p>
249      * <p><b>Attention:</b> This will also return instances of beans for which an Alternative
250      * exists! The &#064;Alternative resolving is only done via {@link BeanManager#resolve(java.util.Set)}
251      * which we cannot use in this case!</p>
252      *
253      * @param type the type of the bean in question
254      * @param optional if <code>true</code> it will return an empty list if no bean could be found or created.
255      *                 Otherwise it will throw an {@code IllegalStateException}
256      * @param <T> target type
257      * @return the resolved list of Contextual Reference or an empty-list if optional is true
258      */
259     /*
260     public static <T> List<T> getContextualReferences(Class<T> type, boolean optional)
261     {
262         return getContextualReferences(type, optional, true);
263     }*/
264 
265     /**
266      * <p>Get a list of Contextual References by type independent of the qualifier.
267      *
268      * Further details are available at {@link #getContextualReferences(Class, boolean)}
269      * <p><b>Attention:</b> please see the notes on manually resolving &#064;Dependent bean
270      * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!</p>
271      * <p><b>Attention:</b> This will also return instances of beans for which an Alternative
272      * exists! The &#064;Alternative resolving is only done via {@link BeanManager#resolve(java.util.Set)}
273      * which we cannot use in this case!</p>
274      *
275      * @param type the type of the bean in question
276      * @param optional if <code>true</code> it will return an empty list if no bean could be found or created.
277      *                 Otherwise it will throw an {@code IllegalStateException}
278      * @param includeDefaultScopedBeans specifies if dependent scoped beans should be included in the result
279      * @param <T> target type
280      * @return the resolved list of Contextual Reference or an empty-list if optional is true
281      */
282     /*
283     public static <T> List<T> getContextualReferences(Class<T> type,
284                                                       boolean optional,
285                                                       boolean includeDefaultScopedBeans)
286     {
287         BeanManager beanManager = getBeanManager();
288 
289         Set<Bean<T>> beans = getBeanDefinitions(type, optional, includeDefaultScopedBeans, beanManager);
290 
291         List<T> result = new ArrayList<T>(beans.size());
292 
293         for (Bean<?> bean : beans)
294         {
295             //noinspection unchecked
296             result.add(getContextualReference(type, beanManager, bean));
297         }
298         return result;
299     }*/
300 
301     /**
302      * Get a set of {@link Bean} definitions by type independent of the qualifier.
303      *
304      * @param type the type of the bean in question
305      * @param optional if <code>true</code> it will return an empty set if no bean could be found.
306      *                 Otherwise it will throw an {@code IllegalStateException}
307      * @param includeDefaultScopedBeans specifies if dependent scoped beans should be included in the result
308      * @param <T> target type
309      * @return the resolved set of {@link Bean} definitions or an empty-set if optional is true
310      */
311     /*
312     public static <T> Set<Bean<T>> getBeanDefinitions(Class<T> type,
313                                                       boolean optional,
314                                                       boolean includeDefaultScopedBeans)
315     {
316         BeanManager beanManager = getBeanManager();
317         
318         return getBeanDefinitions(type, optional, includeDefaultScopedBeans, beanManager);
319     }*/
320     /*
321     private static <T> Set<Bean<T>> getBeanDefinitions(Class<T> type,
322                                                        boolean optional,
323                                                        boolean includeDefaultScopedBeans,
324                                                        BeanManager beanManager)
325     {
326         Set<Bean<?>> beans = beanManager.getBeans(type, new AnyLiteral());
327 
328         if (beans == null || beans.isEmpty())
329         {
330             if (optional)
331             {
332                 return Collections.emptySet();
333             }
334 
335             throw new IllegalStateException("Could not find beans for Type=" + type);
336         }
337 
338         if (!includeDefaultScopedBeans)
339         {
340             beans = filterDefaultScopedBeans(beans);
341         }
342         
343         Set<Bean<T>> result = new HashSet<Bean<T>>();
344         
345         for (Bean<?> bean : beans)
346         {
347             //noinspection unchecked
348             result.add((Bean<T>) bean);
349         }
350         
351         return result;
352     }*/
353     
354     /**
355      * Allows to perform dependency injection for instances which aren't managed by CDI.
356      * <p/>
357      * Attention:<br/>
358      * The resulting instance isn't managed by CDI; only fields annotated with @Inject get initialized.
359      *
360      * @param instance current instance
361      * @param <T> current type
362      * @return instance with injected fields (if possible - or null if the given instance is null)
363      *//*
364     @SuppressWarnings("unchecked")
365     public static <T> T injectFields(T instance)
366     {
367         if (instance == null)
368         {
369             return null;
370         }
371 
372         BeanManager beanManager = getBeanManager();
373 
374         CreationalContext creationalContext = beanManager.createCreationalContext(null);
375 
376         AnnotatedType annotatedType = beanManager.createAnnotatedType(instance.getClass());
377         InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotatedType);
378         injectionTarget.inject(instance, creationalContext);
379         return instance;
380     }*/
381 
382     /*
383     private static Set<Bean<?>> filterDefaultScopedBeans(Set<Bean<?>> beans)
384     {
385         Set<Bean<?>> result = new HashSet<Bean<?>>(beans.size());
386 
387         Iterator<Bean<?>> beanIterator = beans.iterator();
388 
389         Bean<?> currentBean;
390         while (beanIterator.hasNext())
391         {
392             currentBean = beanIterator.next();
393 
394             if (!Dependent.class.isAssignableFrom(currentBean.getScope()))
395             {
396                 result.add(currentBean);
397             }
398         }
399         return result;
400     }*/
401 
402     /**
403      * Internal helper method to resolve the right bean and resolve the contextual reference.
404      *
405      * @param type the type of the bean in question
406      * @param beanManager current bean-manager
407      * @param beans beans in question
408      * @param <T> target type
409      * @return the contextual reference
410      */
411     private static <T> T getContextualReference(Class<T> type, BeanManager beanManager, Set<Bean<?>> beans)
412     {
413         Bean<?> bean = beanManager.resolve(beans);
414 
415         //logWarningIfDependent(bean);
416 
417         CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
418 
419         @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" })
420         T result = (T) beanManager.getReference(bean, type, creationalContext);
421         return result;
422     }
423 
424     /**
425      * Log a warning if the produced creational instance is of
426      * Scope &#064;Dependent as we cannot properly cleanup
427      * the contextual instance afterwards.
428      */
429     /*
430     private static void logWarningIfDependent(Bean<?> bean)
431     {
432         if (LOG_DEPENDENT_WARNINGS && bean.getScope().equals(Dependent.class))
433         {
434             LOG.log(Level.WARNING, "BeanProvider shall not be used to create @Dependent scoped beans. "
435                     + "Bean: " + bean.toString());
436         }
437     }*/
438 
439     /**
440      * Internal method to resolve the BeanManager via the {@link BeanManagerProvider}
441      * @return current bean-manager
442      */
443     /*
444     private static BeanManager getBeanManager()
445     {
446         return BeanManagerProvider.getInstance().getBeanManager();
447     }*/
448 }