/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.weld.services.bootstrap; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Set; import javax.ejb.EJB; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.InjectionPoint; import javax.naming.InitialContext; import javax.naming.NamingException; import org.jboss.as.ee.component.ComponentView; import org.jboss.as.ee.component.EEApplicationDescription; import org.jboss.as.ee.component.EEModuleDescription; import org.jboss.as.ee.component.ViewDescription; import org.jboss.as.naming.ManagedReference; import org.jboss.as.naming.deployment.ContextNames; import org.jboss.as.naming.deployment.ContextNames.BindInfo; import org.jboss.as.weld.logging.WeldLogger; import org.jboss.as.weld.util.ResourceInjectionUtilities; import org.jboss.modules.Module; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceRegistry; import org.jboss.vfs.VirtualFile; import org.jboss.weld.injection.spi.EjbInjectionServices; import org.jboss.weld.injection.spi.ResourceReference; import org.jboss.weld.injection.spi.ResourceReferenceFactory; import org.jboss.weld.injection.spi.helpers.SimpleResourceReference; import org.jboss.weld.logging.BeanLogger; import org.jboss.weld.util.reflection.Reflections; /** * Implementation of EjbInjectionServices. * * @author Stuart Douglas */ public class WeldEjbInjectionServices extends AbstractResourceInjectionServices implements EjbInjectionServices { private final EEApplicationDescription applicationDescription; private final VirtualFile deploymentRoot; private final boolean warModule; public WeldEjbInjectionServices(ServiceRegistry serviceRegistry, EEModuleDescription moduleDescription, final EEApplicationDescription applicationDescription, final VirtualFile deploymentRoot, Module module, boolean warModule) { super(serviceRegistry, moduleDescription, module); this.warModule = warModule; if (serviceRegistry == null) { throw WeldLogger.ROOT_LOGGER.parameterCannotBeNull("serviceRegistry"); } if (moduleDescription == null) { throw WeldLogger.ROOT_LOGGER.parameterCannotBeNull("moduleDescription"); } if (applicationDescription == null) { throw WeldLogger.ROOT_LOGGER.parameterCannotBeNull("applicationDescription"); } if (deploymentRoot == null) { throw WeldLogger.ROOT_LOGGER.parameterCannotBeNull("deploymentRoot"); } this.applicationDescription = applicationDescription; this.deploymentRoot = deploymentRoot; } @Override public Object resolveEjb(InjectionPoint injectionPoint) { throw new UnsupportedOperationException(); } @Override public ResourceReferenceFactory<Object> registerEjbInjectionPoint(final InjectionPoint injectionPoint) { EJB ejb = ResourceInjectionUtilities.getResourceAnnotated(injectionPoint).getAnnotation(EJB.class); if (ejb == null) { throw WeldLogger.ROOT_LOGGER.annotationNotFound(EJB.class, injectionPoint.getMember()); } if (injectionPoint.getMember() instanceof Method && ((Method) injectionPoint.getMember()).getParameterTypes().length != 1) { throw WeldLogger.ROOT_LOGGER.injectionPointNotAJavabean((Method) injectionPoint.getMember()); } if (!ejb.lookup().equals("")) { if (ejb.lookup().startsWith("ejb:")) { return new ResourceReferenceFactory<Object>() { @Override public ResourceReference<Object> createResource() { return new SimpleResourceReference<Object>(doLookup(ejb.lookup(), null)); } }; } return handleServiceLookup(ejb.lookup(), injectionPoint); } else { final ViewDescription viewDescription = getViewDescription(ejb, injectionPoint); if (viewDescription != null) { return handleServiceLookup(viewDescription, injectionPoint); } else { final String proposedName = getEjbBindLocation(injectionPoint); return new ResourceReferenceFactory<Object>() { @Override public ResourceReference<Object> createResource() { return new SimpleResourceReference<Object>(doLookup(proposedName, null)); } }; } } } private ResourceReferenceFactory<Object> handleServiceLookup(ViewDescription viewDescription, InjectionPoint injectionPoint) { /* * Try to obtain ComponentView eagerly and validate the resource type */ final ComponentView view = getComponentView(viewDescription); if (view != null && injectionPoint.getAnnotated().isAnnotationPresent(Produces.class)) { Class<?> clazz = view.getViewClass(); Class<?> injectionPointRawType = Reflections.getRawType(injectionPoint.getType()); //we just compare names, as for remote views the actual classes may be loaded from different class loaders Class<?> c = clazz; boolean found = false; while (c != null && c != Object.class) { if (injectionPointRawType.getName().equals(c.getName())) { found = true; break; } c = c.getSuperclass(); } if (!found) { throw BeanLogger.LOG.invalidResourceProducerType(injectionPoint.getAnnotated(), clazz.getName()); } return new ComponentViewToResourceReferenceFactoryAdapter<Object>(view); } else { return new LazyResourceReferenceFactory(viewDescription, serviceRegistry); } } private ComponentView getComponentView(ViewDescription viewDescription) { final ServiceController<?> controller = serviceRegistry.getService(viewDescription.getServiceName()); if (controller == null) { return null; } return (ComponentView) controller.getValue(); } private ViewDescription getViewDescription(EJB ejb, InjectionPoint injectionPoint) { final Set<ViewDescription> viewService; if (ejb.beanName().isEmpty()) { if (ejb.beanInterface() != Object.class) { viewService = applicationDescription.getComponentsForViewName(ejb.beanInterface().getName(), deploymentRoot); } else { viewService = applicationDescription.getComponentsForViewName(getType(injectionPoint.getType()).getName(), deploymentRoot); } } else { if (ejb.beanInterface() != Object.class) { viewService = applicationDescription.getComponents(ejb.beanName(), ejb.beanInterface().getName(), deploymentRoot); } else { viewService = applicationDescription.getComponents(ejb.beanName(), getType(injectionPoint.getType()).getName(), deploymentRoot); } } if (injectionPoint.getAnnotated().isAnnotationPresent(Produces.class)) { if (viewService.isEmpty()) { throw WeldLogger.ROOT_LOGGER.ejbNotResolved(ejb, injectionPoint.getMember()); } else if (viewService.size() > 1) { throw WeldLogger.ROOT_LOGGER.moreThanOneEjbResolved(ejb, injectionPoint.getMember(), viewService); } } else { if (viewService.isEmpty()) { return null; } else if (viewService.size() > 1) { return null; } } return viewService.iterator().next(); } @Override protected BindInfo getBindInfo(String result) { return ContextNames.bindInfoForEnvEntry(moduleDescription.getApplicationName(), moduleDescription.getModuleName(), moduleDescription.getModuleName(), !warModule, result); } @Override public void cleanup() { } private static Class<?> getType(Type type) { if (type instanceof Class) { return (Class<?>) type; } else if (type instanceof ParameterizedType) { return getType(((ParameterizedType) type).getRawType()); } else { throw WeldLogger.ROOT_LOGGER.couldNotDetermineUnderlyingType(type); } } protected ResourceReferenceFactory<Object> createLazyResourceReferenceFactory(final ViewDescription viewDescription) { return new ResourceReferenceFactory<Object>() { @Override public ResourceReference<Object> createResource() { final ManagedReference instance; try { final ServiceController<?> controller = serviceRegistry.getRequiredService(viewDescription.getServiceName()); final ComponentView view = (ComponentView) controller.getValue(); instance = view.createInstance(); return new ResourceReference<Object>() { @Override public Object getInstance() { return instance.getInstance(); } @Override public void release() { instance.release(); } }; } catch (Exception e) { throw new RuntimeException(e); } } }; } public Object doLookup(String jndiName, String mappedName) { String name = ResourceInjectionUtilities.getResourceName(jndiName, mappedName); try { return new InitialContext().lookup(name); } catch (NamingException e) { throw WeldLogger.ROOT_LOGGER.couldNotFindResource(name, e); } } private String getEjbBindLocation(InjectionPoint injectionPoint) { EJB ejb = ResourceInjectionUtilities.getResourceAnnotated(injectionPoint).getAnnotation(EJB.class); String mappedName = ejb.mappedName(); if (!mappedName.equals("")) { return mappedName; } String name = ejb.name(); if (!name.equals("")) { return ResourceInjectionUtilities.RESOURCE_LOOKUP_PREFIX + "/" + name; } String propertyName; if (injectionPoint.getMember() instanceof Field) { propertyName = injectionPoint.getMember().getName(); } else if (injectionPoint.getMember() instanceof Method) { propertyName = ResourceInjectionUtilities.getPropertyName((Method) injectionPoint.getMember()); if (propertyName == null) { throw WeldLogger.ROOT_LOGGER.injectionPointNotAJavabean((Method) injectionPoint.getMember()); } } else { throw WeldLogger.ROOT_LOGGER.cannotInject(injectionPoint); } String className = injectionPoint.getMember().getDeclaringClass().getName(); return ResourceInjectionUtilities.RESOURCE_LOOKUP_PREFIX + "/" + className + "/" + propertyName; } private static class LazyResourceReferenceFactory implements ResourceReferenceFactory<Object> { private final ViewDescription viewDescription; private final ServiceRegistry serviceRegistry; LazyResourceReferenceFactory(ViewDescription viewDescription, ServiceRegistry serviceRegistry) { this.viewDescription = viewDescription; this.serviceRegistry = serviceRegistry; } @Override public ResourceReference<Object> createResource() { final ManagedReference instance; try { final ServiceController<?> controller = serviceRegistry.getRequiredService(viewDescription.getServiceName()); final ComponentView view = (ComponentView) controller.getValue(); instance = view.createInstance(); return new ResourceReference<Object>() { @Override public Object getInstance() { return instance.getInstance(); } @Override public void release() { instance.release(); } }; } catch (Exception e) { throw new RuntimeException(e); } } } }