1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss.ejb;
23
24 import java.lang.reflect.Method;
25 import java.net.URL;
26 import java.security.Policy;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.LinkedList;
34 import java.util.ListIterator;
35 import java.util.Map;
36
37 import javax.ejb.EJBLocalHome;
38 import javax.management.MalformedObjectNameException;
39 import javax.management.ObjectName;
40 import javax.naming.InitialContext;
41 import javax.naming.NamingException;
42 import javax.security.jacc.EJBMethodPermission;
43 import javax.security.jacc.PolicyConfiguration;
44 import javax.security.jacc.PolicyConfigurationFactory;
45 import javax.security.jacc.PolicyContextException;
46 import javax.transaction.TransactionManager;
47
48 import org.jboss.classloading.spi.RealClassLoader;
49 import org.jboss.deployers.structure.spi.DeploymentUnit;
50 import org.jboss.deployers.vfs.spi.structure.VFSDeploymentUnit;
51 import org.jboss.deployment.DeploymentException;
52 import org.jboss.deployment.DeploymentInfo;
53 import org.jboss.ejb.plugins.SecurityProxyInterceptor;
54 import org.jboss.ejb.plugins.StatefulSessionInstancePool;
55 import org.jboss.ejb.txtimer.EJBTimerService;
56 import org.jboss.invocation.InvocationType;
57 import org.jboss.logging.Logger;
58 import org.jboss.metadata.ApplicationMetaData;
59 import org.jboss.metadata.BeanMetaData;
60 import org.jboss.metadata.ConfigurationMetaData;
61 import org.jboss.metadata.EntityMetaData;
62 import org.jboss.metadata.InvokerProxyBindingMetaData;
63 import org.jboss.metadata.MetaData;
64 import org.jboss.metadata.SessionMetaData;
65 import org.jboss.metadata.XmlLoadable;
66 import org.jboss.mx.util.MBeanProxyExt;
67 import org.jboss.mx.util.ObjectNameFactory;
68 import org.jboss.security.AuthenticationManager;
69 import org.jboss.security.ISecurityManagement;
70 import org.jboss.security.RealmMapping;
71 import org.jboss.security.SecurityConstants;
72 import org.jboss.security.SecurityUtil;
73 import org.jboss.security.authorization.PolicyRegistration;
74 import org.jboss.security.plugins.SecurityDomainContext;
75 import org.jboss.system.Registry;
76 import org.jboss.system.ServiceControllerMBean;
77 import org.jboss.system.ServiceMBeanSupport;
78 import org.jboss.tm.TransactionManagerFactory;
79 import org.jboss.util.loading.DelegatingClassLoader;
80 import org.jboss.virtual.VirtualFile;
81 import org.jboss.web.WebClassLoader;
82 import org.jboss.web.WebClassLoaderFactory;
83 import org.jboss.web.WebServiceMBean;
84 import org.w3c.dom.Element;
85
86 /**
87 * An EjbModule represents a collection of beans that are deployed as a
88 * unit.
89 *
90 * <p>The beans may use the EjbModule to access other beans within the same
91 * deployment unit.
92 *
93 * @see Container
94 * @see EJBDeployer
95 *
96 * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
97 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
98 * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
99 * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian.Brock</a>
100 * @author <a href="mailto:Scott.Stark@jboss.org">Scott Stark</a>
101 * @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
102 * @version $Revision: 73334 $
103 */
104 @SuppressWarnings("deprecation")
105 public class EjbModule
106 extends ServiceMBeanSupport
107 implements EjbModuleMBean
108 {
109 public static final String BASE_EJB_MODULE_NAME = "jboss.j2ee:service=EjbModule";
110
111 public static final ObjectName EJB_MODULE_QUERY_NAME = ObjectNameFactory.create(BASE_EJB_MODULE_NAME + ",*");
112
113 public static String DEFAULT_STATELESS_CONFIGURATION = "Default Stateless SessionBean";
114 public static String DEFAULT_STATEFUL_CONFIGURATION = "Default Stateful SessionBean";
115 public static String DEFAULT_ENTITY_BMP_CONFIGURATION = "Default BMP EntityBean";
116 public static String DEFAULT_ENTITY_CMP_CONFIGURATION = "Default CMP EntityBean";
117 public static String DEFAULT_MESSAGEDRIVEN_CONFIGURATION = "Default MesageDriven Bean";
118
119 // Constants uses with container interceptor configurations
120 public static final int BMT = 1;
121 public static final int CMT = 2;
122 public static final int ANY = 3;
123
124 static final String BMT_VALUE = "Bean";
125 static final String CMT_VALUE = "Container";
126 static final String ANY_VALUE = "Both";
127
128 /** The security management */
129 private ISecurityManagement securityManagement;
130
131 /** Class logger. */
132 private static final Logger log = Logger.getLogger(EjbModule.class);
133
134 // Constants -----------------------------------------------------
135
136 // Attributes ----------------------------------------------------
137
138 /** HashMap<ejbName, Container> the containers for this deployment unit. */
139 HashMap containers = new HashMap();
140 /** The containers in their ApplicationMetaData ordering */
141 LinkedList containerOrdering = new LinkedList();
142 /** HashMap<ejbName, EJBLocalHome> of local homes */
143 HashMap localHomes = new HashMap();
144
145 /** Class loader of this deployment unit. */
146 ClassLoader classLoader = null;
147
148 /** Name of this deployment unit, url it was deployed from */
149 final String name;
150
151 private VFSDeploymentUnit deploymentUnit;
152
153 private ServiceControllerMBean serviceController;
154
155 private final Map moduleData =
156 Collections.synchronizedMap(new HashMap());
157
158 private ObjectName webServiceName;
159
160 private TransactionManagerFactory tmFactory;
161 private EJBTimerService timerService;
162
163 /** Whether we are call by value */
164 private boolean callByValue;
165 private ApplicationMetaData appMetaData;
166
167 /**
168 * Policy Registration Bean (Holder of Authorization Policies)
169 */
170 private PolicyRegistration policyRegistration = null;
171
172 public EjbModule(final VFSDeploymentUnit unit, ApplicationMetaData metaData)
173 {
174 this.appMetaData = metaData;
175 this.deploymentUnit = unit;
176 String name = deploymentUnit.getName();
177 if (name.endsWith("/"))
178 {
179 name = name.substring(0, name.length() - 1);
180 }
181 this.name = name;
182
183 // FIXME all this deployment unit access should be replaced with deployers processing updating the metadata
184 //Ask the ejb deployer whether we are call by value
185 Boolean flag = unit.getAttachment("EJB.callByValue", Boolean.class);
186 DeploymentUnit temp = unit;
187 while (flag == null && temp != null)
188 {
189 //Ask the ear deployer whether we are call by value
190 flag = temp.getAttachment("EAR.callByValue", Boolean.class);
191 if (flag != null)
192 break;
193 temp = temp.getParent();
194 }
195 if (flag != null )
196 callByValue = flag.booleanValue();
197
198 //Set the unauthenticated identity on the metadata if absent
199 if(metaData.getUnauthenticatedPrincipal() == null)
200 {
201 String unauthenticatedPrincipal = unit.getAttachment("EJB.unauthenticatedIdentity", String.class);
202 if(unauthenticatedPrincipal == null)
203 unauthenticatedPrincipal = unit.getAttachment("EAR.unauthenticatedIdentity", String.class);
204 metaData.getJBossMetaData().setUnauthenticatedPrincipal(unauthenticatedPrincipal);
205 }
206 // Add the ApplicationMetaData for the jbossws ejb21 deployer to pickup later
207 if (unit.getAttachment(ApplicationMetaData.class) == null)
208 unit.addAttachment(ApplicationMetaData.class, metaData);
209 }
210
211 /**
212 * @deprecated DeploymentInfo is obsolete
213 */
214 public EjbModule(final DeploymentInfo di, TransactionManager tm,
215 ObjectName webServiceName)
216 {
217 this.name = "deprecated";
218 }
219
220 public void setTransactionManagerFactory(TransactionManagerFactory tm)
221 {
222 this.tmFactory = tm;
223 }
224
225 public void setSecurityManagement(ISecurityManagement sm)
226 {
227 this.securityManagement = sm;
228 }
229
230 public void setPolicyRegistration(PolicyRegistration policyRegistration)
231 {
232 this.policyRegistration = policyRegistration;
233 }
234
235 public EJBTimerService getTimerService()
236 {
237 return timerService;
238 }
239
240 public void setTimerService(EJBTimerService timerService)
241 {
242 this.timerService = timerService;
243 }
244
245 public ObjectName getWebServiceName()
246 {
247 return webServiceName;
248 }
249 public void setWebServiceName(ObjectName webServiceName)
250 {
251 this.webServiceName = webServiceName;
252 }
253
254 public Map getModuleDataMap()
255 {
256 return moduleData;
257 }
258
259 public Object getModuleData(Object key)
260 {
261 return moduleData.get(key);
262 }
263
264 public void putModuleData(Object key, Object value)
265 {
266 moduleData.put(key, value);
267 }
268
269 public void removeModuleData(Object key)
270 {
271 moduleData.remove(key);
272 }
273
274 /**
275 * Add a container to this deployment unit.
276 *
277 * @param con
278 */
279 private void addContainer(Container con)
280 throws DeploymentException
281 {
282 String ejbName = con.getBeanMetaData().getEjbName();
283 if (containers.containsKey(ejbName))
284 throw new DeploymentException("Duplicate ejb-name. Container for "
285 + ejbName + " already exists.");
286 containers.put(ejbName, con);
287 containerOrdering.add(con);
288 con.setEjbModule(this);
289 }
290
291 /**
292 * Remove a container from this deployment unit.
293 *
294 * @param con
295 */
296 public void removeContainer(Container con)
297 {
298 containers.remove(con.getBeanMetaData().getEjbName());
299 containerOrdering.remove(con);
300 }
301
302 public void addLocalHome(Container con, EJBLocalHome localHome)
303 {
304 localHomes.put(con.getBeanMetaData().getEjbName(), localHome);
305 }
306
307 public void removeLocalHome(Container con)
308 {
309 localHomes.remove(con.getBeanMetaData().getEjbName());
310 }
311
312 public EJBLocalHome getLocalHome(Container con)
313 {
314 return (EJBLocalHome) localHomes.get(con.getBeanMetaData().getEjbName());
315 }
316
317 /**
318 * Whether the container is call by value
319 *
320 * @return true for call by value
321 */
322 public boolean isCallByValue()
323 {
324 return callByValue;
325 }
326
327 /**
328 * Get a container from this deployment unit that corresponds to a given name
329 *
330 * @param name ejb-name name defined in ejb-jar.xml
331 *
332 * @return container for the named bean, or null if the container was
333 * not found
334 */
335 public Container getContainer(String name)
336 {
337 return (Container) containers.get(name);
338 }
339
340 /**
341 * Get all containers in this deployment unit.
342 *
343 * @return a collection of containers for each enterprise bean in this
344 * deployment unit.
345 * @jmx:managed-attribute
346 */
347 public Collection getContainers()
348 {
349 return containerOrdering;
350 }
351
352 /**
353 * Get the class loader of this deployment unit.
354 *
355 * @return
356 */
357 public ClassLoader getClassLoader()
358 {
359 return classLoader;
360 }
361
362 /**
363 * Set the class loader of this deployment unit
364 *
365 * @param cl
366 */
367 public void setClassLoader(ClassLoader cl)
368 {
369 this.classLoader = cl;
370 }
371
372 /**
373 * Get the URL from which this deployment unit was deployed
374 *
375 * @return The URL from which this Application was deployed.
376 */
377 public URL getURL()
378 {
379 return appMetaData.getUrl();
380 }
381
382 // Service implementation ----------------------------------------
383
384 protected void createService() throws Exception
385 {
386 serviceController = (ServiceControllerMBean)
387 MBeanProxyExt.create(ServiceControllerMBean.class,
388 ServiceControllerMBean.OBJECT_NAME,
389 server);
390
391 log.debug("createService, begin");
392
393 //Set up the beans in this module.
394 try
395 {
396 Iterator beans = appMetaData.getEnterpriseBeans();
397 String contextID = appMetaData.getJaccContextID();
398 if( contextID == null )
399 contextID = deploymentUnit.getSimpleName();
400 //appMetaData.gsetJaccContextID(contextID);
401 /*PolicyConfiguration pc = null; */
402 while (beans.hasNext())
403 {
404 BeanMetaData bean = (BeanMetaData) beans.next();
405 log.info("Deploying " + bean.getEjbName());
406 Container con = createContainer(bean, deploymentUnit);
407 addContainer(con);
408 //@todo support overriding the context id via metadata is needed
409 con.setJaccContextID(contextID);
410 }
411
412 //only one iteration should be necessary, but we won't sweat it.
413 //2 iterations are needed by cmp...jdbc/bridge/JDBCCMRFieldBridge which
414 //assumes persistence managers are all set up for every
415 //bean in the relationship!
416 ListIterator iter = containerOrdering.listIterator();
417 while( iter.hasNext() )
418 {
419 Container con = (Container) iter.next();
420 ObjectName jmxName = con.getJmxName();
421 /* Add the container mbean to the deployment mbeans so the state
422 of the deployment can be tracked.
423 */
424 server.registerMBean(con, jmxName);
425 //deploymentUnit.mbeans.add(jmxName);
426 BeanMetaData metaData = con.getBeanMetaData();
427 Collection<ObjectName> depends = new ArrayList<ObjectName>();
428 for(String dependsName : metaData.getDepends())
429 {
430 depends.add(ObjectName.getInstance(dependsName));
431 }
432 Iterator<String> invokerBindings = metaData.getInvokerBindings();
433 while (invokerBindings != null && invokerBindings.hasNext())
434 {
435 String invokerBindingName = invokerBindings.next();
436 InvokerProxyBindingMetaData ipbmd = appMetaData.getInvokerProxyBindingMetaDataByName(invokerBindingName);
437 if (ipbmd != null)
438 {
439 String invokerName = ipbmd.getInvokerMBean();
440 if (invokerName != null)
441 {
442 try
443 {
444 ObjectName invokerMBean = ObjectName.getInstance(invokerName);
445 if (depends.contains(invokerMBean) == false)
446 depends.add(invokerMBean);
447 }
448 catch (MalformedObjectNameException e)
449 {
450 log.trace("Ignored malformed invoker mbean '" + invokerName + "' " + e.toString());
451 }
452 }
453 }
454 }
455 serviceController.create(jmxName, depends);
456 // We keep the hashCode around for fast creation of proxies
457 int jmxHash = jmxName.hashCode();
458 Registry.bind(new Integer(jmxHash), jmxName);
459 log.debug("Bound jmxName=" + jmxName + ", hash=" + jmxHash + "into Registry");
460 }
461
462 //Register any available XACML Policies
463 String securityDomain = SecurityUtil.unprefixSecurityDomain(appMetaData.getSecurityDomain());
464 if(securityDomain == null)
465 securityDomain = SecurityConstants.DEFAULT_EJB_APPLICATION_POLICY; //Fallback
466 VirtualFile xacmlFile = deploymentUnit.getMetaDataFile("jboss-xacml-policy.xml");
467 if(xacmlFile != null)
468 {
469 if(policyRegistration != null)
470 {
471 policyRegistration.registerPolicy(contextID, PolicyRegistration.XACML,
472 xacmlFile.toURL());
473 }
474 }
475 }
476 catch (Exception e)
477 {
478 destroyService();
479 throw e;
480 } // end of try-catch
481
482 }
483
484 /**
485 * The mbean Service interface <code>start</code> method calls
486 * the start method on each contatiner, then the init method on each
487 * container. Conversion to a different registration system with one-phase
488 * startup is conceivable.
489 *
490 * @exception Exception if an error occurs
491 */
492 protected void startService() throws Exception
493 {
494 // before EntityContainer returns from the startService, its PM should be usable
495 ListIterator iter = containerOrdering.listIterator();
496 while( iter.hasNext() )
497 {
498 Container con = (Container) iter.next();
499 if(con.getBeanMetaData().isEntity())
500 {
501 ClassLoader oldCl = SecurityActions.getContextClassLoader();
502 SecurityActions.setContextClassLoader(con.getClassLoader());
503 con.pushENC();
504 try
505 {
506 ((EntityContainer)con).getPersistenceManager().start();
507 }
508 finally
509 {
510 con.popENC();
511 // Reset classloader
512 SecurityActions.setContextClassLoader(oldCl);
513 }
514 }
515 }
516
517 iter = containerOrdering.listIterator();
518 while( iter.hasNext() )
519 {
520 Container con = (Container) iter.next();
521 log.debug("startService, starting container: " + con.getBeanMetaData().getEjbName());
522 serviceController.start(con.getJmxName());
523 }
524 }
525
526 /**
527 * Stops all the containers of this application.
528 */
529 protected void stopService() throws Exception
530 {
531 ListIterator iter = containerOrdering.listIterator(containerOrdering.size());
532 while( iter.hasPrevious() )
533 {
534 Container con = (Container) iter.previous();
535 try
536 {
537 ObjectName jmxName = con.getJmxName();
538 // The container may already be destroyed so validate metaData
539 BeanMetaData metaData = con.getBeanMetaData();
540 String ejbName = metaData != null ? metaData.getEjbName() : "Unknown";
541 log.debug("stopService, stopping container: " + ejbName);
542
543 serviceController.stop(jmxName);
544 }
545 catch (Exception e)
546 {
547 log.error("unexpected exception stopping Container: " + con.getJmxName(), e);
548 } // end of try-catch
549 }
550 }
551
552 protected void destroyService() throws Exception
553 {
554 WebServiceMBean webServer = null;
555 if (webServiceName != null)
556 {
557 webServer =
558 (WebServiceMBean) MBeanProxyExt.create(WebServiceMBean.class,
559 webServiceName);
560 }
561 ListIterator iter = containerOrdering.listIterator(containerOrdering.size());
562 // Unegister the permissions with the JACC layer
563 String contextID = appMetaData.getJaccContextID();
564 //Unregister any xacml policies
565 if(this.policyRegistration != null)
566 {
567 policyRegistration.deRegisterPolicy(contextID, PolicyRegistration.XACML);
568 }
569
570 while ( iter.hasPrevious() )
571 {
572 Container con = (Container) iter.previous();
573 ObjectName jmxName = con.getJmxName();
574 int conState = con.getState();
575 boolean destroyContainer = true;
576 log.debug("Looking to destroy container: " + jmxName
577 + ", state: " + con.getStateString() + ", destroy: " + destroyContainer);
578
579 // always unregister from Registry
580 int jmxHash = jmxName.hashCode();
581 Registry.unbind(new Integer(jmxHash));
582
583 // Unregister the web classloader
584 //Removing the wcl should probably be done in stop of the container,
585 // but I don't want to look for errors today.
586 if (webServer != null)
587 {
588 ClassLoader wcl = con.getWebClassLoader();
589 if (wcl != null)
590 {
591 try
592 {
593 webServer.removeClassLoader(wcl);
594 }
595 catch (Throwable e)
596 {
597 log.warn("Failed to unregister webClassLoader", e);
598 }
599 }
600 }
601
602 // Only destroy containers that have been created or started
603 if( destroyContainer )
604 {
605 try
606 {
607 serviceController.destroy(jmxName);
608 serviceController.remove(jmxName);
609 log.info("Undeployed " + con.getBeanMetaData().getEjbName());
610 if( server.isRegistered(jmxName) )
611 server.unregisterMBean(jmxName);
612 }
613 catch (Throwable e)
614 {
615 log.error("unexpected exception destroying Container: " + jmxName, e);
616 } // end of try-catch
617 }
618
619
620 // cleanup container
621 con.setBeanMetaData(null);
622 con.setWebClassLoader(null);
623 con.setClassLoader(null);
624 con.setEjbModule(null);
625 con.setDeploymentInfo(null);
626 con.setTransactionManager(null);
627 con.setSecurityManager(null);
628 con.setRealmMapping(null);
629 con.setSecurityProxy(null);
630 con.setSecurityManagement(null);
631 con.setPolicyRegistration(null);
632 con.proxyFactories.clear();
633 }
634
635 this.containers.clear();
636 this.localHomes.clear();
637 this.containerOrdering.clear();
638 this.moduleData.clear();
639 this.serviceController = null;
640 }
641
642 // ******************
643 // Container Creation
644 // ******************
645
646 private Container createContainer(BeanMetaData bean, VFSDeploymentUnit unit)
647 throws Exception
648 {
649 Container container = null;
650 // Added message driven deployment
651 if (bean.isMessageDriven())
652 {
653 container = createMessageDrivenContainer(bean, unit);
654 }
655 else if (bean.isSession()) // Is session?
656 {
657 if (((SessionMetaData) bean).isStateless()) // Is stateless?
658 {
659 container = createStatelessSessionContainer((SessionMetaData) bean, unit);
660 }
661 else // Stateful
662 {
663 container = createStatefulSessionContainer((SessionMetaData) bean, unit);
664 }
665 }
666 else // Entity
667 {
668 container = createEntityContainer(bean, unit);
669 }
670
671 container.setDeploymentUnit(unit);
672
673 return container;
674 }
675
676 private MessageDrivenContainer createMessageDrivenContainer(BeanMetaData bean,
677 DeploymentUnit unit)
678 throws Exception
679 {
680 // get the container configuration for this bean
681 // a default configuration is now always provided
682 ConfigurationMetaData conf = bean.getContainerConfiguration();
683 // Stolen from Stateless deploy
684 // Create container
685 MessageDrivenContainer container = new MessageDrivenContainer();
686 int transType = bean.isContainerManagedTx() ? CMT : BMT;
687
688 initializeContainer(container, conf, bean, transType, unit);
689 createProxyFactories(bean, container);
690 container.setInstancePool(createInstancePool(conf, unit.getClassLoader()));
691
692 return container;
693 }
694
695 private StatelessSessionContainer createStatelessSessionContainer(SessionMetaData bean,
696 DeploymentUnit unit)
697 throws Exception
698 {
699 // get the container configuration for this bean
700 // a default configuration is now always provided
701 ConfigurationMetaData conf = bean.getContainerConfiguration();
702 // Create container
703 StatelessSessionContainer container = new StatelessSessionContainer();
704 int transType = bean.isContainerManagedTx() ? CMT : BMT;
705 initializeContainer(container, conf, bean, transType, unit);
706 if (bean.getHome() != null || bean.getServiceEndpoint()!=null)
707 {
708 createProxyFactories(bean, container);
709 }
710 container.setInstancePool(createInstancePool(conf, unit.getClassLoader()));
711
712 return container;
713 }
714
715 private StatefulSessionContainer createStatefulSessionContainer(SessionMetaData bean,
716 DeploymentUnit unit)
717 throws Exception
718 {
719 // get the container configuration for this bean
720 // a default configuration is now always provided
721 ConfigurationMetaData conf = bean.getContainerConfiguration();
722 // Create container
723 StatefulSessionContainer container = new StatefulSessionContainer();
724 int transType = bean.isContainerManagedTx() ? CMT : BMT;
725 initializeContainer(container, conf, bean, transType, unit);
726 if (bean.getHome() != null || bean.getServiceEndpoint()!=null)
727 {
728 createProxyFactories(bean, container);
729 }
730
731 ClassLoader cl = unit.getClassLoader();
732 container.setInstanceCache(createInstanceCache(conf, cl));
733 // No real instance pool, use the shadow class
734 StatefulSessionInstancePool ip = new StatefulSessionInstancePool();
735 ip.importXml(conf.getContainerPoolConf());
736 container.setInstancePool(ip);
737 // Set persistence manager
738 container.setPersistenceManager((StatefulSessionPersistenceManager) cl.loadClass(conf.getPersistenceManager()).newInstance());
739 //Set the bean Lock Manager
740 container.setLockManager(createBeanLockManager(container, false, conf.getLockClass(), cl));
741
742 return container;
743 }
744
745 private EntityContainer createEntityContainer(BeanMetaData bean,
746 DeploymentUnit unit)
747 throws Exception
748 {
749 // get the container configuration for this bean
750 // a default configuration is now always provided
751 ConfigurationMetaData conf = bean.getContainerConfiguration();
752 // Create container
753 EntityContainer container = new EntityContainer();
754 int transType = CMT;
755 initializeContainer(container, conf, bean, transType, unit);
756 if (bean.getHome() != null)
757 {
758 createProxyFactories(bean, container);
759 }
760
761 ClassLoader cl = unit.getClassLoader();
762 container.setInstanceCache(createInstanceCache(conf, cl));
763 container.setInstancePool(createInstancePool(conf, cl));
764 //Set the bean Lock Manager
765 boolean reentrant = ((EntityMetaData) bean).isReentrant();
766 BeanLockManager lockMgr = createBeanLockManager(container, reentrant, conf.getLockClass(), cl);
767 container.setLockManager(lockMgr);
768
769 // Set persistence manager
770 if (((EntityMetaData) bean).isBMP())
771 {
772 Class pmClass = cl.loadClass(conf.getPersistenceManager());
773 EntityPersistenceManager pm = (EntityPersistenceManager) pmClass.newInstance();
774 container.setPersistenceManager(pm);
775 }
776 else
777 {
778 // CMP takes a manager and a store
779 org.jboss.ejb.plugins.CMPPersistenceManager persistenceManager =
780 new org.jboss.ejb.plugins.CMPPersistenceManager();
781
782 //Load the store from configuration
783 Class pmClass = cl.loadClass(conf.getPersistenceManager());
784 EntityPersistenceStore pm = (EntityPersistenceStore) pmClass.newInstance();
785 persistenceManager.setPersistenceStore(pm);
786 // Set the manager on the container
787 container.setPersistenceManager(persistenceManager);
788 }
789
790 return container;
791 }
792
793 // **************
794 // Helper Methods
795 // **************
796
797 /**
798 * Perform the common steps to initializing a container.
799 */
800 private void initializeContainer(Container container,
801 ConfigurationMetaData conf,
802 BeanMetaData bean,
803 int transType,
804 DeploymentUnit unit)
805 throws NamingException, DeploymentException
806 {
807 // Create local classloader for this container
808 // For loading resources that must come from the local jar. Not for loading classes!
809 // The VFS should be used for this
810 // container.setLocalClassLoader(new URLClassLoader(new URL[0], localCl));
811 // Set metadata (do it *before* creating the container's WebClassLoader)
812 container.setEjbModule(this);
813 container.setBeanMetaData(bean);
814
815 ClassLoader unitCl = unit.getClassLoader();
816 // Create the container's WebClassLoader
817 // and register it with the web service.
818 String webClassLoaderName = getWebClassLoader(conf, bean);
819 log.debug("Creating WebClassLoader of class " + webClassLoaderName);
820 WebClassLoader wcl = null;
821 try
822 {
823 Class clazz = unitCl.loadClass(webClassLoaderName);
824 wcl = WebClassLoaderFactory.createWebClassLoader(clazz, container.getJmxName(), (RealClassLoader) unitCl);
825 }
826 catch (Exception e)
827 {
828 throw new DeploymentException(
829 "Failed to create WebClassLoader of class "
830 + webClassLoaderName + ": ", e);
831 }
832
833 if (webServiceName != null)
834 {
835 WebServiceMBean webServer =
836 (WebServiceMBean) MBeanProxyExt.create(WebServiceMBean.class,
837 webServiceName);
838 URL[] codebase = {webServer.addClassLoader(wcl)};
839
840
841 wcl.setWebURLs(codebase);
842 } // end of if ()
843
844 container.setWebClassLoader(wcl);
845 // Create classloader for this container
846 // Only used to unique the bean ENC and does not augment class loading
847 container.setClassLoader(new DelegatingClassLoader(wcl));
848
849 // Set transaction manager
850 InitialContext iniCtx = new InitialContext();
851 container.setTransactionManager(tmFactory.getTransactionManager());
852
853 // Set
854 container.setTimerService(timerService);
855
856 // Set security domain manager
857 String securityDomain = bean.getApplicationMetaData().getSecurityDomain();
858 String confSecurityDomain = conf.getSecurityDomain();
859 // Default the config security to the application security manager
860 if (confSecurityDomain == null)
861 confSecurityDomain = securityDomain;
862
863 // Check for an empty confSecurityDomain which signifies to disable security
864 if (confSecurityDomain != null && confSecurityDomain.length() == 0)
865 confSecurityDomain = null;
866
867 if (confSecurityDomain != null)
868 { // Either the application has a security domain or the container has security setup
869 try
870 {
871 String unprefixed = SecurityUtil.unprefixSecurityDomain(confSecurityDomain);
872 log.debug("Setting security domain from: " + confSecurityDomain);
873 String domainCtx = SecurityConstants.JAAS_CONTEXT_ROOT + "/" + unprefixed + "/domainContext";
874 SecurityDomainContext sdc = (SecurityDomainContext) iniCtx.lookup(domainCtx);
875 Object securityMgr = sdc.getSecurityManager();
876
877 //Object securityMgr = iniCtx.lookup(confSecurityDomain);
878 AuthenticationManager ejbS = (AuthenticationManager) securityMgr;
879 RealmMapping rM = (RealmMapping) securityMgr;
880 container.setSecurityManager(ejbS);
881 container.setRealmMapping(rM);
882
883 container.setSecurityManagement(securityManagement);
884 container.setPolicyRegistration(policyRegistration);
885
886 container.setDefaultSecurityDomain((String) unit.getAttachment("EJB.defaultSecurityDomain"));
887 container.setSecurityContextClassName((String) unit.getAttachment("EJB.securityContextClassName"));
888 }
889 catch (NamingException e)
890 {
891 throw new DeploymentException("Could not find the security-domain, name=" + confSecurityDomain, e);
892 }
893 catch (Exception e)
894 {
895 throw new DeploymentException("Invalid security-domain specified, name=" + confSecurityDomain, e);
896 }
897 }
898 else
899 {
900 log.warn("EJB Deployment has no configured security domain. " +
901 "Security will be bypassed. Please verify if this is intended. Bean=" + bean.getEjbName() + " Deployment="+unit.getName());
902 }
903
904 // Load the security proxy instance if one was configured
905 String securityProxyClassName = bean.getSecurityProxy();
906 if (securityProxyClassName != null)
907 {
908 try
909 {
910 Class proxyClass = unitCl.loadClass(securityProxyClassName);
911 Object proxy = proxyClass.newInstance();
912 container.setSecurityProxy(proxy);
913 log.debug("setSecurityProxy, " + proxy);
914 }
915 catch (Exception e)
916 {
917 throw new DeploymentException("Failed to create SecurityProxy of type: " +
918 securityProxyClassName, e);
919 }
920 }
921
922 // Install the container interceptors based on the configuration
923 addInterceptors(container, transType, conf.getContainerInterceptorsConf());
924 }
925
926 /**
927 * Return the name of the WebClassLoader class for this ejb.
928 */
929 private static String getWebClassLoader(ConfigurationMetaData conf,
930 BeanMetaData bmd)
931 throws DeploymentException
932 {
933 String webClassLoader = null;
934 Iterator it = bmd.getInvokerBindings();
935 int count = 0;
936 while (it.hasNext())
937 {
938 String invoker = (String) it.next();
939 ApplicationMetaData amd = bmd.getApplicationMetaData();
940 InvokerProxyBindingMetaData imd =
941 amd.getInvokerProxyBindingMetaDataByName(invoker);
942 if (imd == null)
943 {
944 String msg = "Failed to find InvokerProxyBindingMetaData for: '"
945 + invoker + "'. Check the invoker-proxy-binding-name to "
946 + "invoker-proxy-binding/name mappings in jboss.xml";
947 throw new DeploymentException(msg);
948 }
949
950 Element proxyFactoryConfig = imd.getProxyFactoryConfig();
951 String webCL = MetaData.getOptionalChildContent(proxyFactoryConfig,
952 "web-class-loader");
953 if (webCL != null)
954 {
955 log.debug("Invoker " + invoker
956 + " specified WebClassLoader class" + webCL);
957 webClassLoader = webCL;
958 count++;
959 }
960 }
961 if (count > 1)
962 {
963 log.warn(count + " invokers have WebClassLoader specifications.");
964 log.warn("Using the last specification seen ("
965 + webClassLoader + ").");
966 }
967 else if (count == 0)
968 {
969 webClassLoader = conf.getWebClassLoader();
970 if(webClassLoader == null)
971 webClassLoader = "org.jboss.web.WebClassLoader";
972 }
973 return webClassLoader;
974 }
975
976 /**
977 * Given a container-interceptors element of a container-configuration,
978 * add the indicated interceptors to the container depending on the container
979 * transcation type.
980 *
981 * @param container the container instance to setup.
982 * @param transType one of the BMT, CMT or ANY constants.
983 * @param element the container-interceptors element from the
984 * container-configuration.
985 */
986 private void addInterceptors(Container container,
987 int transType,
988 Element element)
989 throws DeploymentException
990 {
991 // Get the interceptor stack(either jboss.xml or standardjboss.xml)
992 Iterator interceptorElements = MetaData.getChildrenByTagName(element, "interceptor");
993 String transTypeString = stringTransactionValue(transType);
994 ClassLoader loader = container.getClassLoader();
995 /* First build the container interceptor stack from interceptorElements
996 match transType values
997 */
998 ArrayList istack = new ArrayList();
999 while (interceptorElements != null && interceptorElements.hasNext())
1000 {
1001 Element ielement = (Element) interceptorElements.next();
1002 /* Check that the interceptor is configured for the transaction mode of the bean
1003 by comparing its 'transaction' attribute to the string representation
1004 of transType
1005 */
1006 String transAttr = ielement.getAttribute("transaction");
1007 if (transAttr == null || transAttr.length() == 0)
1008 transAttr = ANY_VALUE;
1009 if (transAttr.equalsIgnoreCase(ANY_VALUE) || transAttr.equalsIgnoreCase(transTypeString))
1010 { // The transaction type matches the container bean trans type
1011
1012 String className = null;
1013 try
1014 {
1015 className = MetaData.getFirstElementContent(ielement, null);
1016 Class clazz = loader.loadClass(className);
1017 Interceptor interceptor = (Interceptor) clazz.newInstance();
1018 if (interceptor instanceof XmlLoadable)
1019 {
1020 ((XmlLoadable)interceptor).importXml(ielement);
1021 }
1022 istack.add(interceptor);
1023 }
1024 catch (ClassNotFoundException e)
1025 {
1026 log.warn("Could not load the " + className + " interceptor", e);
1027 }
1028 catch (Exception e)
1029 {
1030 log.warn("Could not load the " + className + " interceptor for this container", e);
1031 }
1032 }
1033 }
1034
1035 if (istack.size() == 0)
1036 log.warn("There are no interceptors configured. Check the standardjboss.xml file");
1037
1038 // Now add the interceptors to the container
1039 for (int i = 0; i < istack.size(); i++)
1040 {
1041 Interceptor interceptor = (Interceptor) istack.get(i);
1042 container.addInterceptor(interceptor);
1043 }
1044
1045 /* If there is a security proxy associated with the container add its
1046 interceptor just before the container interceptor
1047 */
1048 if (container.getSecurityProxy() != null)
1049 container.addInterceptor(new SecurityProxyInterceptor());
1050
1051 // Finally we add the last interceptor from the container
1052 container.addInterceptor(container.createContainerInterceptor());
1053 }
1054
1055
1056
1057 /** Create any JACC permissions for the ejb methods that were not explicitly
1058 * assigned method-permission or exclude-list mappings.
1059 * @param con - the ejb container
1060 * @param bean - the bean metadata
1061 * @throws ClassNotFoundException
1062 * @throws PolicyContextException
1063 */
1064 void createMissingPermissions(Container con, BeanMetaData bean)
1065 throws ClassNotFoundException, PolicyContextException
1066 {
1067 String contextID = con.getJaccContextID();
1068 PolicyConfigurationFactory pcFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
1069 PolicyConfiguration pc = pcFactory.getPolicyConfiguration(contextID, false);
1070 Class clazz = con.getHomeClass();
1071 // If there is no security domain mark all methods as unchecked
1072 boolean hasSecurityDomain = con.getSecurityManager() != null;
1073 boolean exclude = hasSecurityDomain ? bean.isExcludeMissingMethods() : false;
1074
1075 if( clazz != null )
1076 {
1077 addMissingMethodPermissions(bean, exclude, clazz, InvocationType.HOME, pc);
1078 }
1079 clazz = con.getLocalHomeClass();
1080 if( clazz != null )
1081 {
1082 addMissingMethodPermissions(bean, exclude, clazz, InvocationType.LOCALHOME, pc);
1083 }
1084 clazz = con.getLocalClass();
1085 if( clazz != null )
1086 {
1087 addMissingMethodPermissions(bean, exclude, clazz, InvocationType.LOCAL, pc);
1088 }
1089 clazz = con.getRemoteClass();
1090 if( clazz != null )
1091 {
1092 addMissingMethodPermissions(bean, exclude, clazz, InvocationType.REMOTE, pc);
1093 }
1094
1095 if(pc.inService() == false)
1096 pc.commit();
1097 // Allow the policy to incorporate the policy configs
1098 Policy.getPolicy().refresh();
1099 }
1100
1101 private void getInterfaces(Class iface, HashSet tmp)
1102 {
1103 tmp.add(iface);
1104 Class[] ifaces = iface.getInterfaces();
1105 for(int n = 0; n < ifaces.length; n ++)
1106 {
1107 Class iface2 = ifaces[n];
1108 tmp.add(iface2);
1109 getInterfaces(iface2, tmp);
1110 }
1111 }
1112 private void addMissingMethodPermissions(BeanMetaData bean, boolean exclude,
1113 Class iface, InvocationType type, PolicyConfiguration pc)
1114 throws PolicyContextException
1115 {
1116 String ejbName = bean.getEjbName();
1117 HashSet tmp = new HashSet();
1118 getInterfaces(iface, tmp);
1119 Class[] ifaces = new Class[tmp.size()];
1120 tmp.toArray(ifaces);
1121 for(int n = 0; n < ifaces.length; n ++)
1122 {
1123 Class c = ifaces[n];
1124 Method[] methods = c.getDeclaredMethods();
1125 for(int m = 0; m < methods.length; m ++)
1126 {
1127 String methodName = methods[m].getName();
1128 Class[] params = methods[m].getParameterTypes();
1129 // See if there is a method-permission
1130 if( bean.hasMethodPermission(methodName, params, type) )
1131 continue;
1132 // Create a permission for the missing method-permission
1133 EJBMethodPermission p = new EJBMethodPermission(ejbName,
1134 type.toInterfaceString(), methods[m]);
1135 if( exclude )
1136 pc.addToExcludedPolicy(p);
1137 else
1138 pc.addToUncheckedPolicy(p);
1139 }
1140 }
1141 }
1142
1143 private static String stringTransactionValue(int transType)
1144 {
1145 String transaction = ANY_VALUE;
1146 switch (transType)
1147 {
1148 case BMT:
1149 transaction = BMT_VALUE;
1150 break;
1151 case CMT:
1152 transaction = CMT_VALUE;
1153 break;
1154 }
1155 return transaction;
1156 }
1157
1158 /**
1159 * Create all proxy factories for this ejb
1160 */
1161 private static void createProxyFactories(BeanMetaData conf, Container container)
1162 throws Exception
1163 {
1164 ClassLoader cl = container.getClassLoader();
1165 Iterator it = conf.getInvokerBindings();
1166 boolean foundOne=false;
1167 while (it.hasNext())
1168 {
1169 String invoker = (String) it.next();
1170 String jndiBinding = conf.getInvokerBinding(invoker);
1171 log.debug("creating binding for " + jndiBinding + ":" + invoker);
1172 InvokerProxyBindingMetaData imd = conf.getApplicationMetaData().getInvokerProxyBindingMetaDataByName(invoker);
1173 EJBProxyFactory ci = null;
1174
1175 // create a ProxyFactory instance
1176 try
1177 {
1178 ci = (EJBProxyFactory) cl.loadClass(imd.getProxyFactory()).newInstance();
1179 ci.setContainer(container);
1180 ci.setInvokerMetaData(imd);
1181 ci.setInvokerBinding(jndiBinding);
1182 if (ci instanceof XmlLoadable)
1183 {
1184 // the container invoker can load its configuration from the jboss.xml element
1185 ((XmlLoadable) ci).importXml(imd.getProxyFactoryConfig());
1186 }
1187 container.addProxyFactory(invoker, ci);
1188 foundOne=true;
1189 }
1190 catch (Exception e)
1191 {
1192 log.warn("The Container Invoker "+invoker+" (in jboss.xml or standardjboss.xml) could not be created because of "+e+
1193 " We will ignore this error, but you may miss a transport for this bean.");
1194 }
1195 }
1196 if(!foundOne) {
1197 throw new DeploymentException("Missing or invalid Container Invokers (in jboss.xml or standardjboss.xml).");
1198 }
1199 }
1200
1201
1202 private static BeanLockManager createBeanLockManager(Container container, boolean reentrant, String beanLock,
1203 ClassLoader cl)
1204 throws Exception
1205 {
1206 // The bean lock manager
1207 BeanLockManager lockManager = new BeanLockManager(container);
1208
1209 Class lockClass = null;
1210 try
1211 {
1212 if(beanLock == null)
1213 beanLock = "org.jboss.ejb.plugins.lock.QueuedPessimisticEJBLock";
1214 lockClass = cl.loadClass(beanLock);
1215 }
1216 catch (Exception e)
1217 {
1218 throw new DeploymentException("Missing or invalid lock class (in jboss.xml or standardjboss.xml): " + beanLock + " - " + e);
1219 }
1220
1221 lockManager.setLockCLass(lockClass);
1222 lockManager.setReentrant(reentrant);
1223
1224 return lockManager;
1225 }
1226
1227 private static InstancePool createInstancePool(ConfigurationMetaData conf,
1228 ClassLoader cl)
1229 throws Exception
1230 {
1231 // Set instance pool
1232 InstancePool ip = null;
1233
1234 try
1235 {
1236 ip = (InstancePool) cl.loadClass(conf.getInstancePool()).newInstance();
1237 }
1238 catch (Exception e)
1239 {
1240 throw new DeploymentException("Missing or invalid Instance Pool (in jboss.xml or standardjboss.xml)", e);
1241 }
1242
1243 if (ip instanceof XmlLoadable)
1244 ((XmlLoadable) ip).importXml(conf.getContainerPoolConf());
1245
1246 return ip;
1247 }
1248
1249 private static InstanceCache createInstanceCache(ConfigurationMetaData conf,
1250 ClassLoader cl)
1251 throws Exception
1252 {
1253 // Set instance cache
1254 InstanceCache ic = null;
1255
1256 try
1257 {
1258 ic = (InstanceCache) cl.loadClass(conf.getInstanceCache()).newInstance();
1259 }
1260 catch (Exception e)
1261 {
1262 throw new DeploymentException("Missing or invalid Instance Cache (in jboss.xml or standardjboss.xml)", e);
1263 }
1264
1265 if (ic instanceof XmlLoadable)
1266 ((XmlLoadable) ic).importXml(conf.getContainerCacheConf());
1267
1268 return ic;
1269 }
1270 }
1271 /*
1272 vim:ts=3:sw=3:et
1273 */