com.caucho.ejb.cfg.EjbMessageBean Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.ejb.cfg;
import static javax.ejb.TransactionAttributeType.REQUIRED;
import static javax.ejb.TransactionManagementType.BEAN;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import javax.annotation.PostConstruct;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.interceptor.AroundInvoke;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.naming.NamingException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.ResourceAdapter;
import com.caucho.config.Config;
import com.caucho.config.ConfigException;
import com.caucho.config.gen.BeanGenerator;
import com.caucho.config.gen.TransactionAttributeLiteral;
import com.caucho.config.gen.TransactionManagementLiteral;
import com.caucho.config.inject.InjectManager;
import com.caucho.config.reflect.AnnotatedTypeImpl;
import com.caucho.config.types.JndiBuilder;
import com.caucho.ejb.gen.MessageGenerator;
import com.caucho.ejb.manager.EjbManager;
import com.caucho.ejb.message.JmsActivationSpec;
import com.caucho.ejb.message.JmsResourceAdapter;
import com.caucho.ejb.message.MessageManager;
import com.caucho.ejb.server.AbstractEjbBeanManager;
import com.caucho.inject.Module;
import com.caucho.jca.cfg.MessageListenerConfig;
import com.caucho.jca.ra.ResourceArchive;
import com.caucho.jca.ra.ResourceArchiveManager;
import com.caucho.jms.JmsMessageListener;
import com.caucho.util.L10N;
/**
* Configuration for an ejb entity bean.
*/
@Module
public class EjbMessageBean extends EjbBean {
private static final L10N L = new L10N(EjbMessageBean.class);
private ConnectionFactory _connectionFactory;
private ActivationSpec _activationSpec;
private JmsActivationConfig _jmsActivationConfig
= new JmsActivationConfig();
// private Destination _destination;
private String _messageSelector;
private int _acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
private String _selector;
private String _subscriptionName;
private Class> _messagingType;
private MessageGenerator _messageBean;
/**
* Creates a new message bean configuration.
*/
public EjbMessageBean(EjbConfig config, String ejbModuleName)
{
super(config, ejbModuleName);
}
/**
* Creates a new session bean configuration.
*/
public EjbMessageBean(EjbConfig ejbConfig,
AnnotatedType rawAnnType,
AnnotatedType annType,
MessageDriven messageDriven)
{
super(ejbConfig, rawAnnType, annType, messageDriven.name());
}
/**
* Creates a new session bean configuration.
*/
public EjbMessageBean(EjbConfig ejbConfig,
AnnotatedType rawAnnType,
AnnotatedType annType,
String ejbName)
{
super(ejbConfig, rawAnnType, annType, ejbName);
}
/**
* Returns the kind of bean.
*/
@Override
public String getEJBKind()
{
return "message";
}
/**
* Sets the ejb implementation class.
*/
@Override
public void setEJBClass(Class ejbClass)
throws ConfigException
{
super.setEJBClass(ejbClass);
// ejb/0987
/*
if (! MessageDrivenBean.class.isAssignableFrom(ejbClass)
&& ! isAllowPOJO())
throw error(L.l("'{0}' must implement javax.ejb.MessageDrivenBean. Every message-driven bean must implement MessageDrivenBean.", ejbClass.getName()));
*/
if (Modifier.isAbstract(ejbClass.getModifiers()))
throw error(L.l("'{0}' must not be abstract. Every message-driven bean must be a fully-implemented class.",
ejbClass.getName()));
// ejb 3.0 simplified section 10.1.3
// The name annotation element defaults to the unqualified name of the bean
// class.
if (getEJBName() == null) {
setEJBName(ejbClass.getSimpleName());
}
}
/**
* Creates the old EJB 2.0 message-driven-destination
*/
public MessageDrivenDestination createMessageDrivenDestination()
{
return new MessageDrivenDestination();
}
/**
* Sets the JCA activation spec.
*/
public void setActivationSpec(ActivationSpec activationSpec)
{
_activationSpec = activationSpec;
}
/**
* Sets the JMS destination.
*/
public void setDestination(String destinationName)
throws ConfigException
{
_jmsActivationConfig.setDestinationName(destinationName);
}
/**
* Sets the JMS destination.
*/
public void setDestinationValue(Destination destination)
{
_jmsActivationConfig.setDestinationObject(destination);
}
public void setMessagingType(Class> messagingType)
{
if (messagingType != Object.class)
_messagingType = messagingType;
}
/**
* Returns the destination.
*/
public Destination getDestination()
{
return _jmsActivationConfig.getDestinationObject();
}
/**
* @deprecated for compat with TCK
*/
public void setMappedName(String mappedName)
throws ConfigException
{
// XXX:
// setDestination(destination);
}
/**
* Sets the JMS destination type.
*/
public void setMessageDestinationType(String type)
throws ConfigException, NamingException
{
}
/**
* Sets the JMS destination link
*/
public void setMessageDestinationLink(String messageDestinationLink)
throws ConfigException, NamingException
{
}
/**
* Sets the connection factory.
*/
public void setConnectionFactory(JndiBuilder factory)
throws ConfigException, NamingException
{
if (! (factory.getObject() instanceof ConnectionFactory))
throw new ConfigException(L.l("'{0}' needs to implement javax.jms.ConnectionFactory.",
factory.getObject()));
_connectionFactory = (ConnectionFactory) factory.getObject();
}
/**
* Sets the connection factory.
*/
public void setConnectionFactoryValue(ConnectionFactory factory)
{
_connectionFactory = factory;
}
/**
* Returns the destination.
*/
public ConnectionFactory getConnectionFactory()
{
return _connectionFactory;
}
/**
* Returns the acknowledge mode.
*/
public int getAcknowledgeMode()
{
return _acknowledgeMode;
}
/**
* Set the acknowledge mode.
*/
public void setAcknowledgeMode(int acknowledgeMode)
{
_acknowledgeMode = acknowledgeMode;
}
/**
* Returns the message selector
*/
public String getSelector()
{
return _selector;
}
/**
* Set the message selector.
*/
public void setSelector(String selector)
{
_selector = selector;
}
/**
* Returns the durable subscription name
*/
public String getSubscriptionName()
{
return _subscriptionName;
}
/**
* Set the message selector.
*/
public void setSubscriptionName(String subscriptionName)
{
_subscriptionName = subscriptionName;
}
/**
* Set true if the container handles transactions.
*/
public void setTransactionType(String type)
throws ConfigException
{
if (type.equals("Container")) {
setContainerTransaction(true);
}
else if (type.equals("Bean")) {
setContainerTransaction(false);
}
else
throw new ConfigException(L.l("'{0}' is an unknown transaction-type. transaction-type must be 'Bean' or 'Container'.", type));
}
public void setSecurityIdentity(SecurityIdentity identity)
{
}
/**
* Adds the activation config.
*/
public ActivationConfig createActivationConfig()
{
return new ActivationConfig();
}
public void setResourceAdapter(String name)
{
ResourceArchive ra = ResourceArchiveManager.findResourceArchive(name);
if (ra == null)
throw new ConfigException(L.l("'{0}' is an unknown resource-adapter"));
}
private void addActivationConfigProperty(String name, Object value)
{
if ("destination".equals(name)) {
if (value instanceof Destination) {
setDestinationValue((Destination) value);
}
else {
Config.setAttribute(_jmsActivationConfig, "destinationName", value);
}
}
else if ("messageSelector".equals(name)) {
_messageSelector = (String) value;
}
/*
else if ("message-consumer-max".equals(name)
|| "consumer-max".equals(name)) {
setMessageConsumerMax(Integer.parseInt(String.valueOf(value)));
}
*/
else {
Config.setAttribute(_jmsActivationConfig, name, value);
}
}
/**
* Sets the number of message consumers.
*/
public void setMessageConsumerMax(int consumerMax)
throws ConfigException
{
_jmsActivationConfig.setMaxPoolSize(consumerMax);
}
/**
* Initialize
*/
@PostConstruct
@Override
public void init()
throws ConfigException
{
if (_messagingType != null) {
}
else if (_activationSpec != null) {
String specName = _activationSpec.getClass().getName();
ResourceArchive ra
= ResourceArchiveManager.findResourceArchive(specName);
if (ra == null) {
throw new ConfigException(L.l("'{0}' is an unknown activation-spec. Make sure the JCA adapter is deployed in a .rar file",
specName));
}
try {
_activationSpec.validate();
} catch (Exception e) {
throw error(e);
}
MessageListenerConfig listener = ra.getMessageListener(specName);
_messagingType = listener.getMessageListenerType();
}
else if (MessageListener.class.isAssignableFrom(getEJBClass())) {
_messagingType = MessageListener.class;
}
else
throw error(L.l("'{0}' must implement javax.jms.MessageListener or specify {1}.",
getEJBClass().getName(),
isAllowPOJO() ? "messaging-type" : "messageListenerInterface"));
super.init();
AnnotatedMethod super X> ejbCreate = getMethod("ejbCreate", new Class[0]);
if (ejbCreate != null) {
int modifiers = ejbCreate.getJavaMember().getModifiers();
if (! Modifier.isPublic(modifiers)
&& ! Modifier.isProtected(modifiers))
throw error(L.l("{0}: ejbCreate method must be public or protected.",
getEJBClass().getName()));
}
// J2EEManagedObject.register(new com.caucho.management.j2ee.MessageDrivenBean(this));
}
@Override
protected void introspect()
{
super.introspect();
MessageDriven messageDriven
= getAnnotatedType().getAnnotation(MessageDriven.class);
if (messageDriven != null) {
ActivationConfigProperty []activationConfig
= messageDriven.activationConfig();
if (activationConfig != null) {
for (ActivationConfigProperty prop : activationConfig) {
addActivationConfigProperty(prop.propertyName(),
prop.propertyValue());
}
}
Class> type = messageDriven.messageListenerInterface();
if (type != null && ! Object.class.equals(type))
_messagingType = type;
}
validate();
JmsMessageListener listener
= getAnnotatedType().getAnnotation(JmsMessageListener.class);
if (listener != null) {
addActivationConfigProperty("destination", listener.destination());
addActivationConfigProperty("consumer-max",
String.valueOf(listener.consumerMax()));
}
}
private void validate()
{
if (! Modifier.isPublic(getEJBClass().getModifiers())) {
throw new ConfigException(L.l("'{0}' must be public because it's a MessageDriven bean",
getEJBClass().getName()));
}
Constructor> zeroCtor = null;
for (Constructor> ctor : getEJBClass().getConstructors()) {
if (ctor.getParameterTypes().length == 0)
zeroCtor = ctor;
}
if (zeroCtor == null)
throw new ConfigException(L.l("'{0}' needs a zero-arg constructor because it's a MessageDriven bean",
getEJBClass().getName()));
if (! Modifier.isPublic(zeroCtor.getModifiers())) {
throw new ConfigException(L.l("'{0}' needs a public zero-arg constructor beause it's a MessageDriven bean",
getEJBClass().getName()));
}
}
/**
* Obtain and apply initialization from annotations.
*/
@Override
public void initIntrospect()
throws ConfigException
{
// ejb/0fbm
super.initIntrospect();
AnnotatedType type = getAnnotatedType();
// ejb/0j40
if (! type.isAnnotationPresent(MessageDriven.class)
&& ! type.isAnnotationPresent(MessageDriven.class)
&& ! isAllowPOJO())
return;
// XXX: annotations in super classes?
AnnotatedTypeImpl typeImpl = (AnnotatedTypeImpl) type;
if (! type.isAnnotationPresent(TransactionAttribute.class)) {
typeImpl.addAnnotation(new TransactionAttributeLiteral(TransactionAttributeType.REQUIRED));
}
javax.ejb.MessageDriven messageDriven
= type.getAnnotation(javax.ejb.MessageDriven.class);
if (messageDriven != null) {
ActivationConfigProperty[] properties
= messageDriven.activationConfig();
if (properties != null) {
for (ActivationConfigProperty property : properties)
addActivationConfigProperty(property.propertyName(),
property.propertyValue());
}
Class> messageListenerInterface
= messageDriven.messageListenerInterface();
if (messageListenerInterface != null)
setMessagingType(messageListenerInterface);
TransactionManagement transaction = type.getAnnotation(TransactionManagement.class);
if (transaction == null)
setTransactionType("Container");
else if (TransactionManagementType.BEAN.equals(transaction.value()))
setTransactionType("Bean");
else
setTransactionType("Container");
configureMethods(type);
}
}
/**
* Creates the bean generator for the session bean.
*/
@Override
protected BeanGenerator createBeanGenerator()
{
AnnotatedType ejbClass = getAnnotatedType();
ejbClass = fillClassDefaults(ejbClass);
_messageBean = new MessageGenerator(getEJBName(), ejbClass);
// _messageBean.setApi(new AnnotatedTypeImpl(_messagingType));
return _messageBean;
}
private void configureMethods(AnnotatedType type)
throws ConfigException
{
for (AnnotatedMethod super X> method : type.getMethods()) {
AroundInvoke aroundInvoke = method.getAnnotation(AroundInvoke.class);
/*
// ejb/0fbl
if (aroundInvoke != null) {
setAroundInvokeMethodName(method.getJavaMember().getName());
// XXX: needs to check invalid duplicated @AroundInvoke methods.
break;
}
*/
}
}
/**
* Deploys the bean.
*/
@Override
public AbstractEjbBeanManager deployServer(EjbManager ejbManager,
EjbLazyGenerator lazyGenerator)
throws ClassNotFoundException
{
AbstractEjbBeanManager manager;
if (_activationSpec != null)
manager = deployActivationSpecServer(ejbManager, lazyGenerator);
else
manager = deployJmsServer(ejbManager, lazyGenerator);
manager.setResourceList(getResourceList());
return manager;
}
private AbstractEjbBeanManager
deployJmsServer(EjbManager ejbManager,
EjbLazyGenerator lazyGenerator)
throws ClassNotFoundException
{
JmsResourceAdapter ra
= new JmsResourceAdapter(getEJBName(), _jmsActivationConfig);
JmsActivationSpec spec
= new JmsActivationSpec();
ra.setAcknowledgeMode(_acknowledgeMode);
ra.setMessageSelector(_messageSelector);
ra.setSubscriptionName(_subscriptionName);
if (_jmsActivationConfig.getMaxPoolSize() > 0)
ra.setConsumerMax(_jmsActivationConfig.getMaxPoolSize());
else
ra.setConsumerMax(getEjbContainer().getMessageConsumerMax());
return deployMessageServer(ejbManager,
getModuleName(),
lazyGenerator,
ra,
spec);
}
/**
* Deploys the bean.
*/
public AbstractEjbBeanManager
deployActivationSpecServer(EjbManager ejbManager,
EjbLazyGenerator lazyGenerator)
throws ClassNotFoundException
{
if (_activationSpec == null)
throw new ConfigException(L.l("ActivationSpec is required for ActivationSpecServer"));
String specType = _activationSpec.getClass().getName();
ResourceArchive raCfg = ResourceArchiveManager.findResourceArchive(specType);
if (raCfg == null)
throw error(L.l("'{0}' is an unknown activation-spec. Make sure the .rar file for the driver is properly installed.",
specType));
Class> raClass = raCfg.getResourceAdapterClass();
if (raClass == null)
throw error(L.l("resource-adapter class does not exist for activation-spec '{0}'. Make sure the .rar file for the driver is properly installed.",
_activationSpec.getClass().getName()));
InjectManager webBeans = InjectManager.create();
ResourceAdapter ra
= (ResourceAdapter) webBeans.getReference(raClass);
if (ra == null) {
throw error(L.l("resource-adapter '{0}' must be configured in a tag.",
raClass.getName()));
}
return deployMessageServer(ejbManager,
getModuleName(),
lazyGenerator,
ra,
_activationSpec);
}
private AnnotatedType fillClassDefaults(AnnotatedType ejbClass)
{
AnnotatedTypeImpl ejbClassImpl = AnnotatedTypeImpl.create(ejbClass);
if (!_isContainerTransaction) {
ejbClassImpl.addAnnotation(new TransactionManagementLiteral(BEAN));
}
TransactionAttribute ann
= ejbClass.getAnnotation(TransactionAttribute.class);
if (ann == null) {
// ejb/1100
ejbClassImpl.addAnnotation(new TransactionAttributeLiteral(REQUIRED));
}
return ejbClassImpl;
}
/**
* Deploys the bean.
*/
public AbstractEjbBeanManager
deployMessageServer(EjbManager ejbManager,
String moduleName,
EjbLazyGenerator lazyGenerator,
ResourceAdapter ra,
ActivationSpec spec)
throws ClassNotFoundException
{
MessageManager manager;
try {
if (spec == null)
throw new ConfigException(L.l("ActivationSpec is required for MessageServer"));
if (ra == null)
throw new ConfigException(L.l("ResourceAdapter is required for ActivationSpecServer"));
manager = new MessageManager(ejbManager,
getEJBName(),
moduleName,
getRawAnnotatedType(),
getAnnotatedType(),
lazyGenerator);
manager.setConfigLocation(getFilename(), getLine());
manager.setMappedName(getMappedName());
manager.setId(getEJBClass().getSimpleName() + "#" + getEJBName());
manager.setContainerTransaction(isContainerTransaction());
manager.setEjbClass(getEJBClass());
// XXX:
/*
Class> proxyImplClass = javaGen.loadClass(getSkeletonName());
manager.setProxyImplClass(proxyImplClass);
*/
manager.setActivationSpec(spec);
manager.setResourceAdapter(ra);
// server.setMessageListenerType(_messagingType);
// javaGen.loadClass(getEJBClass().getName());
// XXX: can't be right because of timing, i.e. must be in bind() phase
/*
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(manager.getClassLoader());
ContainerProgram initContainer = getInitProgram();
manager.setInitProgram(initContainer);
if (getServerProgram() != null)
getServerProgram().configure(manager);
} finally {
thread.setContextClassLoader(oldLoader);
}
*/
} catch (Exception e) {
throw error(e);
}
return manager;
}
public class ActivationConfig {
public void addActivationConfigProperty(ActivationConfigPropertyConfig prop)
throws NamingException
{
String name = prop.getActivationConfigPropertyName();
String value = prop.getActivationConfigPropertyValue();
EjbMessageBean.this.addActivationConfigProperty(name, value);
}
}
public static class ActivationConfigPropertyConfig {
String _name;
String _value;
public void setActivationConfigPropertyName(String name)
{
_name = name;
}
public String getActivationConfigPropertyName()
{
return _name;
}
public void setActivationConfigPropertyValue(String value)
{
_value = value;
}
public String getActivationConfigPropertyValue()
{
return _value;
}
@Override
public String toString()
{
return (getClass().getSimpleName()
+ "[" + getActivationConfigPropertyName()
+ "=" + getActivationConfigPropertyValue() + "]");
}
}
public class MessageDrivenDestination {
public void setDestinationType(String value)
throws ConfigException, NamingException
{
setMessageDestinationType(value);
}
public void setSubscriptionDurability(String durability)
{
}
public void setJndiName(JndiBuilder destination)
throws ConfigException, NamingException
{
setDestinationValue((Destination) destination.getObject());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy