| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.myfaces.extensions.cdi.core.api.provider; |
| |
| import org.apache.myfaces.extensions.cdi.core.api.startup.CodiStartupBroadcaster; |
| import org.apache.myfaces.extensions.cdi.core.api.util.ClassUtils; |
| |
| import javax.enterprise.context.spi.CreationalContext; |
| import javax.enterprise.event.Observes; |
| import javax.enterprise.inject.spi.AfterBeanDiscovery; |
| import javax.enterprise.inject.spi.Bean; |
| import javax.enterprise.inject.spi.BeanManager; |
| import javax.enterprise.inject.spi.BeforeShutdown; |
| import javax.enterprise.inject.spi.Extension; |
| import javax.naming.InitialContext; |
| import javax.naming.NamingException; |
| import java.lang.annotation.Annotation; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| /** |
| * <p>This class provides access to the BeanManager |
| * by registring the current BeanManager in an extension and |
| * making it available via a singleton factory</p> |
| * <p>This is really handy if you like to access CDI functionality |
| * from places where no injection is available.</p> |
| * |
| * <p>Usage:<p/> |
| * <pre> |
| * BeanManager bm = BeanManagerProvider.getInstance().getBeanManager(); |
| * </pre> |
| */ |
| public class BeanManagerProvider implements Extension |
| { |
| private static BeanManagerProvider bmp = null; |
| |
| private volatile Map<ClassLoader, BeanManagerHolder> bms = new ConcurrentHashMap<ClassLoader, BeanManagerHolder>(); |
| |
| /** |
| * Returns if the {@link BeanManagerProvider} has been initialized |
| * @return true if the bean-manager-provider is ready to be used |
| */ |
| public static boolean isActive() |
| { |
| return bmp != null; |
| } |
| |
| /** |
| * Singleton accessor |
| * @return the singleton BeanManagerProvider |
| */ |
| public static BeanManagerProvider getInstance() |
| { |
| if(bmp == null) |
| { |
| //workaround for Mojarra (in combination with OWB and a custom WebBeansConfigurationListener and a custom |
| //StartupBroadcaster for bootstrapping CDI) |
| CodiStartupBroadcaster.broadcastStartup(); |
| //here bmp might not be null (depends on the broadcasters) |
| } |
| if(bmp == null) |
| { |
| throw new IllegalStateException("no " + BeanManagerProvider.class.getName() + " in place! " + |
| "Please ensure that you configured the CDI implementation of your choice properly. " + |
| "If your setup is correct, please clear all caches and compiled artifacts. " + |
| "If there is still a problem, try one of the controlled bootstrapping add-ons for the CDI " + |
| "implementation you are using."); |
| } |
| return bmp; |
| } |
| |
| |
| /** |
| * The active {@link BeanManager} for the current {@link ClassLoader} |
| * @return the current bean-manager |
| */ |
| public BeanManager getBeanManager() |
| { |
| ClassLoader classLoader = ClassUtils.getClassLoader(null); |
| |
| BeanManagerHolder resultHolder = bms.get(classLoader); |
| BeanManager result; |
| |
| if (resultHolder == null) |
| { |
| result = resolveBeanManagerViaJndi(); |
| |
| if(result != null) |
| { |
| bms.put(classLoader, new RootBeanManagerHolder(result)); |
| } |
| } |
| else |
| { |
| result = resultHolder.getBeanManager(); |
| |
| if (!(resultHolder instanceof RootBeanManagerHolder)) |
| { |
| BeanManager jndiBeanManager = resolveBeanManagerViaJndi(); |
| |
| if (jndiBeanManager != null && /*same instance check:*/jndiBeanManager != result) |
| { |
| setRootBeanManager(jndiBeanManager); |
| |
| result = jndiBeanManager; |
| } |
| else |
| { |
| setRootBeanManager(result); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * <p></p>Get a Contextual Reference by it's type and annotation. |
| * You can use this method to get contextual references of a given type. |
| * A 'Contextual Reference' is a proxy which will automatically resolve |
| * the correct contextual instance when you access any method.</p> |
| * |
| * <p><b>Attention:</b> You shall not use this method to manually resolve a |
| * @Dependent bean! The reason is that this contextual instances do usually |
| * live in the well defined lifecycle of their injection point (the bean they got |
| * injected into). But if we manually resolve a @Dependent bean, then it does <b>not</b> |
| * belong to such a well defined lifecycle (because @Dependent it is not |
| * @NormalScoped) and thus will not automatically be |
| * destroyed at the end of the lifecycle. You need to manually destroy this contextual instance via |
| * {@link javax.enterprise.context.spi.Contextual#destroy(Object, javax.enterprise.context.spi.CreationalContext)}. |
| * Thus you also need to manually store the CreationalContext and the Bean you |
| * used to create the contextual instance which this method will not provide.</p> |
| * |
| * @param type the type of the bean in question |
| * @param qualifiers additional qualifiers which further distinct the resolved bean |
| * @param <T> target type |
| * @return the resolved Contextual Reference |
| */ |
| public <T> T getContextualReference(Class<T> type, Annotation... qualifiers) |
| { |
| BeanManager beanManager = getBeanManager(); |
| Set<Bean<?>> beans = beanManager.getBeans(type, qualifiers); |
| |
| if (beans == null || beans.isEmpty()) |
| { |
| throw new IllegalStateException("Could not find beans for Type=" + type |
| + " and qualifiers:" + Arrays.toString(qualifiers)); |
| } |
| |
| return getReference(type, beanManager, beans); |
| } |
| |
| /** |
| * <p>Get a Contextual Reference by it's EL Name. |
| * This only works for beans with the @Named annotation.</p> |
| * |
| * <p><b>Attention:</b> please see the notes on manually resolving @Dependent bean |
| * in {@link #getContextualReference(Class, java.lang.annotation.Annotation...)}!</p> |
| * |
| * |
| * @param type the type of the bean in question - only use Object.class if the type is unknown in dyn. use-cases |
| * @param name the EL name of the bean |
| * @param <T> target type |
| * @return the resolved Contextual Reference |
| */ |
| public <T> T getContextualReference(Class<T> type, String name) |
| { |
| BeanManager beanManager = getBeanManager(); |
| Set<Bean<?>> beans = beanManager.getBeans(name); |
| |
| return getReference(type, beanManager, beans); |
| } |
| |
| /** |
| * Internal helper method to resolve the right bean and |
| * resolve the contextual reference. |
| * @param type the type of the bean in question |
| * @param beanManager current bean-manager |
| * @param beans beans in question |
| * @param <T> target type |
| * @return the contextual reference |
| */ |
| private <T> T getReference(Class<T> type, BeanManager beanManager, Set<Bean<?>> beans) |
| { |
| Bean<?> bean = beanManager.resolve(beans); |
| |
| CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean); |
| |
| @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) |
| T result = (T)beanManager.getReference(bean, type, creationalContext); |
| return result; |
| } |
| |
| /** |
| * Get the BeanManager from the JNDI registry. |
| * |
| * Workaround for jboss 6 (EXTCDI-74) |
| * {@link #setBeanManager(javax.enterprise.inject.spi.AfterBeanDiscovery, javax.enterprise.inject.spi.BeanManager)} |
| * is called in context of a different classloader |
| * |
| * @return current {@link javax.enterprise.inject.spi.BeanManager} which is provided via jndi |
| */ |
| private BeanManager resolveBeanManagerViaJndi() |
| { |
| try |
| { |
| return (BeanManager) new InitialContext().lookup("java:comp/BeanManager"); |
| } |
| catch (NamingException e) |
| { |
| //workaround didn't work -> force NPE |
| return null; |
| } |
| } |
| |
| /** |
| * It basiscally doesn't matter which of the system events we use, |
| * but basically we |
| * @param afterBeanDiscovery event which we don't actually use ;) |
| * @param beanManager the BeanManager we store and make available. |
| */ |
| public void setBeanManager(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) |
| { |
| setBeanManager(new BeanManagerHolder(beanManager)); |
| } |
| |
| public void setRootBeanManager(BeanManager beanManager) |
| { |
| setBeanManager(new RootBeanManagerHolder(beanManager)); |
| } |
| |
| private void setBeanManager(BeanManagerHolder beanManagerHolder) |
| { |
| BeanManagerProvider bmpFirst = setBeanManagerProvider(this); |
| |
| ClassLoader cl = ClassUtils.getClassLoader(null); |
| |
| if (beanManagerHolder instanceof RootBeanManagerHolder || |
| //the lat bm wins - as before, but don't replace a root-bmh with a normal bmh |
| (!(bmpFirst.bms.get(cl) instanceof RootBeanManagerHolder))) |
| { |
| bmpFirst.bms.put(cl, beanManagerHolder); |
| } |
| |
| CodiStartupBroadcaster.broadcastStartup(); |
| } |
| |
| /** |
| * Cleanup on container shutdown |
| * @param beforeShutdown cdi shutdown event |
| */ |
| public void cleanupStoredBeanManagerOnShutdown(@Observes BeforeShutdown beforeShutdown) |
| { |
| bms.remove(ClassUtils.getClassLoader(null)); |
| } |
| |
| /** |
| * This function exists to prevent findbugs to complain about |
| * setting a static member from a non-static function. |
| * @param beanManagerProvider the bean-manager-provider which should be used if there isn't an existing provider |
| * @return the first BeanManagerProvider |
| */ |
| private static BeanManagerProvider setBeanManagerProvider(BeanManagerProvider beanManagerProvider) |
| { |
| if (bmp == null) |
| { |
| bmp = beanManagerProvider; |
| } |
| |
| return bmp; |
| } |
| } |