0001: /*
0002: * JBoss, Home of Professional Open Source.
0003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004: * as indicated by the @author tags. See the copyright.txt file in the
0005: * distribution for a full listing of individual contributors.
0006: *
0007: * This is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU Lesser General Public License as
0009: * published by the Free Software Foundation; either version 2.1 of
0010: * the License, or (at your option) any later version.
0011: *
0012: * This software is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this software; if not, write to the Free
0019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021: */
0022: package org.jboss.ejb;
0023:
0024: import java.lang.reflect.Constructor;
0025: import java.lang.reflect.Method;
0026: import java.net.URL;
0027: import java.net.URLClassLoader;
0028: import java.util.ArrayList;
0029: import java.util.Collection;
0030: import java.util.Collections;
0031: import java.util.LinkedList;
0032: import java.util.HashMap;
0033: import java.util.Iterator;
0034: import java.util.Map;
0035: import java.util.ListIterator;
0036: import java.util.Set;
0037: import java.util.HashSet;
0038:
0039: import javax.ejb.EJBLocalHome;
0040: import javax.management.ObjectName;
0041: import javax.naming.InitialContext;
0042: import javax.naming.NamingException;
0043: import javax.security.jacc.PolicyConfiguration;
0044: import javax.security.jacc.PolicyConfigurationFactory;
0045: import javax.security.jacc.EJBMethodPermission;
0046: import javax.security.jacc.PolicyContextException;
0047: import javax.security.jacc.EJBRoleRefPermission;
0048: import javax.transaction.TransactionManager;
0049:
0050: import org.jboss.deployment.DeploymentException;
0051: import org.jboss.deployment.DeploymentInfo;
0052: import org.jboss.deployment.EARDeployerMBean;
0053: import org.jboss.logging.Logger;
0054: import org.jboss.metadata.ApplicationMetaData;
0055: import org.jboss.metadata.BeanMetaData;
0056: import org.jboss.metadata.ConfigurationMetaData;
0057: import org.jboss.metadata.EntityMetaData;
0058: import org.jboss.metadata.InvokerProxyBindingMetaData;
0059: import org.jboss.metadata.MetaData;
0060: import org.jboss.metadata.SessionMetaData;
0061: import org.jboss.metadata.XmlLoadable;
0062: import org.jboss.metadata.MethodMetaData;
0063: import org.jboss.metadata.SecurityRoleRefMetaData;
0064: import org.jboss.mx.loading.RepositoryClassLoader;
0065: import org.jboss.ejb.plugins.SecurityProxyInterceptor;
0066: import org.jboss.ejb.plugins.StatefulSessionInstancePool;
0067: import org.jboss.security.AuthenticationManager;
0068: import org.jboss.security.RealmMapping;
0069: import org.jboss.system.Registry;
0070: import org.jboss.system.ServiceControllerMBean;
0071: import org.jboss.system.ServiceMBeanSupport;
0072: import org.jboss.mx.util.MBeanProxyExt;
0073: import org.jboss.mx.util.ObjectNameFactory;
0074: import org.jboss.util.loading.DelegatingClassLoader;
0075: import org.jboss.web.WebClassLoader;
0076: import org.jboss.web.WebServiceMBean;
0077: import org.jboss.invocation.InvocationType;
0078:
0079: import org.w3c.dom.Element;
0080:
0081: /**
0082: * An EjbModule represents a collection of beans that are deployed as a
0083: * unit.
0084: *
0085: * <p>The beans may use the EjbModule to access other beans within the same
0086: * deployment unit.
0087: *
0088: * @see Container
0089: * @see EJBDeployer
0090: *
0091: * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Ãberg</a>
0092: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
0093: * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
0094: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian.Brock</a>
0095: * @author <a href="mailto:Scott.Stark@jboss.org">Scott Stark</a>
0096: * @version $Revision: 60959 $
0097: *
0098: * @jmx:mbean extends="org.jboss.system.ServiceMBean"
0099: */
0100: public class EjbModule extends ServiceMBeanSupport implements
0101: EjbModuleMBean {
0102: public static final String BASE_EJB_MODULE_NAME = "jboss.j2ee:service=EjbModule";
0103:
0104: public static final ObjectName EJB_MODULE_QUERY_NAME = ObjectNameFactory
0105: .create(BASE_EJB_MODULE_NAME + ",*");
0106:
0107: public static String DEFAULT_STATELESS_CONFIGURATION = "Default Stateless SessionBean";
0108: public static String DEFAULT_STATEFUL_CONFIGURATION = "Default Stateful SessionBean";
0109: public static String DEFAULT_ENTITY_BMP_CONFIGURATION = "Default BMP EntityBean";
0110: public static String DEFAULT_ENTITY_CMP_CONFIGURATION = "Default CMP EntityBean";
0111: public static String DEFAULT_MESSAGEDRIVEN_CONFIGURATION = "Default MesageDriven Bean";
0112:
0113: // Constants uses with container interceptor configurations
0114: public static final int BMT = 1;
0115: public static final int CMT = 2;
0116: public static final int ANY = 3;
0117:
0118: static final String BMT_VALUE = "Bean";
0119: static final String CMT_VALUE = "Container";
0120: static final String ANY_VALUE = "Both";
0121:
0122: /** Class logger. */
0123: private static final Logger log = Logger.getLogger(EjbModule.class);
0124:
0125: // Constants -----------------------------------------------------
0126:
0127: // Attributes ----------------------------------------------------
0128:
0129: /** HashMap<ejbName, Container> the containers for this deployment unit. */
0130: HashMap containers = new HashMap();
0131: /** The containers in their ApplicationMetaData ordering */
0132: LinkedList containerOrdering = new LinkedList();
0133: /** HashMap<ejbName, EJBLocalHome> of local homes */
0134: HashMap localHomes = new HashMap();
0135:
0136: /** Class loader of this deployment unit. */
0137: ClassLoader classLoader = null;
0138:
0139: /** Name of this deployment unit, url it was deployed from */
0140: final String name;
0141:
0142: private DeploymentInfo deploymentInfo;
0143:
0144: private ServiceControllerMBean serviceController;
0145:
0146: private final Map moduleData = Collections
0147: .synchronizedMap(new HashMap());
0148:
0149: private ObjectName webServiceName;
0150:
0151: private TransactionManager tm;
0152:
0153: /** Whether we are call by value */
0154: private boolean callByValue;
0155:
0156: public EjbModule(final DeploymentInfo di, TransactionManager tm,
0157: ObjectName webServiceName) {
0158: this .deploymentInfo = di;
0159: String name = deploymentInfo.url.toString();
0160: if (name.endsWith("/")) {
0161: name = name.substring(0, name.length() - 1);
0162: }
0163: this .name = name;
0164: this .tm = tm;
0165: this .webServiceName = webServiceName;
0166: }
0167:
0168: public Map getModuleDataMap() {
0169: return moduleData;
0170: }
0171:
0172: public Object getModuleData(Object key) {
0173: return moduleData.get(key);
0174: }
0175:
0176: public void putModuleData(Object key, Object value) {
0177: moduleData.put(key, value);
0178: }
0179:
0180: public void removeModuleData(Object key) {
0181: moduleData.remove(key);
0182: }
0183:
0184: /**
0185: * Add a container to this deployment unit.
0186: *
0187: * @param con
0188: */
0189: private void addContainer(Container con) throws DeploymentException {
0190: String ejbName = con.getBeanMetaData().getEjbName();
0191: if (containers.containsKey(ejbName))
0192: throw new DeploymentException(
0193: "Duplicate ejb-name. Container for " + ejbName
0194: + " already exists.");
0195: containers.put(ejbName, con);
0196: containerOrdering.add(con);
0197: con.setEjbModule(this );
0198: }
0199:
0200: /**
0201: * Remove a container from this deployment unit.
0202: *
0203: * @param con
0204: */
0205: public void removeContainer(Container con) {
0206: containers.remove(con.getBeanMetaData().getEjbName());
0207: containerOrdering.remove(con);
0208: }
0209:
0210: public void addLocalHome(Container con, EJBLocalHome localHome) {
0211: localHomes.put(con.getBeanMetaData().getEjbName(), localHome);
0212: }
0213:
0214: public void removeLocalHome(Container con) {
0215: localHomes.remove(con.getBeanMetaData().getEjbName());
0216: }
0217:
0218: public EJBLocalHome getLocalHome(Container con) {
0219: return (EJBLocalHome) localHomes.get(con.getBeanMetaData()
0220: .getEjbName());
0221: }
0222:
0223: /**
0224: * Whether the container is call by value
0225: *
0226: * @return true for call by value
0227: */
0228: public boolean isCallByValue() {
0229: return callByValue;
0230: }
0231:
0232: /**
0233: * Get a container from this deployment unit that corresponds to a given name
0234: *
0235: * @param name ejb-name name defined in ejb-jar.xml
0236: *
0237: * @return container for the named bean, or null if the container was
0238: * not found
0239: */
0240: public Container getContainer(String name) {
0241: return (Container) containers.get(name);
0242: }
0243:
0244: /**
0245: * Get all containers in this deployment unit.
0246: *
0247: * @return a collection of containers for each enterprise bean in this
0248: * deployment unit.
0249: * @jmx:managed-attribute
0250: */
0251: public Collection getContainers() {
0252: return containerOrdering;
0253: }
0254:
0255: /**
0256: * Get the class loader of this deployment unit.
0257: *
0258: * @return
0259: */
0260: public ClassLoader getClassLoader() {
0261: return classLoader;
0262: }
0263:
0264: /**
0265: * Set the class loader of this deployment unit
0266: */
0267: public void setClassLoader(ClassLoader cl) {
0268: this .classLoader = cl;
0269: }
0270:
0271: /**
0272: * Get the URL from which this deployment unit was deployed
0273: *
0274: * @return The URL from which this Application was deployed.
0275: */
0276: public URL getURL() {
0277: return deploymentInfo.url;
0278: }
0279:
0280: // Service implementation ----------------------------------------
0281:
0282: protected void createService() throws Exception {
0283: serviceController = (ServiceControllerMBean) MBeanProxyExt
0284: .create(ServiceControllerMBean.class,
0285: ServiceControllerMBean.OBJECT_NAME, server);
0286:
0287: log.debug("createService, begin");
0288:
0289: //Ask the ejb deployer whether we are call by value
0290: try {
0291: if (((Boolean) server.getAttribute(
0292: EJBDeployerMBean.OBJECT_NAME, "CallByValue"))
0293: .booleanValue())
0294: callByValue = true;
0295: } catch (Exception ignored) {
0296: log
0297: .debug(
0298: "Unable to ask the EJBDeployer whether we are call by value",
0299: ignored);
0300: }
0301:
0302: //Ask the ear deployer whether we are call by value
0303: try {
0304: if (callByValue == false
0305: && ((Boolean) server
0306: .getAttribute(EARDeployerMBean.OBJECT_NAME,
0307: "CallByValue")).booleanValue())
0308: callByValue = true;
0309: } catch (Exception ignored) {
0310: log
0311: .debug(
0312: "Unable to ask the EARDeployer whether we are call by value",
0313: ignored);
0314: }
0315:
0316: //Set up the beans in this module.
0317: try {
0318: ApplicationMetaData appMetaData = (ApplicationMetaData) deploymentInfo.metaData;
0319: Iterator beans = appMetaData.getEnterpriseBeans();
0320: String contextID = deploymentInfo.shortName;
0321: PolicyConfigurationFactory pcFactory = PolicyConfigurationFactory
0322: .getPolicyConfigurationFactory();
0323: PolicyConfiguration pc = pcFactory.getPolicyConfiguration(
0324: contextID, true);
0325: while (beans.hasNext()) {
0326: BeanMetaData bean = (BeanMetaData) beans.next();
0327: log.info("Deploying " + bean.getEjbName());
0328: Container con = createContainer(bean, deploymentInfo);
0329: con.setDeploymentInfo(deploymentInfo);
0330: addContainer(con);
0331: //@todo support overriding the context id via metadata is needed
0332: con.setJaccContextID(contextID);
0333: // Register the permissions with the JACC layer
0334: createPermissions(bean, pc);
0335: deploymentInfo.context.put(
0336: "javax.security.jacc.PolicyConfiguration", pc);
0337: // Link this to the parent PC
0338: DeploymentInfo current = deploymentInfo;
0339: while (current.parent != null)
0340: current = current.parent;
0341: PolicyConfiguration parentPC = (PolicyConfiguration) current.context
0342: .get("javax.security.jacc.PolicyConfiguration");
0343: if (parentPC != null && parentPC != pc)
0344: parentPC.linkConfiguration(pc);
0345: }
0346: pc.commit();
0347:
0348: //only one iteration should be necessary, but we won't sweat it.
0349: //2 iterations are needed by cmp...jdbc/bridge/JDBCCMRFieldBridge which
0350: //assumes persistence managers are all set up for every
0351: //bean in the relationship!
0352: ListIterator iter = containerOrdering.listIterator();
0353: while (iter.hasNext()) {
0354: Container con = (Container) iter.next();
0355: ObjectName jmxName = con.getJmxName();
0356: /* Add the container mbean to the deployment mbeans so the state
0357: of the deployment can be tracked.
0358: */
0359: server.registerMBean(con, jmxName);
0360: deploymentInfo.mbeans.add(jmxName);
0361: BeanMetaData metaData = con.getBeanMetaData();
0362: Collection depends = metaData.getDepends();
0363: serviceController.create(jmxName, depends);
0364: // We keep the hashCode around for fast creation of proxies
0365: int jmxHash = jmxName.hashCode();
0366: Registry.bind(new Integer(jmxHash), jmxName);
0367: log.debug("Bound jmxName=" + jmxName + ", hash="
0368: + jmxHash + "into Registry");
0369: }
0370: } catch (Exception e) {
0371: destroyService();
0372: throw e;
0373: } // end of try-catch
0374:
0375: }
0376:
0377: /**
0378: * The mbean Service interface <code>start</code> method calls
0379: * the start method on each contatiner, then the init method on each
0380: * container. Conversion to a different registration system with one-phase
0381: * startup is conceivable.
0382: *
0383: * @exception Exception if an error occurs
0384: */
0385: protected void startService() throws Exception {
0386: // before EntityContainer returns from the startService, its PM should be usable
0387: ListIterator iter = containerOrdering.listIterator();
0388: while (iter.hasNext()) {
0389: Container con = (Container) iter.next();
0390: if (con.getBeanMetaData().isEntity()) {
0391: ClassLoader oldCl = SecurityActions
0392: .getContextClassLoader();
0393: SecurityActions.setContextClassLoader(con
0394: .getClassLoader());
0395:
0396: try {
0397: ((EntityContainer) con).getPersistenceManager()
0398: .start();
0399: } finally {
0400: // Reset classloader
0401: SecurityActions.setContextClassLoader(oldCl);
0402: }
0403: }
0404: }
0405:
0406: iter = containerOrdering.listIterator();
0407: while (iter.hasNext()) {
0408: Container con = (Container) iter.next();
0409: log.debug("startService, starting container: "
0410: + con.getBeanMetaData().getEjbName());
0411: serviceController.start(con.getJmxName());
0412: }
0413: }
0414:
0415: /**
0416: * Stops all the containers of this application.
0417: */
0418: protected void stopService() throws Exception {
0419: ListIterator iter = containerOrdering
0420: .listIterator(containerOrdering.size());
0421: while (iter.hasPrevious()) {
0422: Container con = (Container) iter.previous();
0423: try {
0424: // The container may already be destroyed so validate metaData
0425: BeanMetaData metaData = con.getBeanMetaData();
0426: String ejbName = metaData != null ? metaData
0427: .getEjbName() : "Unknown";
0428: log
0429: .debug("stopService, stopping container: "
0430: + ejbName);
0431:
0432: serviceController.stop(con.getJmxName());
0433: } catch (Exception e) {
0434: log.error("unexpected exception stopping Container: "
0435: + con.getJmxName(), e);
0436: } // end of try-catch
0437: }
0438: }
0439:
0440: protected void destroyService() throws Exception {
0441: WebServiceMBean webServer = null;
0442: if (webServiceName != null) {
0443: webServer = (WebServiceMBean) MBeanProxyExt.create(
0444: WebServiceMBean.class, webServiceName);
0445: }
0446:
0447: ListIterator iter = containerOrdering
0448: .listIterator(containerOrdering.size());
0449: // Unegister the permissions with the JACC layer
0450: String contextID = deploymentInfo.shortName;
0451: PolicyConfigurationFactory pcFactory = PolicyConfigurationFactory
0452: .getPolicyConfigurationFactory();
0453: PolicyConfiguration pc = pcFactory.getPolicyConfiguration(
0454: contextID, true);
0455: pc.delete();
0456: while (iter.hasPrevious()) {
0457: Container con = (Container) iter.previous();
0458: ObjectName jmxName = con.getJmxName();
0459: int conState = con.getState();
0460: boolean destroyContainer = conState == CREATED
0461: || conState == STOPPED || conState == FAILED;
0462: log.debug("Looking to destroy container: " + jmxName
0463: + ", state: " + con.getStateString()
0464: + ", destroy: " + destroyContainer);
0465:
0466: // always unregister from Registry
0467: int jmxHash = jmxName.hashCode();
0468: Registry.unbind(new Integer(jmxHash));
0469:
0470: // Unregister the web classloader
0471: //Removing the wcl should probably be done in stop of the container,
0472: // but I don't want to look for errors today.
0473: if (webServer != null) {
0474: ClassLoader wcl = con.getWebClassLoader();
0475: if (wcl != null) {
0476: try {
0477: webServer.removeClassLoader(wcl);
0478: } catch (Throwable e) {
0479: log.warn("Failed to unregister webClassLoader",
0480: e);
0481: }
0482: }
0483: }
0484:
0485: // Only destroy containers that have been created or started
0486: if (destroyContainer) {
0487: try {
0488: serviceController.destroy(jmxName);
0489: log.info("Undeployed "
0490: + con.getBeanMetaData().getEjbName());
0491: } catch (Throwable e) {
0492: log.error(
0493: "unexpected exception destroying Container: "
0494: + jmxName, e);
0495: } // end of try-catch
0496: }
0497:
0498: // If the container was registered with the mbeanserver, remove it
0499: if (conState != UNREGISTERED) {
0500: try {
0501: serviceController.remove(jmxName);
0502: } catch (Throwable e) {
0503: log.error(
0504: "unexpected exception removing Container: "
0505: + jmxName, e);
0506: } // end of try-catch
0507: }
0508:
0509: // cleanup container
0510: con.setBeanMetaData(null);
0511: con.setWebClassLoader(null);
0512: con.setClassLoader(null);
0513: con.setLocalClassLoader(null);
0514: con.setEjbModule(null);
0515: con.setDeploymentInfo(null);
0516: con.setTransactionManager(null);
0517: con.setSecurityManager(null);
0518: con.setRealmMapping(null);
0519: con.setSecurityProxy(null);
0520: con.proxyFactories.clear();
0521: }
0522:
0523: this .containers.clear();
0524: this .localHomes.clear();
0525: this .containerOrdering.clear();
0526: this .moduleData.clear();
0527: this .serviceController = null;
0528: }
0529:
0530: // ******************
0531: // Container Creation
0532: // ******************
0533:
0534: private Container createContainer(BeanMetaData bean,
0535: DeploymentInfo sdi) throws Exception {
0536: ClassLoader cl = sdi.ucl;
0537: ClassLoader localCl = sdi.localCl;
0538:
0539: Container container = null;
0540: // Added message driven deployment
0541: if (bean.isMessageDriven()) {
0542: container = createMessageDrivenContainer(bean, cl, localCl);
0543: } else if (bean.isSession()) // Is session?
0544: {
0545: if (((SessionMetaData) bean).isStateless()) // Is stateless?
0546: {
0547: container = createStatelessSessionContainer(
0548: (SessionMetaData) bean, cl, localCl);
0549: } else // Stateful
0550: {
0551: container = createStatefulSessionContainer(
0552: (SessionMetaData) bean, cl, localCl);
0553: }
0554: } else // Entity
0555: {
0556: container = createEntityContainer(bean, cl, localCl);
0557: }
0558: return container;
0559: }
0560:
0561: private MessageDrivenContainer createMessageDrivenContainer(
0562: BeanMetaData bean, ClassLoader cl, ClassLoader localCl)
0563: throws Exception {
0564: // get the container configuration for this bean
0565: // a default configuration is now always provided
0566: ConfigurationMetaData conf = bean.getContainerConfiguration();
0567: // Stolen from Stateless deploy
0568: // Create container
0569: MessageDrivenContainer container = new MessageDrivenContainer();
0570: int transType = bean.isContainerManagedTx() ? CMT : BMT;
0571:
0572: initializeContainer(container, conf, bean, transType, cl,
0573: localCl);
0574: createProxyFactories(bean, container, cl);
0575: container.setInstancePool(createInstancePool(conf, cl));
0576:
0577: return container;
0578: }
0579:
0580: private StatelessSessionContainer createStatelessSessionContainer(
0581: SessionMetaData bean, ClassLoader cl, ClassLoader localCl)
0582: throws Exception {
0583: // get the container configuration for this bean
0584: // a default configuration is now always provided
0585: ConfigurationMetaData conf = bean.getContainerConfiguration();
0586: // Create container
0587: StatelessSessionContainer container = new StatelessSessionContainer();
0588: int transType = bean.isContainerManagedTx() ? CMT : BMT;
0589: initializeContainer(container, conf, bean, transType, cl,
0590: localCl);
0591: if (bean.getHome() != null || bean.getServiceEndpoint() != null) {
0592: createProxyFactories(bean, container, cl);
0593: }
0594: container.setInstancePool(createInstancePool(conf, cl));
0595:
0596: return container;
0597: }
0598:
0599: private StatefulSessionContainer createStatefulSessionContainer(
0600: SessionMetaData bean, ClassLoader cl, ClassLoader localCl)
0601: throws Exception {
0602: // get the container configuration for this bean
0603: // a default configuration is now always provided
0604: ConfigurationMetaData conf = bean.getContainerConfiguration();
0605: // Create container
0606: StatefulSessionContainer container = new StatefulSessionContainer();
0607: int transType = bean.isContainerManagedTx() ? CMT : BMT;
0608: initializeContainer(container, conf, bean, transType, cl,
0609: localCl);
0610: if (bean.getHome() != null || bean.getServiceEndpoint() != null) {
0611: createProxyFactories(bean, container, cl);
0612: }
0613: container.setInstanceCache(createInstanceCache(conf, cl));
0614: // No real instance pool, use the shadow class
0615: StatefulSessionInstancePool ip = new StatefulSessionInstancePool();
0616: ip.importXml(conf.getContainerPoolConf());
0617: container.setInstancePool(ip);
0618: // Set persistence manager
0619: container
0620: .setPersistenceManager((StatefulSessionPersistenceManager) cl
0621: .loadClass(conf.getPersistenceManager())
0622: .newInstance());
0623: //Set the bean Lock Manager
0624: container.setLockManager(createBeanLockManager(container,
0625: false, conf.getLockClass(), cl));
0626:
0627: return container;
0628: }
0629:
0630: private EntityContainer createEntityContainer(BeanMetaData bean,
0631: ClassLoader cl, ClassLoader localCl) throws Exception {
0632: // get the container configuration for this bean
0633: // a default configuration is now always provided
0634: ConfigurationMetaData conf = bean.getContainerConfiguration();
0635: // Create container
0636: EntityContainer container = new EntityContainer();
0637: int transType = CMT;
0638: initializeContainer(container, conf, bean, transType, cl,
0639: localCl);
0640: if (bean.getHome() != null) {
0641: createProxyFactories(bean, container, cl);
0642: }
0643: container.setInstanceCache(createInstanceCache(conf, cl));
0644: container.setInstancePool(createInstancePool(conf, cl));
0645: //Set the bean Lock Manager
0646: boolean reentrant = ((EntityMetaData) bean).isReentrant();
0647: BeanLockManager lockMgr = createBeanLockManager(container,
0648: reentrant, conf.getLockClass(), cl);
0649: container.setLockManager(lockMgr);
0650:
0651: // Set persistence manager
0652: if (((EntityMetaData) bean).isBMP()) {
0653: Class pmClass = cl.loadClass(conf.getPersistenceManager());
0654: EntityPersistenceManager pm = (EntityPersistenceManager) pmClass
0655: .newInstance();
0656: container.setPersistenceManager(pm);
0657: } else {
0658: // CMP takes a manager and a store
0659: org.jboss.ejb.plugins.CMPPersistenceManager persistenceManager = new org.jboss.ejb.plugins.CMPPersistenceManager();
0660:
0661: //Load the store from configuration
0662: Class pmClass = cl.loadClass(conf.getPersistenceManager());
0663: EntityPersistenceStore pm = (EntityPersistenceStore) pmClass
0664: .newInstance();
0665: persistenceManager.setPersistenceStore(pm);
0666: // Set the manager on the container
0667: container.setPersistenceManager(persistenceManager);
0668: }
0669:
0670: return container;
0671: }
0672:
0673: // **************
0674: // Helper Methods
0675: // **************
0676:
0677: /**
0678: * Perform the common steps to initializing a container.
0679: */
0680: private void initializeContainer(Container container,
0681: ConfigurationMetaData conf, BeanMetaData bean,
0682: int transType, ClassLoader cl, ClassLoader localCl)
0683: throws NamingException, DeploymentException {
0684: // Create local classloader for this container
0685: // For loading resources that must come from the local jar. Not for loading classes!
0686: container.setLocalClassLoader(new URLClassLoader(new URL[0],
0687: localCl));
0688: // Set metadata (do it *before* creating the container's WebClassLoader)
0689: container.setEjbModule(this );
0690: container.setBeanMetaData(bean);
0691:
0692: // Create the container's WebClassLoader
0693: // and register it with the web service.
0694: String webClassLoaderName = getWebClassLoader(conf, bean);
0695: log.debug("Creating WebClassLoader of class "
0696: + webClassLoaderName);
0697: WebClassLoader wcl = null;
0698: try {
0699: Class clazz = cl.loadClass(webClassLoaderName);
0700: Constructor constructor = clazz.getConstructor(new Class[] {
0701: ObjectName.class, RepositoryClassLoader.class });
0702: wcl = (WebClassLoader) constructor
0703: .newInstance(new Object[] { container.getJmxName(),
0704: cl });
0705: } catch (Exception e) {
0706: throw new DeploymentException(
0707: "Failed to create WebClassLoader of class "
0708: + webClassLoaderName + ": ", e);
0709: }
0710: if (webServiceName != null) {
0711:
0712: WebServiceMBean webServer = (WebServiceMBean) MBeanProxyExt
0713: .create(WebServiceMBean.class, webServiceName);
0714: URL[] codebase = { webServer.addClassLoader(wcl) };
0715:
0716: wcl.setWebURLs(codebase);
0717: } // end of if ()
0718: container.setWebClassLoader(wcl);
0719: // Create classloader for this container
0720: // Only used to unique the bean ENC and does not augment class loading
0721: container.setClassLoader(new DelegatingClassLoader(wcl));
0722:
0723: // Set transaction manager
0724: InitialContext iniCtx = new InitialContext();
0725: container.setTransactionManager(tm);
0726:
0727: // Set security domain manager
0728: String securityDomain = bean.getApplicationMetaData()
0729: .getSecurityDomain();
0730: String confSecurityDomain = conf.getSecurityDomain();
0731: // Default the config security to the application security manager
0732: if (confSecurityDomain == null)
0733: confSecurityDomain = securityDomain;
0734: // Check for an empty confSecurityDomain which signifies to disable security
0735: if (confSecurityDomain != null
0736: && confSecurityDomain.length() == 0)
0737: confSecurityDomain = null;
0738: if (confSecurityDomain != null) { // Either the application has a security domain or the container has security setup
0739: try {
0740: log.debug("Setting security domain from: "
0741: + confSecurityDomain);
0742: Object securityMgr = iniCtx.lookup(confSecurityDomain);
0743: AuthenticationManager ejbS = (AuthenticationManager) securityMgr;
0744: RealmMapping rM = (RealmMapping) securityMgr;
0745: container.setSecurityManager(ejbS);
0746: container.setRealmMapping(rM);
0747: } catch (NamingException e) {
0748: throw new DeploymentException(
0749: "Could not find the security-domain, name="
0750: + confSecurityDomain, e);
0751: } catch (Exception e) {
0752: throw new DeploymentException(
0753: "Invalid security-domain specified, name="
0754: + confSecurityDomain, e);
0755: }
0756: }
0757:
0758: // Load the security proxy instance if one was configured
0759: String securityProxyClassName = bean.getSecurityProxy();
0760: if (securityProxyClassName != null) {
0761: try {
0762: Class proxyClass = cl.loadClass(securityProxyClassName);
0763: Object proxy = proxyClass.newInstance();
0764: container.setSecurityProxy(proxy);
0765: log.debug("setSecurityProxy, " + proxy);
0766: } catch (Exception e) {
0767: throw new DeploymentException(
0768: "Failed to create SecurityProxy of type: "
0769: + securityProxyClassName, e);
0770: }
0771: }
0772:
0773: // Install the container interceptors based on the configuration
0774: addInterceptors(container, transType, conf
0775: .getContainerInterceptorsConf());
0776: }
0777:
0778: /**
0779: * Return the name of the WebClassLoader class for this ejb.
0780: */
0781: private static String getWebClassLoader(ConfigurationMetaData conf,
0782: BeanMetaData bmd) throws DeploymentException {
0783: String webClassLoader = null;
0784: Iterator it = bmd.getInvokerBindings();
0785: int count = 0;
0786: while (it.hasNext()) {
0787: String invoker = (String) it.next();
0788: ApplicationMetaData amd = bmd.getApplicationMetaData();
0789: InvokerProxyBindingMetaData imd = amd
0790: .getInvokerProxyBindingMetaDataByName(invoker);
0791: if (imd == null) {
0792: String msg = "Failed to find InvokerProxyBindingMetaData for: '"
0793: + invoker
0794: + "'. Check the invoker-proxy-binding-name to "
0795: + "invoker-proxy-binding/name mappings in jboss.xml";
0796: throw new DeploymentException(msg);
0797: }
0798:
0799: Element proxyFactoryConfig = imd.getProxyFactoryConfig();
0800: String webCL = MetaData.getOptionalChildContent(
0801: proxyFactoryConfig, "web-class-loader");
0802: if (webCL != null) {
0803: log.debug("Invoker " + invoker
0804: + " specified WebClassLoader class" + webCL);
0805: webClassLoader = webCL;
0806: count++;
0807: }
0808: }
0809: if (count > 1) {
0810: log.warn(count
0811: + " invokers have WebClassLoader specifications.");
0812: log.warn("Using the last specification seen ("
0813: + webClassLoader + ").");
0814: } else if (count == 0) {
0815: webClassLoader = conf.getWebClassLoader();
0816: }
0817: return webClassLoader;
0818: }
0819:
0820: /**
0821: * Given a container-interceptors element of a container-configuration,
0822: * add the indicated interceptors to the container depending on the container
0823: * transcation type and metricsEnabled flag.
0824: *
0825: *
0826: * @todo marcf: frankly the transaction type stuff makes no sense to me, we have externalized
0827: * the container stack construction in jbossxml and I don't see why or why there would be a
0828: * type missmatch on the transaction
0829: *
0830: * @param container the container instance to setup.
0831: * @param transType one of the BMT, CMT or ANY constants.
0832: * @param element the container-interceptors element from the
0833: * container-configuration.
0834: */
0835: private void addInterceptors(Container container, int transType,
0836: Element element) throws DeploymentException {
0837: // Get the interceptor stack(either jboss.xml or standardjboss.xml)
0838: Iterator interceptorElements = MetaData.getChildrenByTagName(
0839: element, "interceptor");
0840: String transTypeString = stringTransactionValue(transType);
0841: ClassLoader loader = container.getClassLoader();
0842: /* First build the container interceptor stack from interceptorElements
0843: match transType and metricsEnabled values
0844: */
0845: ArrayList istack = new ArrayList();
0846: while (interceptorElements != null
0847: && interceptorElements.hasNext()) {
0848: Element ielement = (Element) interceptorElements.next();
0849: /* Check that the interceptor is configured for the transaction mode of the bean
0850: by comparing its 'transaction' attribute to the string representation
0851: of transType
0852: FIXME: marcf, WHY???????
0853: */
0854: String transAttr = ielement.getAttribute("transaction");
0855: if (transAttr == null || transAttr.length() == 0)
0856: transAttr = ANY_VALUE;
0857: if (transAttr.equalsIgnoreCase(ANY_VALUE)
0858: || transAttr.equalsIgnoreCase(transTypeString)) { // The transaction type matches the container bean trans type, check the metricsEnabled
0859: String metricsAttr = ielement
0860: .getAttribute("metricsEnabled");
0861: boolean metricsInterceptor = metricsAttr
0862: .equalsIgnoreCase("true");
0863: try {
0864: boolean metricsEnabled = ((Boolean) server
0865: .getAttribute(EJBDeployerMBean.OBJECT_NAME,
0866: "MetricsEnabled")).booleanValue();
0867: if (metricsEnabled == false
0868: && metricsInterceptor == true) {
0869: continue;
0870: }
0871: } catch (Exception e) {
0872: throw new DeploymentException(
0873: "couldn't contace EJBDeployer!", e);
0874: } // end of try-catch
0875:
0876: String className = null;
0877: try {
0878: className = MetaData.getFirstElementContent(
0879: ielement, null);
0880: Class clazz = loader.loadClass(className);
0881: Interceptor interceptor = (Interceptor) clazz
0882: .newInstance();
0883: if (interceptor instanceof XmlLoadable) {
0884: ((XmlLoadable) interceptor).importXml(ielement);
0885: }
0886: istack.add(interceptor);
0887: } catch (ClassNotFoundException e) {
0888: log.warn("Could not load the " + className
0889: + " interceptor", e);
0890: } catch (Exception e) {
0891: log.warn("Could not load the " + className
0892: + " interceptor for this container", e);
0893: }
0894: }
0895: }
0896:
0897: if (istack.size() == 0)
0898: log
0899: .warn("There are no interceptors configured. Check the standardjboss.xml file");
0900:
0901: // Now add the interceptors to the container
0902: for (int i = 0; i < istack.size(); i++) {
0903: Interceptor interceptor = (Interceptor) istack.get(i);
0904: container.addInterceptor(interceptor);
0905: }
0906:
0907: /* If there is a security proxy associated with the container add its
0908: interceptor just before the container interceptor
0909: */
0910: if (container.getSecurityProxy() != null)
0911: container.addInterceptor(new SecurityProxyInterceptor());
0912:
0913: // Finally we add the last interceptor from the container
0914: container
0915: .addInterceptor(container.createContainerInterceptor());
0916: }
0917:
0918: private void createPermissions(BeanMetaData bean,
0919: PolicyConfiguration pc) throws PolicyContextException {
0920: // Process the method-permission MethodMetaData
0921: Iterator iter = bean.getPermissionMethods();
0922: while (iter.hasNext()) {
0923: MethodMetaData mmd = (MethodMetaData) iter.next();
0924: String[] params = null;
0925: if (mmd.isParamGiven())
0926: params = mmd.getMethodParams();
0927: String methodName = mmd.getMethodName();
0928: if (methodName != null && methodName.equals("*"))
0929: methodName = null;
0930: EJBMethodPermission p = new EJBMethodPermission(mmd
0931: .getEjbName(), methodName, mmd.getInterfaceType(),
0932: params);
0933: if (mmd.isUnchecked()) {
0934: pc.addToUncheckedPolicy(p);
0935: } else {
0936: Set roles = mmd.getRoles();
0937: Iterator riter = roles.iterator();
0938: while (riter.hasNext()) {
0939: String role = (String) riter.next();
0940: pc.addToRole(role, p);
0941: }
0942: }
0943: }
0944: // Process the exclude-list MethodMetaData
0945: iter = bean.getExcludedMethods();
0946: while (iter.hasNext()) {
0947: MethodMetaData mmd = (MethodMetaData) iter.next();
0948: String[] params = null;
0949: if (mmd.isParamGiven())
0950: params = mmd.getMethodParams();
0951: EJBMethodPermission p = new EJBMethodPermission(mmd
0952: .getEjbName(), mmd.getMethodName(), mmd
0953: .getInterfaceType(), params);
0954: pc.addToExcludedPolicy(p);
0955: }
0956: // Process the security-role-ref SecurityRoleRefMetaData
0957: iter = bean.getSecurityRoleReferences();
0958: while (iter.hasNext()) {
0959: SecurityRoleRefMetaData srrmd = (SecurityRoleRefMetaData) iter
0960: .next();
0961: EJBRoleRefPermission p = new EJBRoleRefPermission(bean
0962: .getEjbName(), srrmd.getName());
0963: pc.addToRole(srrmd.getLink(), p);
0964: }
0965: /* Special handling of stateful session bean getEJBObject due how the
0966: stateful session handles acquire the proxy by sending an invocation to
0967: the ejb container.
0968: */
0969: /*if( bean instanceof SessionMetaData )
0970: {
0971: SessionMetaData smd = (SessionMetaData) bean;
0972: if( smd.isStateful() )
0973: {
0974: EJBMethodPermission p = new EJBMethodPermission(bean.getEjbName(),
0975: "getEJBObject", "Home", null);
0976: pc.addToUncheckedPolicy(p);
0977: }
0978: }*/
0979: }
0980:
0981: /** Create any JACC permissions for the ejb methods that were not explicitly
0982: * assigned method-permission or exclude-list mappings.
0983: * @param con - the ejb container
0984: * @param bean - the bean metadata
0985: * @throws ClassNotFoundException
0986: * @throws PolicyContextException
0987: */
0988: void createMissingPermissions(Container con, BeanMetaData bean)
0989: throws ClassNotFoundException, PolicyContextException {
0990: String contextID = con.getJaccContextID();
0991: PolicyConfigurationFactory pcFactory = PolicyConfigurationFactory
0992: .getPolicyConfigurationFactory();
0993: PolicyConfiguration pc = pcFactory.getPolicyConfiguration(
0994: contextID, false);
0995: Class clazz = con.getHomeClass();
0996: // If there is no security domain mark all methods as unchecked
0997: boolean hasSecurityDomain = con.getSecurityManager() != null;
0998: boolean exclude = hasSecurityDomain ? bean
0999: .isExcludeMissingMethods() : false;
1000:
1001: if (clazz != null) {
1002: addMissingMethodPermissions(bean, exclude, clazz,
1003: InvocationType.HOME, pc);
1004: }
1005: clazz = con.getLocalHomeClass();
1006: if (clazz != null) {
1007: addMissingMethodPermissions(bean, exclude, clazz,
1008: InvocationType.LOCALHOME, pc);
1009: }
1010: clazz = con.getLocalClass();
1011: if (clazz != null) {
1012: addMissingMethodPermissions(bean, exclude, clazz,
1013: InvocationType.LOCAL, pc);
1014: }
1015: clazz = con.getRemoteClass();
1016: if (clazz != null) {
1017: addMissingMethodPermissions(bean, exclude, clazz,
1018: InvocationType.REMOTE, pc);
1019: }
1020: pc.commit();
1021: }
1022:
1023: private void getInterfaces(Class iface, HashSet tmp) {
1024: tmp.add(iface);
1025: Class[] ifaces = iface.getInterfaces();
1026: for (int n = 0; n < ifaces.length; n++) {
1027: Class iface2 = ifaces[n];
1028: tmp.add(iface2);
1029: getInterfaces(iface2, tmp);
1030: }
1031: }
1032:
1033: private void addMissingMethodPermissions(BeanMetaData bean,
1034: boolean exclude, Class iface, InvocationType type,
1035: PolicyConfiguration pc) throws PolicyContextException {
1036: String ejbName = bean.getEjbName();
1037: HashSet tmp = new HashSet();
1038: getInterfaces(iface, tmp);
1039: Class[] ifaces = new Class[tmp.size()];
1040: tmp.toArray(ifaces);
1041: for (int n = 0; n < ifaces.length; n++) {
1042: Class c = ifaces[n];
1043: Method[] methods = c.getDeclaredMethods();
1044: for (int m = 0; m < methods.length; m++) {
1045: String methodName = methods[m].getName();
1046: Class[] params = methods[m].getParameterTypes();
1047: // See if there is a method-permission
1048: if (bean.hasMethodPermission(methodName, params, type))
1049: continue;
1050: // Create a permission for the missing method-permission
1051: EJBMethodPermission p = new EJBMethodPermission(
1052: ejbName, type.toInterfaceString(), methods[m]);
1053: if (exclude)
1054: pc.addToExcludedPolicy(p);
1055: else
1056: pc.addToUncheckedPolicy(p);
1057: }
1058: }
1059: }
1060:
1061: private static String stringTransactionValue(int transType) {
1062: String transaction = ANY_VALUE;
1063: switch (transType) {
1064: case BMT:
1065: transaction = BMT_VALUE;
1066: break;
1067: case CMT:
1068: transaction = CMT_VALUE;
1069: break;
1070: }
1071: return transaction;
1072: }
1073:
1074: /**
1075: * Create all proxy factories for this ejb
1076: */
1077: private static void createProxyFactories(BeanMetaData conf,
1078: Container container, ClassLoader cl) throws Exception {
1079: Iterator it = conf.getInvokerBindings();
1080: boolean foundOne = false;
1081: while (it.hasNext()) {
1082: String invoker = (String) it.next();
1083: String jndiBinding = conf.getInvokerBinding(invoker);
1084: log.debug("creating binding for " + jndiBinding + ":"
1085: + invoker);
1086: InvokerProxyBindingMetaData imd = conf
1087: .getApplicationMetaData()
1088: .getInvokerProxyBindingMetaDataByName(invoker);
1089: EJBProxyFactory ci = null;
1090:
1091: // create a ProxyFactory instance
1092: try {
1093: ci = (EJBProxyFactory) cl.loadClass(
1094: imd.getProxyFactory()).newInstance();
1095: ci.setContainer(container);
1096: ci.setInvokerMetaData(imd);
1097: ci.setInvokerBinding(jndiBinding);
1098: if (ci instanceof XmlLoadable) {
1099: // the container invoker can load its configuration from the jboss.xml element
1100: ((XmlLoadable) ci).importXml(imd
1101: .getProxyFactoryConfig());
1102: }
1103: container.addProxyFactory(invoker, ci);
1104: foundOne = true;
1105: } catch (Exception e) {
1106: log
1107: .warn("The Container Invoker "
1108: + invoker
1109: + " (in jboss.xml or standardjboss.xml) could not be created because of "
1110: + e
1111: + " We will ignore this error, but you may miss a transport for this bean.");
1112: }
1113: }
1114: if (!foundOne) {
1115: throw new DeploymentException(
1116: "Missing or invalid Container Invokers (in jboss.xml or standardjboss.xml).");
1117: }
1118: }
1119:
1120: private static BeanLockManager createBeanLockManager(
1121: Container container, boolean reentrant, String beanLock,
1122: ClassLoader cl) throws Exception {
1123: // The bean lock manager
1124: BeanLockManager lockManager = new BeanLockManager(container);
1125:
1126: Class lockClass = null;
1127: try {
1128: lockClass = cl.loadClass(beanLock);
1129: } catch (Exception e) {
1130: throw new DeploymentException(
1131: "Missing or invalid lock class (in jboss.xml or standardjboss.xml): "
1132: + beanLock + " - " + e);
1133: }
1134:
1135: lockManager.setLockCLass(lockClass);
1136: lockManager.setReentrant(reentrant);
1137:
1138: return lockManager;
1139: }
1140:
1141: private static InstancePool createInstancePool(
1142: ConfigurationMetaData conf, ClassLoader cl)
1143: throws Exception {
1144: // Set instance pool
1145: InstancePool ip = null;
1146:
1147: try {
1148: ip = (InstancePool) cl.loadClass(conf.getInstancePool())
1149: .newInstance();
1150: } catch (Exception e) {
1151: throw new DeploymentException(
1152: "Missing or invalid Instance Pool (in jboss.xml or standardjboss.xml)",
1153: e);
1154: }
1155:
1156: if (ip instanceof XmlLoadable)
1157: ((XmlLoadable) ip).importXml(conf.getContainerPoolConf());
1158:
1159: return ip;
1160: }
1161:
1162: private static InstanceCache createInstanceCache(
1163: ConfigurationMetaData conf, ClassLoader cl)
1164: throws Exception {
1165: // Set instance cache
1166: InstanceCache ic = null;
1167:
1168: try {
1169: ic = (InstanceCache) cl.loadClass(conf.getInstanceCache())
1170: .newInstance();
1171: } catch (Exception e) {
1172: throw new DeploymentException(
1173: "Missing or invalid Instance Cache (in jboss.xml or standardjboss.xml)",
1174: e);
1175: }
1176:
1177: if (ic instanceof XmlLoadable)
1178: ((XmlLoadable) ic).importXml(conf.getContainerCacheConf());
1179:
1180: return ic;
1181: }
1182:
1183: }
1184: /*
1185: vim:ts=3:sw=3:et
1186: */
|