/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, 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.switchboard.mc.deployer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.jboss.beans.metadata.api.annotations.Inject;
import org.jboss.beans.metadata.plugins.AbstractInjectionValueMetaData;
import org.jboss.beans.metadata.plugins.builder.BeanMetaDataBuilderFactory;
import org.jboss.beans.metadata.spi.BeanMetaData;
import org.jboss.beans.metadata.spi.DemandMetaData;
import org.jboss.beans.metadata.spi.DependencyMetaData;
import org.jboss.beans.metadata.spi.SupplyMetaData;
import org.jboss.beans.metadata.spi.builder.BeanMetaDataBuilder;
import org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer;
import org.jboss.deployers.structure.spi.DeploymentUnit;
import org.jboss.logging.Logger;
import org.jboss.metadata.ejb.jboss.JBossMetaData;
import org.jboss.metadata.javaee.spec.Environment;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.reloaded.naming.deployers.javaee.JavaEEComponentInformer;
import org.jboss.reloaded.naming.spi.JavaEEComponent;
import org.jboss.reloaded.naming.spi.JavaEEModule;
import org.jboss.switchboard.jbmeta.javaee.environment.BeanManagerReference;
import org.jboss.switchboard.jbmeta.javaee.environment.JndiEnvironmentMetadata;
import org.jboss.switchboard.jbmeta.javaee.environment.ORBReference;
import org.jboss.switchboard.jbmeta.javaee.environment.TransactionSynchronizationRegistryReference;
import org.jboss.switchboard.jbmeta.javaee.environment.UserTransactionReference;
import org.jboss.switchboard.jbmeta.javaee.environment.ValidatorFactoryReference;
import org.jboss.switchboard.jbmeta.javaee.environment.ValidatorReference;
import org.jboss.switchboard.mc.JndiEnvironmentProcessor;
import org.jboss.switchboard.mc.SwitchBoardImpl;
import org.jboss.switchboard.spi.Barrier;
import org.jboss.switchboard.spi.EnvironmentEntryType;
import org.jboss.switchboard.spi.JndiEnvironment;
import org.jboss.switchboard.spi.Resource;
import org.jboss.switchboard.spi.ResourceProvider;
/**
* AbstractENCOperatorDeployer
*
* @author Jaikiran Pai
* @version $Revision: $
*/
public abstract class AbstractSwitchBoardDeployer extends AbstractRealDeployer
{
/** Logger */
private static Logger logger = Logger.getLogger(AbstractSwitchBoardDeployer.class);
protected JavaEEComponentInformer informer;
protected JndiEnvironmentProcessor jndiEnvProcessor;
public AbstractSwitchBoardDeployer(JavaEEComponentInformer informer)
{
this.informer = informer;
//setInputs(informer.getRequiredAttachments());
setOutput(BeanMetaData.class);
addOutput(Barrier.class);
}
@Inject
public void setJNDIEnvironmentProcessor(JndiEnvironmentProcessor processor)
{
this.jndiEnvProcessor = processor;
}
protected String getApplicationName(DeploymentUnit deploymentUnit)
{
return informer.getApplicationName(deploymentUnit);
}
protected String getComponentName(DeploymentUnit deploymentUnit)
{
return informer.getComponentName(deploymentUnit);
}
protected String getModuleName(DeploymentUnit deploymentUnit)
{
return informer.getModuleName(deploymentUnit);
}
protected void process(DeploymentUnit unit, Collection<Environment> environments)
{
Map<String, Resource> resources = new HashMap<String, Resource>();
// create resources out of the environments
if (environments != null)
{
for (Environment env : environments)
{
if (env == null)
{
continue;
}
JndiEnvironment jndiEnv = new JndiEnvironmentMetadata(env);
this.addJavaComponentEntries(jndiEnv);
resources.putAll(this.jndiEnvProcessor.process(unit, jndiEnv));
}
}
// A SwitchBoard Barrier might already exist for the unit. For example,
// for EJBs and servlets deployed in a single .war (component), there will be
// a ENCOperator which might have been created and added when processing JBossMetaData (for EJBs)
// and now we might be processing JBossWebMetaData (for servlets), which both share the same
// (JavaEE)component.
Barrier barrier = unit.getAttachment(Barrier.class);
if (barrier == null)
{
// create a new one and attach it to unit
SwitchBoardImpl switchBoard = new SwitchBoardImpl(this.getSwitchBoardMCBeanName(unit), resources, unit);
this.attachBarrier(unit, switchBoard);
BeanMetaData switchBoardBMD = this.createSwitchBoardBMD(unit, switchBoard);
this.attachSwitchBoardBMD(unit, switchBoardBMD);
}
else
{
// HACK!
// TODO: Think about a better way of doing this (maybe making available the methods in Barrier)
if (barrier instanceof SwitchBoardImpl)
{
SwitchBoardImpl switchboard = (SwitchBoardImpl) barrier;
switchboard.addENCBinding(resources);
// recreate and attach SwitchBoard BMD, since the
// new Resource binding might have additional dependencies
BeanMetaData switchBoardBMD = this.createSwitchBoardBMD(unit, switchboard);
this.attachSwitchBoardBMD(unit, switchBoardBMD);
}
}
}
/**
* Add additional {@link EnvironmentEntryType environment entries}, to the {@link JndiEnvironment},
* which are expected to be bound in java:comp of the component.
* <p>
* Typically, these entries that go into java:comp, unlike the entries that go into java:comp/env,
* are <i>not</i> driven by deployment descriptors or annotation in the user deployments. For example,
* the spec mandates that the following resources be made available in the java:comp of an component:
* <ul>
* <li>ORB (at java:comp/ORB)</li>
* <li>UserTransaction (at java:comp/UserTransaction)</li>
* <li>TransactionSynchronizationRegistry (at java:comp/TransactionSynchronizationRegistry)</li>
* <li>BeanManager (at java:comp/BeanManager)</li>
* <li>Validator (at java:comp/Validator)</li>
* <li>ValidatorFactory (at java:comp/ValidatorFactory)</li>
* </ul>
* This method add these {@link EnvironmentEntryType environment entries} to the {@link JndiEnvironment},
* so that the corresponding {@link ResourceProvider}s can then pick these up and provide the appropriate
* {@link Resource}s.
*
* </p>
* @param jndiEnv
*/
protected void addJavaComponentEntries(JndiEnvironment jndiEnv)
{
// for java:comp/ORB
jndiEnv.addEntry(new ORBReference());
// for java:comp/UserTransaction
jndiEnv.addEntry(new UserTransactionReference());
// for java:comp/TransactionSynchronizationRegistry
jndiEnv.addEntry(new TransactionSynchronizationRegistryReference());
// for java:comp/BeanManager
jndiEnv.addEntry(new BeanManagerReference());
// for java:comp/Validator
jndiEnv.addEntry(new ValidatorReference());
// for java:comp/ValidatorFactory
jndiEnv.addEntry(new ValidatorFactoryReference());
}
protected BeanMetaData createSwitchBoardBMD(DeploymentUnit unit, SwitchBoardImpl switchBoard)
{
String mcBeanName = switchBoard.getId();
BeanMetaDataBuilder builder = BeanMetaDataBuilderFactory.createBuilder(mcBeanName, switchBoard.getClass().getName());
builder.setConstructorValue(switchBoard);
// inject java:global context into switchboard.
// the global context is available via the NameSpaces MC bean's "globalContext" property
builder.addPropertyMetaData("javaGlobalContext", builder.createInject("NameSpaces", "globalContext"));
// inject the appropriate JavaEEComponent or JavaEEModule for the switchboard
AbstractInjectionValueMetaData namingContextInjection = this.getNamingContextInjectionMetaData(unit);
if (this.informer.isJavaEEComponent(unit) && !this.isSharedENC(unit))
{
builder.addPropertyMetaData("javaEEComponent", namingContextInjection);
}
else
{
builder.addPropertyMetaData("javaEEModule", namingContextInjection);
}
// add the dependencies of the Resources, on the switchboard so that
// the switchboard will not be installed till those dependencies required by the
// ENC binding Resource(s) are satisfied.
for (DependencyMetaData bindDependency : switchBoard.getBindDependencies())
{
builder.addDependency(bindDependency);
}
for (DependencyMetaData invocationDependency : switchBoard.getInvocationDependencies())
{
builder.addDependency(invocationDependency);
}
// log the switchboard installation
if (logger.isDebugEnabled())
{
logger.debug("Installing SwitchBoard: " + mcBeanName + " for unit: " + unit.getSimpleName());
Set<DependencyMetaData> dependencies = builder.getBeanMetaData().getDepends();
if (dependencies != null)
{
logger.debug("with dependencies:");
for (DependencyMetaData dependency : dependencies)
{
logger.debug(dependency);
}
}
Set<DemandMetaData> demands = builder.getBeanMetaData().getDemands();
if (demands != null)
{
logger.debug("demands:");
for (DemandMetaData demand : demands)
{
logger.debug(demand);
}
}
Set<SupplyMetaData> supplies = builder.getBeanMetaData().getSupplies();
if (supplies != null)
{
logger.debug("supplies:");
for (SupplyMetaData supply : supplies)
{
logger.debug(supply);
}
}
}
// return the switchboard BMD
return builder.getBeanMetaData();
}
protected String getSwitchBoardMCBeanName(DeploymentUnit unit)
{
StringBuilder sb = new StringBuilder("jboss-switchboard:");
String appName = this.getApplicationName(unit);
if (appName != null)
{
sb.append("appName=");
sb.append(appName);
sb.append(",");
}
String moduleName = this.getModuleName(unit);
sb.append("module=");
sb.append(moduleName);
if (this.informer.isJavaEEComponent(unit) && !this.isSharedENC(unit))
{
String componentName = this.getComponentName(unit);
sb.append(",name=");
sb.append(componentName);
}
return sb.toString();
}
/**
* Returns the MC bean name of either {@link JavaEEComponent} or a {@link JavaEEModule}
* depending on the deployment unit
* @param deploymentUnit
* @return
*/
protected String getENCContextMCBeanName(DeploymentUnit deploymentUnit)
{
String applicationName = this.getApplicationName(deploymentUnit);
String moduleName = this.getModuleName(deploymentUnit);
final StringBuilder builder = new StringBuilder("jboss.naming:");
if (applicationName != null)
{
builder.append("application=").append(applicationName).append(",");
}
builder.append("module=").append(moduleName);
if (this.informer.isJavaEEComponent(deploymentUnit) && !this.isSharedENC(deploymentUnit))
{
String componentName = this.getComponentName(deploymentUnit);
builder.append(",component=").append(componentName);
}
return builder.toString();
}
protected boolean isSharedENC(DeploymentUnit deploymentUnit)
{
JBossMetaData jbossMetaData = deploymentUnit.getAttachment(JBossMetaData.class);
JBossWebMetaData jbosswebMetaData = deploymentUnit.getAttachment(JBossWebMetaData.class);
if (jbossMetaData != null && jbosswebMetaData != null)
{
return true;
}
return false;
}
protected AbstractInjectionValueMetaData getNamingContextInjectionMetaData(DeploymentUnit deploymentUnit)
{
String encCtxMCBeanName = this.getENCContextMCBeanName(deploymentUnit);
AbstractInjectionValueMetaData namingContextInjectionMetaData = new AbstractInjectionValueMetaData(encCtxMCBeanName);
return namingContextInjectionMetaData;
}
protected abstract void attachSwitchBoardBMD(DeploymentUnit deploymentUnit, BeanMetaData switchBoardBMD);
protected abstract void attachBarrier(DeploymentUnit deploymentUnit, Barrier switchBoard);
}