/* * Copyright (c) 1998-2011 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 java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; import javax.annotation.PostConstruct; import javax.ejb.Local; import javax.ejb.LocalBean; import javax.ejb.Remote; import javax.ejb.SessionSynchronization; import javax.ejb.Singleton; import javax.ejb.Stateful; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedType; import com.caucho.config.ConfigException; import com.caucho.config.Configurable; import com.caucho.config.LineConfigException; import com.caucho.config.gen.TransactionAttributeLiteral; import com.caucho.config.inject.InjectManager; import com.caucho.config.reflect.AnnotatedTypeImpl; import com.caucho.config.reflect.BaseType; import com.caucho.ejb.manager.EjbManager; import com.caucho.ejb.session.AbstractSessionManager; import com.caucho.ejb.session.SingletonManager; import com.caucho.ejb.session.StatefulManager; import com.caucho.ejb.session.StatelessManager; import com.caucho.util.L10N; /** * Configuration for an ejb entity bean. */ public class EjbSessionBean<X> extends EjbBean<X> { private static final L10N L = new L10N(EjbSessionBean.class); private Class<? extends Annotation> _sessionType; /** * Creates a new session bean configuration. */ public EjbSessionBean(EjbConfig ejbConfig, AnnotatedType<X> rawAnnType, AnnotatedType<X> annType, String ejbModuleName) { super(ejbConfig, rawAnnType, annType, ejbModuleName); } /** * Returns the kind of bean. */ @Override public String getEJBKind() { return "session"; } /** * Sets the ejb implementation class. */ @Override public void setEJBClass(Class<X> type) throws ConfigException { super.setEJBClass(type); AnnotatedType<X> ejbClass = getAnnotatedType(); Class<X> ejbJavaClass = ejbClass.getJavaClass(); if (Modifier.isAbstract(ejbJavaClass.getModifiers())) throw error(L.l( "'{0}' must not be abstract. Session bean implementations must be fully implemented.", ejbJavaClass.getName())); if (ejbClass.isAnnotationPresent(Stateless.class)) { Stateless stateless = ejbClass.getAnnotation(Stateless.class); if (getEJBName() == null && !"".equals(stateless.name())) setEJBName(stateless.name()); _sessionType = Stateless.class; } else if (ejbClass.isAnnotationPresent(Stateful.class)) { Stateful stateful = ejbClass.getAnnotation(Stateful.class); if (getEJBName() == null && !"".equals(stateful.name())) setEJBName(stateful.name()); _sessionType = Stateful.class; } if (getEJBName() == null) setEJBName(ejbJavaClass.getSimpleName()); /* * if (! ejbClass.isAssignableTo(SessionBean.class) && ! * ejbClass.isAnnotationPresent(Stateless.class) && ! * ejbClass.isAnnotationPresent(Stateful.class)) throwerror(L.l( * "'{0}' must implement SessionBean or @Stateless or @Stateful. Session beans must implement javax.ejb.SessionBean." * , ejbClass.getName())); */ // introspectSession(); } /** * Gets the session bean type. */ public Class<? extends Annotation> getSessionType() { return _sessionType; } /** * Returns true if the container handles transactions. */ @Override public boolean isContainerTransaction() { return _isContainerTransaction; } /** * Set true if the container handles transactions. */ public void setTransactionType(String type) throws ConfigException { if (type.equals("Container")) _isContainerTransaction = true; else if (type.equals("Bean")) _isContainerTransaction = false; else throw new ConfigException( L.l("'{0}' is an unknown transaction-type. transaction-type must be 'Container' or 'Bean'.", type)); } /** * Configure initialization. */ @PostConstruct public void init() throws ConfigException { super.init(); try { for (AnnotatedType<?> remoteApi : getRemoteList()) validateRemote(remoteApi); for (AnnotatedType<?> localApi : getLocalList()) validateLocal(localApi); if (getEJBClass() == null) { throw error(L.l( "'{0}' does not have a defined ejb-class. Session beans must have an ejb-class.", getEJBName())); } Class<X> ejbClass = getAnnotatedType().getJavaClass(); if (! SessionSynchronization.class.isAssignableFrom(ejbClass)) { } else if (! Stateful.class.equals(getSessionType())) { throw error(L.l( "'{0}' must not implement SessionSynchronization. Stateless session beans must not implement SessionSynchronization.", getEJBClass().getName())); } else if (! _isContainerTransaction) { throw error(L.l( "'{0}' must not implement SessionSynchronization. Session beans with Bean-managed transactions may not use SessionSynchronization.", getEJBClass().getName())); } fillClassDefaults(); } catch (LineConfigException e) { throw e; } catch (ConfigException e) { throw new LineConfigException(getLocation() + e.getMessage(), e); } } protected void fillClassDefaults() { AnnotatedTypeImpl<X> ejbClass = getAnnotatedType(); TransactionManagement tm = ejbClass.getAnnotation(TransactionManagement.class); /* if (! ejbClassImpl.isAnnotationPresent(TransactionManagement.class)) { ejbClassImpl.addAnnotation(XaAnnotation.createBeanManaged()); } */ if (tm == null || tm.value() == TransactionManagementType.CONTAINER) { TransactionAttribute ann = ejbClass.getAnnotation(TransactionAttribute.class); if (ann == null) { // ejb/1100 ejbClass.addAnnotation(new TransactionAttributeLiteral(REQUIRED)); } } } /** * Obtain and apply initialization from annotations. */ @Override public void initIntrospect() throws ConfigException { super.initIntrospect(); AnnotatedType<X> type = getAnnotatedType(); // XXX: ejb/0f78 if (type == null) return; // ejb/0j20 if (!type.isAnnotationPresent(Stateful.class) && !type.isAnnotationPresent(Stateless.class) && !type.isAnnotationPresent(Singleton.class) && !isAllowPOJO()) return; /* * TCK: ejb/0f6d: bean with local and remote interfaces if (_localHome != * null || _localList.size() != 0 || _remoteHome != null || * _remoteList.size() != 0) return; */ Class<?> ejbClass = type.getJavaClass(); ArrayList<BaseType> interfaceList = new ArrayList<BaseType>(); addInterfaces(interfaceList, ejbClass, true); Local local = type.getAnnotation(Local.class); if (local != null && local.value() != null) { _localList.clear(); for (Class<?> api : local.value()) { // XXX: grab from type? addLocal((Class) api); } } Remote remote = type.getAnnotation(Remote.class); if (remote != null && remote.value() != null) { _remoteList.clear(); for (Class<?> api : remote.value()) { // XXX: grab from type? addRemote(api); } } // if (getLocalList().size() != 0 || getRemoteList().size() != 0) { if (_localList.size() != 0 || _remoteList.size() != 0) { } else if (interfaceList.size() == 0) { // Session bean no-interface view. } else if (interfaceList.size() != 1) throw new ConfigException( L.l("'{0}' has multiple interfaces, but none are marked as @Local or @Remote.\n{1}", type.getJavaClass().getName(), interfaceList.toString())); else { addLocalType(interfaceList.get(0)); } // ioc/0312 if (type.isAnnotationPresent(LocalBean.class)) { setLocalBean(true); } else if (_localList.size() == 0) { setLocalBean(true); } } private void addInterfaces(ArrayList<BaseType> interfaceList, Class<?> ejbClass, boolean isTop) { if (ejbClass == null) return; InjectManager cdiManager = InjectManager.getCurrent(); for (Type localApi : ejbClass.getGenericInterfaces()) { BaseType type = cdiManager.createTargetBaseType(localApi); Class<?> rawClass = type.getRawClass(); Local local = rawClass.getAnnotation(Local.class); if (local != null) { addLocalType(type); continue; } javax.ejb.Remote remote = rawClass.getAnnotation(javax.ejb.Remote.class); if (remote != null || java.rmi.Remote.class.isAssignableFrom(rawClass)) { addRemoteType(type); continue; } if (rawClass.getName().equals("java.io.Serializable")) continue; if (rawClass.getName().equals("java.io.Externalizable")) continue; if (rawClass.getName().startsWith("javax.ejb")) continue; if (rawClass.getName().equals("java.rmi.Remote")) continue; if (isTop) addInterface(interfaceList, type); } // ejb/6040 // addInterfaces(interfaceList, ejbClass.getSuperclass(), false); } private void addInterface(ArrayList<BaseType> interfaceList, BaseType cl) { for (int i = interfaceList.size() - 1; i >= 0; i--) { BaseType oldClass = interfaceList.get(i); if (oldClass.isAssignableFrom(cl)) { interfaceList.set(i, cl); return; } else if (cl.isAssignableFrom(oldClass)) { return; } } interfaceList.add(cl); } /** * Deploys the bean. */ @Override public AbstractSessionManager<X> deployServer(EjbManager ejbContainer, EjbLazyGenerator<X> lazyGenerator) throws ClassNotFoundException, ConfigException { AbstractSessionManager<X> manager; if (Stateless.class.equals(getSessionType())) { manager = new StatelessManager<X>(ejbContainer, getEJBName(), getModuleName(), getRawAnnotatedType(), getAnnotatedType(), lazyGenerator); } else if (Stateful.class.equals(getSessionType())) { manager = new StatefulManager<X>(ejbContainer, getEJBName(), getModuleName(), getRawAnnotatedType(), getAnnotatedType(), lazyGenerator); } else if (Singleton.class.equals(getSessionType())) { manager = new SingletonManager<X>(ejbContainer, getEJBName(), getModuleName(), getRawAnnotatedType(), getAnnotatedType(), lazyGenerator); } else throw new IllegalStateException(String.valueOf(getSessionType())); manager.setMappedName(getMappedName()); manager.setId(getEJBModuleName() + "#" + getEJBName()); manager.setContainerTransaction(_isContainerTransaction); manager.setResourceList(getResourceList()); Thread thread = Thread.currentThread(); ClassLoader oldLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(manager.getClassLoader()); // manager.setInjectionTarget(getInjectionTarget()); // manager.setInitProgram(getInitProgram()); try { if (getServerProgram() != null) getServerProgram().configure(manager); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw ConfigException.create(e); } } finally { thread.setContextClassLoader(oldLoader); } return manager; } /** * @return Type of bean (Stateful, Stateless, etc.) */ @Override protected String getBeanType() { return getSessionType().getSimpleName(); } }