/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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.ejb3.deployment.processors;
import static org.jboss.as.ee.component.Attachments.EE_APPLICATION_DESCRIPTION;
import java.util.HashSet;
import java.util.Set;
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.InjectionSource;
import org.jboss.as.ee.component.ViewDescription;
import org.jboss.as.ee.component.ViewManagedReferenceFactory;
import org.jboss.as.ejb3.logging.EjbLogger;
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.remote.RemoteViewManagedReferenceFactory;
import org.jboss.as.naming.ManagedReferenceFactory;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.module.ResourceRoot;
import org.jboss.modules.Module;
import org.jboss.msc.inject.Injector;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.value.Value;
/**
* Implementation of {@link InjectionSource} responsible for finding a specific bean instance with a bean name and interface.
*
* @author John Bailey
* @author Stuart Douglas
*/
public class EjbInjectionSource extends InjectionSource {
private final String beanName;
private final String typeName;
private final String bindingName;
private final DeploymentUnit deploymentUnit;
private final boolean appclient;
private volatile String error = null;
private volatile ServiceName resolvedViewName;
private volatile RemoteViewManagedReferenceFactory remoteFactory;
private volatile boolean resolved = false;
public EjbInjectionSource(final String beanName, final String typeName, final String bindingName, final DeploymentUnit deploymentUnit, final boolean appclient) {
this.beanName = beanName;
this.typeName = typeName;
this.bindingName = bindingName;
this.deploymentUnit = deploymentUnit;
this.appclient = appclient;
}
public EjbInjectionSource(final String typeName, final String bindingName, final DeploymentUnit deploymentUnit, final boolean appclient) {
this.bindingName = bindingName;
this.deploymentUnit = deploymentUnit;
this.appclient = appclient;
this.beanName = null;
this.typeName = typeName;
}
public void getResourceValue(final ResolutionContext resolutionContext, final ServiceBuilder<?> serviceBuilder, final DeploymentPhaseContext phaseContext, final Injector<ManagedReferenceFactory> injector) throws DeploymentUnitProcessingException {
resolve();
if (error != null) {
throw new DeploymentUnitProcessingException(error);
}
if (remoteFactory != null) {
//because we are using the ejb: lookup namespace we do not need a dependency
injector.inject(remoteFactory);
} else if (!appclient) {
//we do not add a dependency if this is the appclient
//as local injections are simply ignored
serviceBuilder.addDependency(resolvedViewName, ComponentView.class, new ViewManagedReferenceFactory.Injector(injector));
}
}
/**
* Checks if this ejb injection has been resolved yet, and if not resolves it.
*/
private void resolve() {
if (!resolved) {
synchronized (this) {
if (!resolved) {
final Set<ViewDescription> views = getViews();
final Set<EJBViewDescription> ejbsForViewName = new HashSet<EJBViewDescription>();
for (final ViewDescription view : views) {
if (view instanceof EJBViewDescription) {
final MethodIntf viewType = ((EJBViewDescription) view).getMethodIntf();
// @EJB injection *shouldn't* consider the @WebService endpoint view or MDBs
if (viewType == MethodIntf.SERVICE_ENDPOINT || viewType == MethodIntf.MESSAGE_ENDPOINT) {
continue;
}
ejbsForViewName.add((EJBViewDescription) view);
}
}
if (ejbsForViewName.isEmpty()) {
if (beanName == null) {
error = EjbLogger.ROOT_LOGGER.ejbNotFound(typeName, bindingName);
} else {
error = EjbLogger.ROOT_LOGGER.ejbNotFound(typeName, beanName, bindingName);
}
} else if (ejbsForViewName.size() > 1) {
if (beanName == null) {
error = EjbLogger.ROOT_LOGGER.moreThanOneEjbFound(typeName, bindingName, ejbsForViewName);
} else {
error = EjbLogger.ROOT_LOGGER.moreThanOneEjbFound(typeName, beanName, bindingName, ejbsForViewName);
}
} else {
final EJBViewDescription description = ejbsForViewName.iterator().next();
final EJBViewDescription ejbViewDescription = (EJBViewDescription) description;
//for remote interfaces we do not want to use a normal binding
//we need to bind the remote proxy factory into JNDI instead to get the correct behaviour
if (ejbViewDescription.getMethodIntf() == MethodIntf.REMOTE || ejbViewDescription.getMethodIntf() == MethodIntf.HOME) {
final EJBComponentDescription componentDescription = (EJBComponentDescription) description.getComponentDescription();
final EEModuleDescription moduleDescription = componentDescription.getModuleDescription();
final String earApplicationName = moduleDescription.getEarApplicationName();
final Value<ClassLoader> viewClassLoader = new Value<ClassLoader>() {
@Override
public ClassLoader getValue() throws IllegalStateException, IllegalArgumentException {
final Module module = deploymentUnit.getAttachment(Attachments.MODULE);
return module != null ? module.getClassLoader() : null;
}
};
remoteFactory = new RemoteViewManagedReferenceFactory(earApplicationName, moduleDescription.getModuleName(), moduleDescription.getDistinctName(), componentDescription.getComponentName(), description.getViewClassName(), componentDescription.isStateful(), viewClassLoader, appclient);
}
final ServiceName serviceName = description.getServiceName();
resolvedViewName = serviceName;
}
resolved = true;
}
}
}
}
private Set<ViewDescription> getViews() {
final EEApplicationDescription applicationDescription = deploymentUnit.getAttachment(EE_APPLICATION_DESCRIPTION);
final ResourceRoot deploymentRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
final Set<ViewDescription> componentsForViewName;
if (beanName != null) {
componentsForViewName = applicationDescription.getComponents(beanName, typeName, deploymentRoot.getRoot());
} else {
componentsForViewName = applicationDescription.getComponentsForViewName(typeName, deploymentRoot.getRoot());
}
return componentsForViewName;
}
public boolean equals(Object o) {
if (this == o) { return true; }
if (!(o instanceof EjbInjectionSource)) { return false; }
resolve();
if (error != null) {
//we can't do a real equals comparison in this case, so just return false
return false;
}
final EjbInjectionSource other = (EjbInjectionSource) o;
return eq(typeName, other.typeName) && eq(resolvedViewName, other.resolvedViewName);
}
public int hashCode() {
return typeName.hashCode();
}
private static boolean eq(Object a, Object b) {
return a == b || (a != null && a.equals(b));
}
}