package org.jboss.ejb.plugins.inflow;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import javax.ejb.EJBMetaData;
import javax.management.ObjectName;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.UnavailableException;
import javax.resource.spi.endpoint.MessageEndpoint;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.transaction.xa.XAResource;
import org.jboss.deployment.DeploymentException;
import org.jboss.ejb.Container;
import org.jboss.ejb.EJBProxyFactory;
import org.jboss.ejb.MessageDrivenContainer;
import org.jboss.invocation.Invocation;
import org.jboss.invocation.InvocationType;
import org.jboss.invocation.InvokerInterceptor;
import org.jboss.metadata.ActivationConfigPropertyMetaData;
import org.jboss.metadata.InvokerProxyBindingMetaData;
import org.jboss.metadata.MessageDestinationMetaData;
import org.jboss.metadata.MessageDrivenMetaData;
import org.jboss.metadata.MetaData;
import org.jboss.mx.util.JMXExceptionDecoder;
import org.jboss.proxy.GenericProxyFactory;
import org.jboss.system.ServiceMBeanSupport;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
public class JBossMessageEndpointFactory
extends ServiceMBeanSupport
implements EJBProxyFactory, MessageEndpointFactory, JBossMessageEndpointFactoryMBean
{
protected boolean trace = log.isTraceEnabled();
protected MessageDrivenContainer container;
protected MessageDrivenMetaData metaData;
protected String invokerBinding;
protected InvokerProxyBindingMetaData invokerMetaData;
protected HashMap properties = new HashMap();
protected GenericProxyFactory proxyFactory = new GenericProxyFactory();
protected Class messagingTypeClass;
protected String resourceAdapterName;
protected ObjectName resourceAdapterObjectName;
protected ActivationSpec activationSpec;
protected ArrayList interceptors;
protected Class[] interfaces;
protected SynchronizedInt nextProxyId = new SynchronizedInt(0);
protected String[] createActivationSpecSig = new String[]
{
Class.class.getName(),
Collection.class.getName()
};
protected String[] activationSig = new String[]
{
MessageEndpointFactory.class.getName(),
ActivationSpec.class.getName()
};
public MessageDrivenContainer getContainer()
{
return container;
}
public String getConfig()
{
return toString();
}
public MessageEndpoint createEndpoint(XAResource resource) throws UnavailableException
{
trace = log.isTraceEnabled();
if (getState() != STARTED && getState() != STARTING)
throw new UnavailableException("The container is not started");
HashMap context = new HashMap();
context.put(MessageEndpointInterceptor.MESSAGE_ENDPOINT_FACTORY, this);
context.put(MessageEndpointInterceptor.MESSAGE_ENDPOINT_XARESOURCE, resource);
String ejbName = container.getBeanMetaData().getContainerObjectNameJndiName();
if (trace)
log.trace("createEndpoint " + this + " xaResource=" + resource);
MessageEndpoint endpoint = (MessageEndpoint) proxyFactory.createProxy
(
ejbName + "@" + nextProxyId.increment(),
container.getServiceName(),
InvokerInterceptor.getLocal(),
null,
null,
interceptors,
container.getClassLoader(),
interfaces,
context
);
if (trace)
log.trace("Created endpoint " + endpoint + " from " + this);
return endpoint;
}
public boolean isDeliveryTransacted(Method method) throws NoSuchMethodException
{
boolean result = false;
int transType = metaData.getMethodTransactionType(method.getName(), method.getParameterTypes(), InvocationType.LOCAL);
if (transType == MetaData.TX_REQUIRED)
result = true;
if (trace)
log.trace("isDeliveryTransacted " + container.getBeanMetaData().getContainerObjectNameJndiName() + " method=" + method + " result=" + result);
return result;
}
protected void startService() throws Exception
{
metaData = (MessageDrivenMetaData) container.getBeanMetaData();
resolveMessageListener();
resolveResourceAdapter();
createActivationSpec();
setupProxyParameters();
activate();
}
protected void stopService() throws Exception
{
deactivate();
}
public boolean isIdentical(Container container, Invocation mi)
{
throw new Error("Not valid for MessageDriven beans");
}
public Object getEJBHome()
{
throw new Error("Not valid for MessageDriven beans");
}
public EJBMetaData getEJBMetaData()
{
throw new Error("Not valid for MessageDriven beans");
}
public Collection getEntityCollection(Collection enum)
{
throw new Error("Not valid for MessageDriven beans");
}
public Object getEntityEJBObject(Object id)
{
throw new Error("Not valid for MessageDriven beans");
}
public Object getStatefulSessionEJBObject(Object id)
{
throw new Error("Not valid for MessageDriven beans");
}
public Object getStatelessSessionEJBObject()
{
throw new Error("Not valid for MessageDriven beans");
}
public void setInvokerBinding(String binding)
{
this.invokerBinding = binding;
}
public void setInvokerMetaData(InvokerProxyBindingMetaData imd)
{
this.invokerMetaData = imd;
}
public void setContainer(final Container container)
{
this.container = (MessageDrivenContainer) container;
}
public String toString()
{
StringBuffer buffer = new StringBuffer(100);
buffer.append(super.toString());
buffer.append("{ resourceAdapter=").append(resourceAdapterObjectName);
buffer.append(", messagingType=").append(messagingTypeClass.getName());
buffer.append(", ejbName=").append(container.getBeanMetaData().getContainerObjectNameJndiName());
buffer.append(", activationConfig=").append(properties.values());
buffer.append(", activationSpec=").append(activationSpec);
buffer.append("}");
return buffer.toString();
}
protected void resolveMessageListener() throws DeploymentException
{
String messagingType = metaData.getMessagingType();
try
{
messagingTypeClass = GetTCLAction.getContextClassLoader().loadClass(messagingType);
}
catch (Exception e)
{
DeploymentException.rethrowAsDeploymentException("Could not load messaging-type class " + messagingType, e);
}
}
protected String resolveResourceAdapterName() throws DeploymentException
{
return metaData.getResourceAdapterName();
}
protected void resolveResourceAdapter() throws DeploymentException
{
resourceAdapterName = resolveResourceAdapterName();
try
{
resourceAdapterObjectName = new ObjectName("jboss.jca:service=RARDeployment,name='" + resourceAdapterName + "'");
int state = ((Integer) server.getAttribute(resourceAdapterObjectName, "State")).intValue();
if (state != STARTED)
throw new DeploymentException("The resource adapter is not started " + resourceAdapterName);
}
catch (Exception e)
{
DeploymentException.rethrowAsDeploymentException("Cannot locate resource adapter deployment " + resourceAdapterName, e);
}
}
protected void setupProxyParameters() throws DeploymentException
{
interfaces = new Class[] { MessageEndpoint.class, messagingTypeClass };
interceptors = new ArrayList();
Element proxyConfig = invokerMetaData.getProxyFactoryConfig();
Element endpointInterceptors = MetaData.getOptionalChild(proxyConfig, "endpoint-interceptors", null);
if (endpointInterceptors == null)
throw new DeploymentException("No endpoint interceptors found");
else
{
NodeList children = endpointInterceptors.getElementsByTagName("interceptor");
for (int i = 0; i < children.getLength(); ++i)
{
Node currentChild = children.item(i);
if (currentChild.getNodeType() == Node.ELEMENT_NODE)
{
Element interceptor = (Element) children.item(i);
String className = MetaData.getElementContent(interceptor);
try
{
Class clazz = container.getClassLoader().loadClass(className);
interceptors.add(clazz);
}
catch (Throwable t)
{
DeploymentException.rethrowAsDeploymentException("Error loading interceptor class " + className, t);
}
}
}
}
}
protected void augmentActivationConfigProperties() throws DeploymentException
{
Element proxyConfig = invokerMetaData.getProxyFactoryConfig();
Element activationConfig = MetaData.getOptionalChild(proxyConfig, "activation-config");
if (activationConfig != null)
{
Iterator iterator = MetaData.getChildrenByTagName(activationConfig, "activation-config-property");
while (iterator.hasNext())
{
Element resourceRef = (Element) iterator.next();
ActivationConfigPropertyMetaData metaData = new ActivationConfigPropertyMetaData();
metaData.importXml(resourceRef);
if (properties.containsKey(metaData.getName()) == false)
properties.put(metaData.getName(), metaData);
}
}
String link = metaData.getDestinationLink();
if (link != null)
{
link = link.trim();
if (link.length() > 0)
{
if (properties.containsKey("destination"))
log.warn("Ignoring message-destination-link '" + link + "' when the destination " +
"is already in the activation-config.");
else
{
MessageDestinationMetaData destinationMetaData = container.getMessageDestination(link);
if (destinationMetaData == null)
throw new DeploymentException("Unresolved message-destination-link '" + link + "' no message-destination in ejb-jar.xml");
String jndiName = destinationMetaData.getJNDIName();
if (jndiName == null)
throw new DeploymentException("The message-destination '" + link + "' has no jndi-name in jboss.xml");
properties.put("destination", jndiName);
}
}
}
}
protected void createActivationSpec() throws DeploymentException
{
properties = new HashMap(metaData.getActivationConfigProperties());
augmentActivationConfigProperties();
Object[] params = new Object[]
{
messagingTypeClass,
properties.values()
};
try
{
activationSpec = (ActivationSpec) server.invoke(resourceAdapterObjectName, "createActivationSpec", params, createActivationSpecSig);
}
catch (Throwable t)
{
t = JMXExceptionDecoder.decode(t);
DeploymentException.rethrowAsDeploymentException("Unable to create activation spec ra=" + resourceAdapterObjectName +
" messaging-type=" + messagingTypeClass.getName() + " properties=" + metaData.getActivationConfigProperties(), t);
}
}
protected void activate() throws DeploymentException
{
Object[] params = new Object[] { this, activationSpec };
try
{
server.invoke(resourceAdapterObjectName, "endpointActivation", params, activationSig);
}
catch (Throwable t)
{
t = JMXExceptionDecoder.decode(t);
DeploymentException.rethrowAsDeploymentException("Endpoint activation failed ra=" + resourceAdapterObjectName +
" activationSpec=" + activationSpec, t);
}
}
protected void deactivate()
{
Object[] params = new Object[] { this, activationSpec };
try
{
server.invoke(resourceAdapterObjectName, "endpointDeactivation", params, activationSig);
}
catch (Throwable t)
{
t = JMXExceptionDecoder.decode(t);
log.warn("Endpoint activation failed ra=" + resourceAdapterObjectName +
" activationSpec=" + activationSpec, t);
}
}
}