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 * @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 @Dependent bean, then it does <b>not</b> 70 * belong to such a well defined lifecycle (because @Dependent it is not 71 * @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 @Named annotation.</p> 148 * 149 * <p><b>Attention:</b> please see the notes on manually resolving @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 @Named annotation.</p> 166 * 167 * <p><b>Attention:</b> please see the notes on manually resolving @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 @Named annotation.</p> 184 * 185 * <p><b>Attention:</b> please see the notes on manually resolving @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 @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 @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 @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 @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 @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 }