/*
* 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.ejb;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.jboss.as.ee.component.ViewDescription;
import org.jboss.as.ejb3.component.EJBComponentDescription;
import org.jboss.as.ejb3.component.EJBViewDescription;
import org.jboss.as.ejb3.component.MethodIntf;
import org.jboss.as.ejb3.component.session.SessionBeanComponentDescription;
import org.jboss.as.ejb3.component.stateful.StatefulComponentDescription;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
import org.jboss.msc.service.ServiceName;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.ejb.spi.BusinessInterfaceDescriptor;
import org.jboss.weld.ejb.spi.EjbDescriptor;
import org.jboss.weld.resources.spi.ResourceLoader;
/**
* Implementation of EjbDescriptor
*
* @author Stuart Douglas
*/
public class EjbDescriptorImpl<T> implements EjbDescriptor<T> {
private final ServiceName baseName;
private final Set<BusinessInterfaceDescriptor<?>> localInterfaces;
private final Set<BusinessInterfaceDescriptor<?>> remoteInterfaces;
private final Map<Class<?>, ServiceName> viewServices;
private final Set<Method> removeMethods;
private final Class<T> ejbClass;
private final String ejbName;
private final boolean stateless;
private final boolean stateful;
private final boolean singleton;
private final boolean messageDriven;
private final boolean passivationCapable;
public EjbDescriptorImpl(EJBComponentDescription componentDescription, BeanDeploymentArchive beanDeploymentArchive, final DeploymentReflectionIndex reflectionIndex) {
final SessionBeanComponentDescription description = componentDescription instanceof SessionBeanComponentDescription ? (SessionBeanComponentDescription) componentDescription : null;
final Set<BusinessInterfaceDescriptor<?>> localInterfaces = new HashSet<BusinessInterfaceDescriptor<?>>();
final Set<BusinessInterfaceDescriptor<?>> remoteInterfaces = new HashSet<BusinessInterfaceDescriptor<?>>();
final ResourceLoader loader = beanDeploymentArchive.getServices().get(ResourceLoader.class);
ejbClass = (Class<T>) loader.classForName(componentDescription.getEJBClassName());
if (componentDescription.getViews() != null) {
for (ViewDescription view : componentDescription.getViews()) {
if (description == null || getMethodIntf(view) == MethodIntf.LOCAL) {
final String viewClassName = view.getViewClassName();
localInterfaces.add(new BusinessInterfaceDescriptorImpl<Object>(beanDeploymentArchive, viewClassName));
} else if (getMethodIntf(view) == MethodIntf.REMOTE) {
remoteInterfaces.add(new BusinessInterfaceDescriptorImpl<Object>(beanDeploymentArchive, view.getViewClassName()));
}
}
}
if(componentDescription instanceof StatefulComponentDescription) {
Set<Method> removeMethods = new HashSet<Method>();
final Collection<StatefulComponentDescription.StatefulRemoveMethod> methods = ((StatefulComponentDescription) componentDescription).getRemoveMethods();
for(final StatefulComponentDescription.StatefulRemoveMethod method : methods) {
Class<?> c = ejbClass;
while (c != null && c != Object.class) {
ClassReflectionIndex index = reflectionIndex.getClassIndex(c);
Method m = index.getMethod(method.getMethodIdentifier());
if(m != null) {
removeMethods.add(m);
}
c = c.getSuperclass();
}
}
this.removeMethods = Collections.unmodifiableSet(removeMethods);
} else {
removeMethods = Collections.emptySet();
}
this.ejbName = componentDescription.getEJBName();
this.localInterfaces = localInterfaces;
this.remoteInterfaces = remoteInterfaces;
this.baseName = componentDescription.getServiceName();
this.stateless = componentDescription.isStateless();
this.messageDriven = componentDescription.isMessageDriven();
this.stateful = componentDescription.isStateful();
this.singleton = componentDescription.isSingleton();
this.passivationCapable = componentDescription.isPassivationApplicable();
final Map<Class<?>, ServiceName> viewServices = new HashMap<Class<?>, ServiceName>();
final Map<String, Class<?>> views = new HashMap<String, Class<?>>();
Map<Class<?>, ServiceName> viewServicesMap = new HashMap<Class<?>, ServiceName>();
for (ViewDescription view : componentDescription.getViews()) {
viewServicesMap.put(loader.classForName(view.getViewClassName()), view.getServiceName());
}
for (BusinessInterfaceDescriptor<?> view : remoteInterfaces) {
views.put(view.getInterface().getName(), view.getInterface());
}
for (BusinessInterfaceDescriptor<?> view : localInterfaces) {
views.put(view.getInterface().getName(), view.getInterface());
}
for (Map.Entry<Class<?>, ServiceName> entry : viewServicesMap.entrySet()) {
final Class<?> viewClass = entry.getKey();
if (viewClass != null) {
//see WELD-921
//this is horrible, but until it is fixed there is not much that can be done
final Set<Class<?>> seen = new HashSet<Class<?>>();
final Set<Class<?>> toProcess = new HashSet<Class<?>>();
toProcess.add(viewClass);
while (!toProcess.isEmpty()) {
Iterator<Class<?>> it = toProcess.iterator();
final Class<?> clazz = it.next();
it.remove();
seen.add(clazz);
viewServices.put(clazz, entry.getValue());
final Class<?> superclass = clazz.getSuperclass();
if (superclass != Object.class && superclass != null && !seen.contains(superclass)) {
toProcess.add(superclass);
}
for (Class<?> iface : clazz.getInterfaces()) {
if (!seen.contains(iface)) {
toProcess.add(iface);
}
}
}
}
}
this.viewServices = viewServices;
}
private MethodIntf getMethodIntf(final ViewDescription view) {
if (view instanceof EJBViewDescription) {
final EJBViewDescription ejbView = (EJBViewDescription) view;
return ejbView.getMethodIntf();
}
return null;
}
@Override
public Class<T> getBeanClass() {
return ejbClass;
}
@Override
public Collection<BusinessInterfaceDescriptor<?>> getLocalBusinessInterfaces() {
return localInterfaces;
}
@Override
public Collection<BusinessInterfaceDescriptor<?>> getRemoteBusinessInterfaces() {
return remoteInterfaces;
}
@Override
public String getEjbName() {
return ejbName;
}
@Override
public Collection<Method> getRemoveMethods() {
return removeMethods;
}
@Override
public boolean isStateless() {
return stateless;
}
@Override
public boolean isSingleton() {
return singleton;
}
@Override
public boolean isStateful() {
return stateful;
}
@Override
public boolean isMessageDriven() {
return messageDriven;
}
public ServiceName getBaseName() {
return baseName;
}
public ServiceName getCreateServiceName() {
return baseName.append("CREATE");
}
public ServiceName getStartServiceName() {
return baseName.append("START");
}
public Map<Class<?>, ServiceName> getViewServices() {
return viewServices;
}
@Override
public boolean isPassivationCapable() {
return passivationCapable;
}
}