1 /*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a 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.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.net.URL;
27 import java.rmi.MarshalException;
28 import java.security.AccessController;
29 import java.security.Policy;
30 import java.security.Principal;
31 import java.security.PrivilegedActionException;
32 import java.security.PrivilegedExceptionAction;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.Map;
37 import java.util.Set;
38
39 import javax.ejb.EJBException;
40 import javax.ejb.EJBObject;
41 import javax.ejb.TimedObject;
42 import javax.ejb.Timer;
43 import javax.ejb.TimerService;
44 import javax.ejb.spi.HandleDelegate;
45 import javax.management.MBeanException;
46 import javax.management.MalformedObjectNameException;
47 import javax.management.ObjectName;
48 import javax.naming.Context;
49 import javax.naming.InitialContext;
50 import javax.naming.LinkRef;
51 import javax.naming.NamingException;
52 import javax.naming.Reference;
53 import javax.naming.StringRefAddr;
54 import javax.transaction.TransactionManager;
55 import javax.xml.soap.SOAPMessage;
56
57 import org.jboss.deployers.vfs.spi.structure.VFSDeploymentUnit;
58 import org.jboss.deployment.DeploymentException;
59 import org.jboss.deployment.DeploymentInfo;
60 import org.jboss.ejb.plugins.local.BaseLocalProxyFactory;
61 import org.jboss.ejb.txtimer.EJBTimerService;
62 import org.jboss.ejb.txtimer.EJBTimerServiceImpl;
63 import org.jboss.invocation.Invocation;
64 import org.jboss.invocation.InvocationKey;
65 import org.jboss.invocation.InvocationStatistics;
66 import org.jboss.invocation.InvocationType;
67 import org.jboss.invocation.JBossLazyUnmarshallingException;
68 import org.jboss.invocation.MarshalledInvocation;
69 import org.jboss.logging.Logger;
70 import org.jboss.metadata.ApplicationMetaData;
71 import org.jboss.metadata.BeanMetaData;
72 import org.jboss.metadata.EjbLocalRefMetaData;
73 import org.jboss.metadata.EjbRefMetaData;
74 import org.jboss.metadata.EnvEntryBinder;
75 import org.jboss.metadata.EnvEntryMetaData;
76 import org.jboss.metadata.MessageDestinationRefMetaData;
77 import org.jboss.metadata.ResourceEnvRefMetaData;
78 import org.jboss.metadata.ResourceRefMetaData;
79 import org.jboss.metadata.javaee.spec.MessageDestinationMetaData;
80 import org.jboss.metadata.javaee.spec.ServiceReferenceMetaData;
81 import org.jboss.metadata.serviceref.ServiceReferenceHandler;
82 import org.jboss.metadata.serviceref.VirtualFileAdaptor;
83 import org.jboss.mx.util.ObjectNameConverter;
84 import org.jboss.mx.util.ObjectNameFactory;
85 import org.jboss.naming.ENCFactory;
86 import org.jboss.naming.ENCThreadLocalKey;
87 import org.jboss.naming.NonSerializableFactory;
88 import org.jboss.naming.Util;
89 import org.jboss.security.AnybodyPrincipal;
90 import org.jboss.security.AuthenticationManager;
91 import org.jboss.security.ISecurityManagement;
92 import org.jboss.security.authorization.PolicyRegistration;
93 import org.jboss.security.RealmMapping;
94 import org.jboss.security.SimplePrincipal;
95 import org.jboss.system.ServiceMBeanSupport;
96 import org.jboss.util.NestedError;
97 import org.jboss.util.NestedRuntimeException;
98 import org.jboss.wsf.spi.deployment.UnifiedVirtualFile;
99 import org.omg.CORBA.ORB;
100
101 /**
102 * This is the base class for all EJB-containers in JBoss. A Container
103 * functions as the central hub of all metadata and plugins. Through this
104 * the container plugins can get hold of the other plugins and any metadata
105 * they need.
106 *
107 * <p>The EJBDeployer creates instances of subclasses of this class
108 * and calls the appropriate initialization methods.
109 *
110 * <p>A Container does not perform any significant work, but instead delegates
111 * to the plugins to provide for all kinds of algorithmic functionality.
112 *
113 * @see EJBDeployer
114 *
115 * @author <a href="mailto:rickard.oberg@jboss.org">Rickard Oberg</a>
116 * @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a>
117 * @author <a href="mailto:Scott.Stark@jboss.org">Scott Stark</a>.
118 * @author <a href="bill@burkecentral.com">Bill Burke</a>
119 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
120 * @author <a href="mailto:christoph.jung@infor.de">Christoph G. Jung</a>
121 * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
122 * @author adrian@jboss.org
123 * @author anil.saldhana@jboss.org
124 * @version $Revision: 74152 $
125 *
126 * @jmx.mbean extends="org.jboss.system.ServiceMBean"
127 */
128 public abstract class Container extends ServiceMBeanSupport implements ContainerMBean, AllowedOperationsFlags
129 {
130 public final static String BASE_EJB_CONTAINER_NAME = "jboss.j2ee:service=EJB";
131
132 public final static ObjectName ORB_NAME = ObjectNameFactory.create("jboss:service=CorbaORB");
133
134 public final static ObjectName EJB_CONTAINER_QUERY_NAME = ObjectNameFactory.create(BASE_EJB_CONTAINER_NAME + ",*");
135
136 protected static final Method EJBOBJECT_REMOVE;
137
138 /** A reference to {@link javax.ejb.TimedObject#ejbTimeout}. */
139 protected static final Method EJB_TIMEOUT;
140
141 /** This is the application that this container is a part of */
142 protected EjbModule ejbModule;
143
144 /**
145 * This is the classloader of this container. All classes and resources that
146 * the bean uses will be loaded from here. By doing this we make the bean
147 * re-deployable
148 */
149 protected ClassLoader classLoader;
150
151 /** The class loader for remote dynamic classloading */
152 protected ClassLoader webClassLoader;
153
154 /**
155 * Externally supplied configuration data
156 */
157 private VFSDeploymentUnit unit;
158
159 /**
160 * This is the new metadata. it includes information from both ejb-jar and
161 * jboss.xml the metadata for the application can be accessed trough
162 * metaData.getApplicationMetaData()
163 */
164 protected BeanMetaData metaData;
165
166 /** This is the EnterpriseBean class */
167 protected Class beanClass;
168
169 /** This is the Home interface class */
170 protected Class homeInterface;
171
172 /** This is the Remote interface class */
173 protected Class remoteInterface;
174
175 /** The local home interface class */
176 protected Class localHomeInterface;
177
178 /** The local inteface class */
179 protected Class localInterface;
180
181 /** This is the TransactionManager */
182 protected TransactionManager tm;
183
184 /** The Security Context FQN */
185 protected String securityContextClassName;
186
187 /** Security Domain to fall back on **/
188 protected String defaultSecurityDomain;
189
190 /** SecurityManagement Instance - holder of all security managers */
191 protected ISecurityManagement securityManagement;
192
193 /** PolicyRegistration - Holds Authorization Policies */
194 protected PolicyRegistration policyRegistration;
195
196 /** This is the SecurityManager */
197 protected AuthenticationManager sm;
198
199 /** This is the realm mapping */
200 protected RealmMapping rm;
201
202 /** The custom security proxy used by the SecurityInterceptor */
203 protected Object securityProxy;
204
205 /** This is the bean lock manager that is to be used */
206 protected BeanLockManager lockManager;
207
208 /** ??? */
209 protected LocalProxyFactory localProxyFactory = new BaseLocalProxyFactory();
210
211 /** This is a cache for method permissions */
212 private HashMap<Method, Set<Principal>> methodPermissionsCache = new HashMap<Method, Set<Principal>>();
213
214 /** Maps for MarshalledInvocation mapping */
215 protected Map marshalledInvocationMapping = new HashMap();
216
217 /** ObjectName of Container */
218 private ObjectName jmxName;
219
220 /** HashMap<String, EJBProxyFactory> for the invoker bindings */
221 protected HashMap proxyFactories = new HashMap();
222
223 /** A priviledged actions for MBeanServer.invoke when running with sec mgr */
224 private MBeanServerAction serverAction = new MBeanServerAction();
225
226 /**
227 * The Proxy factory is set in the Invocation. This TL is used
228 * for methods that do not have access to the Invocation.
229 */
230 protected ThreadLocal proxyFactoryTL = new ThreadLocal();
231
232 /** The number of create invocations that have been made */
233 protected long createCount;
234
235 /** The number of create invocations that have been made */
236 protected long removeCount;
237
238 /** Time statistics for the invoke(Invocation) methods */
239 protected InvocationStatistics invokeStats = new InvocationStatistics();
240
241 /** The JACC context id for the container */
242 protected String jaccContextID;
243
244 /**
245 * Flag to denote whether a JACC configuration has been fitted for authorization
246 */
247 protected boolean isJaccEnabled = false;
248
249 protected EJBTimerService timerService;
250
251 static
252 {
253 try
254 {
255 EJBOBJECT_REMOVE = EJBObject.class.getMethod("remove", new Class[0]);
256 EJB_TIMEOUT = TimedObject.class.getMethod("ejbTimeout", new Class[] { Timer.class });
257 }
258 catch (Throwable t)
259 {
260 throw new NestedRuntimeException(t);
261 }
262 }
263
264 // Public --------------------------------------------------------
265
266 public Class getLocalClass()
267 {
268 return localInterface;
269 }
270
271 public Class getLocalHomeClass()
272 {
273 return localHomeInterface;
274 }
275
276 public Class getRemoteClass()
277 {
278 return remoteInterface;
279 }
280
281 /**
282 * this actually should be called remotehome, but for interface compliance purposes
283 * we keep it like that
284 */
285 public Class getHomeClass()
286 {
287 return homeInterface;
288 }
289
290 /**
291 * Whether the bean is call by value
292 *
293 * @return true for call by value
294 */
295 public boolean isCallByValue()
296 {
297 if (ejbModule.isCallByValue())
298 return true;
299 return metaData.isCallByValue();
300 }
301
302 /**
303 * Sets a transaction manager for this container.
304 *
305 * @see javax.transaction.TransactionManager
306 *
307 * @param tm
308 */
309 public void setTransactionManager(final TransactionManager tm)
310 {
311 this.tm = tm;
312 }
313
314 /**
315 * Returns this container's transaction manager.
316 *
317 * @return A concrete instance of javax.transaction.TransactionManager
318 */
319 public TransactionManager getTransactionManager()
320 {
321 return tm;
322 }
323
324 public void setSecurityManager(AuthenticationManager sm)
325 {
326 this.sm = sm;
327 }
328
329 public AuthenticationManager getSecurityManager()
330 {
331 return sm;
332 }
333
334 public ISecurityManagement getSecurityManagement()
335 {
336 return securityManagement;
337 }
338
339 public void setSecurityManagement(ISecurityManagement securityManagement)
340 {
341 this.securityManagement = securityManagement;
342 }
343
344 public PolicyRegistration getPolicyRegistration()
345 {
346 return policyRegistration;
347 }
348
349 public void setPolicyRegistration(PolicyRegistration policyRegistration)
350 {
351 this.policyRegistration = policyRegistration;
352 }
353
354 public String getDefaultSecurityDomain()
355 {
356 return defaultSecurityDomain;
357 }
358
359 public void setDefaultSecurityDomain(String defaultSecurityDomain)
360 {
361 this.defaultSecurityDomain = defaultSecurityDomain;
362 }
363
364 public String getSecurityContextClassName()
365 {
366 return securityContextClassName;
367 }
368
369 public void setSecurityContextClassName(String securityContextClassName)
370 {
371 this.securityContextClassName = securityContextClassName;
372 }
373
374 public BeanLockManager getLockManager()
375 {
376 return lockManager;
377 }
378
379 public void setLockManager(final BeanLockManager lockManager)
380 {
381 this.lockManager = lockManager;
382 lockManager.setContainer(this);
383 }
384
385 public void addProxyFactory(String invokerBinding, EJBProxyFactory factory)
386 {
387 proxyFactories.put(invokerBinding, factory);
388 }
389
390 public void setRealmMapping(final RealmMapping rm)
391 {
392 this.rm = rm;
393 }
394
395 public RealmMapping getRealmMapping()
396 {
397 return rm;
398 }
399
400 public void setSecurityProxy(Object proxy)
401 {
402 this.securityProxy = proxy;
403 }
404
405 public Object getSecurityProxy()
406 {
407 return securityProxy;
408 }
409
410 public EJBProxyFactory getProxyFactory()
411 {
412 EJBProxyFactory factory = (EJBProxyFactory)proxyFactoryTL.get();
413 // There's no factory thread local which means this is probably
414 // a local invocation. Just use the first (usually only)
415 // proxy factory.
416 // TODO: define a default factory in the meta data or
417 // even better, let the return over the original transport
418 // plugin the transport layer for the generated proxy
419 if (factory == null && remoteInterface != null)
420 {
421 Iterator i = proxyFactories.values().iterator();
422 if (i.hasNext())
423 factory = (EJBProxyFactory)i.next();
424 }
425 return factory;
426 }
427
428 public void setProxyFactory(Object factory)
429 {
430 proxyFactoryTL.set(factory);
431 }
432
433 public EJBProxyFactory lookupProxyFactory(String binding)
434 {
435 return (EJBProxyFactory)proxyFactories.get(binding);
436 }
437
438 /**
439 * Gets the DeploymentInfo for this Container
440 * @deprecated use DeploymentUnit accessors
441 * @return The DeploymentInfo for this Container
442 */
443 public final DeploymentInfo getDeploymentInfo()
444 {
445 return null;
446 }
447
448 /**
449 * Sets the DeploymentInfo of this Container
450 * @deprecated use DeploymentUnit accessors
451 * @param di The new DeploymentInfo to be used
452 */
453 public final void setDeploymentInfo(DeploymentInfo di)
454 {
455 }
456
457 public final VFSDeploymentUnit getDeploymentUnit()
458 {
459 return unit;
460 }
461
462 public final void setDeploymentUnit(VFSDeploymentUnit di)
463 {
464 this.unit = di;
465 }
466
467 /**
468 * Sets the application deployment unit for this container. All the bean
469 * containers within the same application unit share the same instance.
470 *
471 * @param app application for this container
472 */
473 public void setEjbModule(EjbModule app)
474 {
475 ejbModule = app;
476 }
477
478 public String getJaccContextID()
479 {
480 return jaccContextID;
481 }
482
483 public void setJaccContextID(String id)
484 {
485 jaccContextID = id;
486 }
487
488 public EJBTimerService getTimerService()
489 {
490 return timerService;
491 }
492
493 public void setTimerService(EJBTimerService timerService)
494 {
495 this.timerService = timerService;
496 }
497
498 /**
499 * Get the flag whether JACC is enabled
500 * @return
501 */
502 public boolean isJaccEnabled()
503 {
504 return isJaccEnabled;
505 }
506
507 /**
508 * Set the flag that JACC is enabled
509 *
510 * @param isJaccEnabled
511 */
512 public void setJaccEnabled(boolean isJaccEnabled)
513 {
514 this.isJaccEnabled = isJaccEnabled;
515 }
516
517 /**
518 * Gets the application deployment unit for this container. All the bean
519 * containers within the same application unit share the same instance.
520 * @jmx.managed-attribute
521 */
522 public EjbModule getEjbModule()
523 {
524 return ejbModule;
525 }
526
527 /**
528 * Gets the number of create invocations that have been made
529 * @jmx.managed-attribute
530 */
531 public long getCreateCount()
532 {
533 return createCount;
534 }
535
536 /**
537 * Gets the number of remove invocations that have been made
538 * @jmx.managed-attribute
539 */
540 public long getRemoveCount()
541 {
542 return removeCount;
543 }
544
545 /** Gets the invocation statistics collection
546 * @jmx.managed-attribute
547 */
548 public InvocationStatistics getInvokeStats()
549 {
550 return invokeStats;
551 }
552
553 /**
554 * Sets the class loader for this container. All the classes and resources
555 * used by the bean in this container will use this classloader.
556 *
557 * @param cl
558 */
559 public void setClassLoader(ClassLoader cl)
560 {
561 this.classLoader = cl;
562 }
563
564 /**
565 * Returns the classloader for this container.
566 *
567 * @return
568 */
569 public ClassLoader getClassLoader()
570 {
571 return classLoader;
572 }
573
574 /** Get the class loader for dynamic class loading via http.
575 */
576 public ClassLoader getWebClassLoader()
577 {
578 return webClassLoader;
579 }
580
581 /** Set the class loader for dynamic class loading via http.
582 */
583 public void setWebClassLoader(final ClassLoader webClassLoader)
584 {
585 this.webClassLoader = webClassLoader;
586 }
587
588 /**
589 * Sets the meta data for this container. The meta data consists of the
590 * properties found in the XML descriptors.
591 *
592 * @param metaData
593 */
594 public void setBeanMetaData(final BeanMetaData metaData)
595 {
596 this.metaData = metaData;
597 }
598
599 /**
600 * push the ENC onto the stack so that java:comp works
601 *
602 */
603 public void pushENC()
604 {
605 ENCFactory.pushContextId(getJmxName());
606 }
607
608 public void popENC()
609 {
610 ENCFactory.popContextId();
611 }
612
613 /**
614 * cleanup ENC on shutdown
615 *
616 */
617 public void cleanENC()
618 {
619 ENCFactory.getEncById().remove(getJmxName());
620 }
621
622 /** Get the components environment context
623 * @jmx.managed-attribute
624 * @return Environment Context
625 */
626 public Context getEnvContext() throws NamingException
627 {
628 pushENC();
629 try
630 {
631 return (Context)new InitialContext().lookup("java:comp/env");
632 }
633 finally
634 {
635 popENC();
636 }
637 }
638
639 /**
640 * Returns the metadata of this container.
641 *
642 * @jmx.managed-attribute
643 * @return metaData;
644 */
645 public BeanMetaData getBeanMetaData()
646 {
647 return metaData;
648 }
649
650 /**
651 * Returns the permissions for a method. (a set of roles)
652 *
653 * @return assemblyDescriptor;
654 */
655 public Set<Principal> getMethodPermissions(Method m, InvocationType iface)
656 {
657 Set<Principal> permissions;
658
659 if (methodPermissionsCache.containsKey(m))
660 {
661 permissions = (Set)methodPermissionsCache.get(m);
662 }
663 else if (m.equals(EJB_TIMEOUT))
664 {
665 // No role is required to access the ejbTimeout as this is
666 permissions = new HashSet<Principal>();
667 permissions.add(AnybodyPrincipal.ANYBODY_PRINCIPAL);
668 methodPermissionsCache.put(m, permissions);
669 }
670 else
671 {
672 String name = m.getName();
673 Class[] sig = m.getParameterTypes();
674 Set<String> roles = getBeanMetaData().getMethodPermissions(name, sig, iface);
675 permissions = new HashSet<Principal>();
676 if (roles != null)
677 {
678 for (String role : roles)
679 permissions.add(new SimplePrincipal(role));
680 }
681 methodPermissionsCache.put(m, permissions);
682 }
683
684 return permissions;
685 }
686
687 /**
688 * Returns the bean class instance of this container.
689 *
690 * @return instance of the Enterprise bean class.
691 */
692 public Class getBeanClass()
693 {
694 return beanClass;
695 }
696
697 /**
698 * Returns a new instance of the bean class or a subclass of the bean class.
699 * This factory style method is speciffically used by a container to supply
700 * an implementation of the abstract accessors in EJB2.0, but could be
701 * usefull in other situations. This method should ALWAYS be used instead
702 * of getBeanClass().newInstance();
703 *
704 * @return the new instance
705 *
706 * @see java.lang.Class#newInstance
707 */
708 public Object createBeanClassInstance() throws Exception
709 {
710 return getBeanClass().newInstance();
711 }
712
713 /**
714 * Sets the codebase of this container.
715 *
716 * @param codebase a possibly empty, but non null String with
717 * a sequence of URLs separated by spaces
718 * /
719 public void setCodebase(final String codebase)
720 {
721 if (codebase != null)
722 this.codebase = codebase;
723 }
724 */
725 /**
726 * Gets the codebase of this container.
727 *
728 * @return this container's codebase String, a sequence of URLs
729 * separated by spaces
730 * /
731 public String getCodebase()
732 {
733 return codebase;
734 }
735 */
736
737 /** Build a JMX name using the pattern jboss.j2ee:service=EJB,jndiName=[jndiName]
738 where the [jndiName] is either the bean remote home JNDI binding, or
739 the local home JNDI binding if the bean has no remote interfaces.
740 */
741 public ObjectName getJmxName()
742 {
743 if (jmxName == null)
744 {
745 BeanMetaData beanMetaData = getBeanMetaData();
746 if (beanMetaData == null)
747 {
748 throw new IllegalStateException("Container metaData is null");
749 }
750
751 String jndiName = beanMetaData.getContainerObjectNameJndiName();
752 if (jndiName == null)
753 {
754 throw new IllegalStateException("Container jndiName is null");
755 }
756
757 // The name must be escaped since the jndiName may be arbitrary
758 String name = BASE_EJB_CONTAINER_NAME + ",jndiName=" + jndiName;
759 try
760 {
761 jmxName = ObjectNameConverter.convert(name);
762 }
763 catch (MalformedObjectNameException e)
764 {
765 throw new RuntimeException("Failed to create ObjectName, msg=" + e.getMessage());
766 }
767 }
768 return jmxName;
769 }
770
771 /**
772 * Creates the single Timer Service for this container if not already created
773 *
774 * @param pKey Bean id
775 * @return Container Timer Service
776 * @throws IllegalStateException If the type of EJB is not allowed to use the
777 * timer service, or the bean class does not implement javax.ejb.TimedObject
778 *
779 * @see javax.ejb.EJBContext#getTimerService
780 *
781 * @jmx.managed-operation
782 **/
783 public TimerService getTimerService(Object pKey) throws IllegalStateException
784 {
785 if (this instanceof StatefulSessionContainer)
786 throw new IllegalStateException("Statefull Session Beans are not allowed to access the TimerService");
787
788 // Validate that the bean implements the TimedObject interface
789 if (TimedObject.class.isAssignableFrom(beanClass) == false)
790 {
791 // jbcts-381
792 return EJBTimerServiceImpl.FOR_NON_TIMED_OBJECT;
793 }
794
795 TimerService timerService = null;
796 try
797 {
798 timerService = this.timerService.createTimerService(getJmxName(), pKey, this);
799 }
800 catch (Exception e)
801 {
802 throw new EJBException("Could not create timer service", e);
803 }
804 return timerService;
805 }
806
807 /**
808 * Removes Timer Service for this container
809 *
810 * @param pKey Bean id
811 * @throws IllegalStateException If the type of EJB is not allowed to use the timer service
812 *
813 * @jmx.managed-operation
814 **/
815 public void removeTimerService(Object pKey) throws IllegalStateException
816 {
817 try
818 {
819 if (pKey != null)
820 {
821 // entity bean->remove()
822 timerService.removeTimerService(getJmxName(), pKey);
823 }
824 else
825 {
826 // container stop, we choose whether active timers
827 // should be persisted (default), or not (legacy)
828 timerService.removeTimerService(getJmxName(), getBeanMetaData().getTimerPersistence());
829 }
830 }
831 catch (Exception e)
832 {
833 log.error("Could not remove timer service", e);
834 }
835 }
836
837 /**
838 * Restore any timers previously persisted for this container
839 */
840 protected void restoreTimers()
841 {
842 try
843 {
844 // TODO: this name needs to be externalized
845 // pass to the ejb timer service the container ObjectName
846 timerService.restoreTimers(getServiceName(), getClassLoader());
847 }
848 catch (Exception e)
849 {
850 log.warn("Could not restore ejb timers", e);
851 }
852 }
853
854 /**
855 * The EJBDeployer calls this method. The EJBDeployer has set
856 * all the plugins and interceptors that this bean requires and now proceeds
857 * to initialize the chain. The method looks for the standard classes in
858 * the URL, sets up the naming environment of the bean. The concrete
859 * container classes should override this method to introduce
860 * implementation specific initialization behaviour.
861 *
862 * @throws Exception if loading the bean class failed
863 * (ClassNotFoundException) or setting up "java:"
864 * naming environment failed (DeploymentException)
865 */
866 protected void createService() throws Exception
867 {
868 // Acquire classes from CL
869 beanClass = classLoader.loadClass(metaData.getEjbClass());
870
871 if (metaData.getLocalHome() != null)
872 localHomeInterface = classLoader.loadClass(metaData.getLocalHome());
873 if (metaData.getLocal() != null)
874 localInterface = classLoader.loadClass(metaData.getLocal());
875
876 localProxyFactory.setContainer(this);
877 localProxyFactory.create();
878 if (localHomeInterface != null)
879 ejbModule.addLocalHome(this, localProxyFactory.getEJBLocalHome());
880 ejbModule.createMissingPermissions(this, metaData);
881 // Allow the policy to incorporate the policy configs
882 Policy.getPolicy().refresh();
883 }
884
885 /**
886 * A default implementation of starting the container service.
887 * The container registers it's dynamic MBean interface in the JMX base.
888 *
889 * The concrete container classes should override this method to introduce
890 * implementation specific start behaviour.
891 *
892 * todo implement the service lifecycle methods in an xmbean interceptor so
893 * non lifecycle managed ops are blocked when mbean is not started.
894 *
895 * @throws Exception An exception that occured during start
896 */
897 protected void startService() throws Exception
898 {
899 // Setup "java:comp/env" namespace
900 setupEnvironment();
901
902 localProxyFactory.start();
903 }
904
905 /**
906 * A default implementation of stopping the container service (no-op). The
907 * concrete container classes should override this method to introduce
908 * implementation specific stop behaviour.
909 */
910 protected void stopService() throws Exception
911 {
912 localProxyFactory.stop();
913 removeTimerService(null);
914 teardownEnvironment();
915 }
916
917 /**
918 * A default implementation of destroying the container service (no-op).
919 * The concrete container classes should override this method to introduce
920 * implementation specific destroy behaviour.
921 */
922 protected void destroyService() throws Exception
923 {
924 cleanENC();
925 localProxyFactory.destroy();
926 ejbModule.removeLocalHome(this);
927
928 beanClass = null;
929 homeInterface = null;
930 remoteInterface = null;
931 localHomeInterface = null;
932 localInterface = null;
933 methodPermissionsCache.clear();
934 // InvocationStatistics holds refs to Methods from
935 // application classes, so to avoid a classloader
936 // leak, lets not just resetStats() but also replace
937 // the object
938 invokeStats.resetStats(); // in case someone else has a ref
939 invokeStats = new InvocationStatistics();
940 marshalledInvocationMapping.clear();
941 }
942
943 /**
944 * This method is called when a method call comes
945 * in on the Home object. The Container forwards this call to the
946 * interceptor chain for further processing.
947 *
948 * @param mi the object holding all info about this invocation
949 * @return the result of the home invocation
950 *
951 * @throws Exception
952 */
953 public abstract Object internalInvokeHome(Invocation mi) throws Exception;
954
955 /**
956 * This method is called when a method call comes
957 * in on an EJBObject. The Container forwards this call to the interceptor
958 * chain for further processing.
959 */
960 public abstract Object internalInvoke(Invocation mi) throws Exception;
961
962 abstract Interceptor createContainerInterceptor();
963
964 public abstract void addInterceptor(Interceptor in);
965
966 /** The detached invoker operation.
967 *
968 * @jmx.managed-operation
969 *
970 * @param mi - the method invocation context
971 * @return the value of the ejb invocation
972 * @throws Exception on error
973 */
974 public Object invoke(Invocation mi) throws Exception
975 {
976 ClassLoader callerClassLoader = SecurityActions.getContextClassLoader();
977 long start = System.currentTimeMillis();
978 Method m = null;
979
980 Object type = null;
981 String contextID = getJaccContextID();
982 try
983 {
984 pushENC();
985
986 // JBAS-3732 - Remove classloader.equals optimization
987 SecurityActions.setContextClassLoader(this.classLoader);
988
989 // Set the JACC context id
990 mi.setValue(InvocationKey.JACC_CONTEXT_ID, contextID);
991 contextID = SecurityActions.setContextID(contextID);
992 // Set the standard JACC policy context handler data is not a SEI msg
993 if (mi.getType() != InvocationType.SERVICE_ENDPOINT)
994 {
995 EJBArgsPolicyContextHandler.setArgs(mi.getArguments());
996 }
997 else
998 {
999 SOAPMessage msg = (SOAPMessage)mi.getValue(InvocationKey.SOAP_MESSAGE);
1000 SOAPMsgPolicyContextHandler.setMessage(msg);
1001 }
1002 // Set custom JACC policy handlers
1003 BeanMetaDataPolicyContextHandler.setMetaData(this.getBeanMetaData());
1004
1005 // Check against home, remote, localHome, local, getHome,
1006 // getRemote, getLocalHome, getLocal
1007 type = mi.getType();
1008
1009 // stat gathering: concurrent calls
1010 this.invokeStats.callIn();
1011
1012 if (type == InvocationType.REMOTE || type == InvocationType.LOCAL ||
1013 // web service calls come in as "ordinary" application invocations
1014 type == InvocationType.SERVICE_ENDPOINT)
1015 {
1016 if (mi instanceof MarshalledInvocation)
1017 {
1018 ((MarshalledInvocation)mi).setMethodMap(marshalledInvocationMapping);
1019
1020 if (log.isTraceEnabled())
1021 {
1022 log.trace("METHOD REMOTE INVOKE " + mi.getObjectName() + "||" + mi.getMethod().getName() + "||");
1023 }
1024 }
1025
1026 m = mi.getMethod();
1027
1028 Object obj = internalInvoke(mi);
1029 return obj;
1030 }
1031 else if (type == InvocationType.HOME || type == InvocationType.LOCALHOME)
1032 {
1033 if (mi instanceof MarshalledInvocation)
1034 {
1035
1036 ((MarshalledInvocation)mi).setMethodMap(marshalledInvocationMapping);
1037
1038 if (log.isTraceEnabled())
1039 {
1040 log.trace("METHOD HOME INVOKE " + mi.getObjectName() + "||" + mi.getMethod().getName() + "||" + mi.getArguments().toString());
1041 }
1042 }
1043 m = mi.getMethod();
1044
1045 Object obj = internalInvokeHome(mi);
1046 return obj;
1047 }
1048 else
1049 {
1050 throw new MBeanException(new IllegalArgumentException("Unknown invocation type: " + type));
1051 }
1052 }
1053 /**
1054 * Having to catch this exception here in case can not
1055 * unmarshall arguments, values, etc. Then, convert to
1056 * UnmarshalException as defined by spec (JBAS-2999)
1057 */
1058 catch (JBossLazyUnmarshallingException e)
1059 {
1060 InvocationType calltype = mi.getType();
1061 boolean isLocal = calltype == InvocationType.LOCAL || calltype == InvocationType.LOCALHOME;
1062
1063 // handle unmarshalling exception which should only come if problem unmarshalling
1064 // invocation payload, arguments, or value on remote end.
1065 if (isLocal)
1066 {
1067 throw new EJBException("UnmarshalException", e);
1068 }
1069 else
1070 {
1071 throw new MarshalException("MarshalException", e);
1072 }
1073 }
1074 finally
1075 {
1076 if (m != null)
1077 {
1078 long end = System.currentTimeMillis();
1079 long elapsed = end - start;
1080 this.invokeStats.updateStats(m, elapsed);
1081 }
1082
1083 // stat gathering: concurrent calls
1084 this.invokeStats.callOut();
1085
1086 popENC();
1087
1088 // Restore the incoming class loader
1089 SecurityActions.setContextClassLoader(callerClassLoader);
1090
1091 // Restore the incoming context id
1092 contextID = SecurityActions.setContextID(contextID);
1093
1094 if (mi.getType() == InvocationType.SERVICE_ENDPOINT)
1095 {
1096 // Remove msg from ThreadLocal to prevent leakage into the thread pool
1097 SOAPMsgPolicyContextHandler.setMessage(null);
1098 }
1099 else
1100 {
1101 // Remove args from ThreadLocal to prevent leakage into the thread pool
1102 EJBArgsPolicyContextHandler.setArgs(null);
1103 }
1104
1105 // Remove metadata from ThreadLocal to prevent leakage into the thread pool
1106 BeanMetaDataPolicyContextHandler.setMetaData(null);
1107 }
1108 }
1109
1110 // Private -------------------------------------------------------
1111
1112 /**
1113 * This method sets up the naming environment of the bean.
1114 * We create the java:comp/env namespace with properties, EJB-References,
1115 * and DataSource ressources.
1116 */
1117 private void setupEnvironment() throws Exception
1118 {
1119 BeanMetaData beanMetaData = getBeanMetaData();
1120
1121 // debug
1122 log.debug("Begin java:comp/env for EJB: " + beanMetaData.getEjbName());
1123 ClassLoader tcl = SecurityActions.getContextClassLoader();
1124 log.debug("TCL: " + tcl);
1125
1126 ORB orb = null;
1127 HandleDelegate hd = null;
1128 try
1129 {
1130 orb = (ORB)server.getAttribute(ORB_NAME, "ORB");
1131 hd = (HandleDelegate)server.getAttribute(ORB_NAME, "HandleDelegate");
1132 }
1133 catch (Throwable t)
1134 {
1135 log.debug("Unable to retrieve orb" + t.toString());
1136 }
1137
1138 // Since the BCL is already associated with this thread we can start
1139 // using the java: namespace directly
1140 Context ctx = (Context)new InitialContext().lookup("java:comp");
1141 Object id = ENCFactory.getCurrentId();
1142 log.debug("Using java:comp using id=" + id);
1143
1144 // Bind the orb
1145 if (orb != null)
1146 {
1147 NonSerializableFactory.rebind(ctx, "ORB", orb);
1148 log.debug("Bound java:comp/ORB for EJB: " + getBeanMetaData().getEjbName());
1149
1150 NonSerializableFactory.rebind(ctx, "HandleDelegate", hd);
1151 log.debug("Bound java:comp/HandleDelegate for EJB: " + getBeanMetaData().getEjbName());
1152 }
1153
1154 // JTA links
1155 ctx.bind("TransactionSynchronizationRegistry", new LinkRef("java:TransactionSynchronizationRegistry"));
1156 log.debug("Linked java:comp/TransactionSynchronizationRegistry to JNDI name: java:TransactionSynchronizationRegistry");
1157
1158 Context envCtx = ctx.createSubcontext("env");
1159
1160 // Bind environment properties
1161 {
1162 Iterator i = beanMetaData.getEnvironmentEntries();
1163 while (i.hasNext())
1164 {
1165 EnvEntryMetaData entry = (EnvEntryMetaData)i.next();
1166 log.debug("Binding env-entry: " + entry.getName() + " of type: " + entry.getType() + " to value:" + entry.getValue());
1167
1168 EnvEntryBinder.bindEnvEntry(envCtx, entry);
1169 }
1170 }
1171
1172 // Bind EJB references
1173 {
1174 Iterator i = beanMetaData.getEjbReferences();
1175 while (i.hasNext())
1176 {
1177 EjbRefMetaData ref = (EjbRefMetaData)i.next();
1178 log.debug("Binding an EJBReference " + ref.getName());
1179
1180 if (ref.getLink() != null)
1181 {
1182 // Internal link
1183 String linkName = ref.getLink();
1184 String jndiName = ref.getJndiName();
1185 log.debug("Binding " + ref.getName() + " to ejb-link: " + linkName + " -> " + jndiName);
1186
1187 if (jndiName == null)
1188 {
1189 String msg = "Failed to resolve ejb-link: " + linkName + " from ejb-ref: " + ref.getName() + " in ejb: " + beanMetaData.getEjbName();
1190 throw new DeploymentException(msg);
1191 }
1192
1193 Util.bind(envCtx, ref.getName(), new LinkRef(jndiName));
1194
1195 }
1196 else
1197 {
1198 // Get the invoker specific ejb-ref mappings
1199 Iterator it = beanMetaData.getInvokerBindings();
1200 Reference reference = null;
1201 while (it.hasNext())
1202 {
1203 String invokerBinding = (String)it.next();
1204 // Check for an invoker level jndi-name
1205 String name = ref.getInvokerBinding(invokerBinding);
1206 // Check for an global jndi-name
1207 if (name == null)
1208 name = ref.getJndiName();
1209 if (name == null)
1210 {
1211 throw new DeploymentException("ejb-ref " + ref.getName() + ", expected either ejb-link in ejb-jar.xml or " + "jndi-name in jboss.xml");
1212 }
1213
1214 StringRefAddr addr = new StringRefAddr(invokerBinding, name);
1215 log.debug("adding " + invokerBinding + ":" + name + " to Reference");
1216
1217 if (reference == null)
1218 {
1219 reference = new Reference("javax.naming.LinkRef", ENCThreadLocalKey.class.getName(), null);
1220 }
1221 reference.add(addr);
1222 }
1223
1224 // If there were invoker bindings create bind the reference
1225 if (reference != null)
1226 {
1227 if (ref.getJndiName() != null)
1228 {
1229 // Add default for the bean level ejb-ref/jndi-name
1230 StringRefAddr addr = new StringRefAddr("default", ref.getJndiName());
1231 reference.add(addr);
1232 }
1233 if (reference.size() == 1 && reference.get("default") == null)
1234 {
1235 /* There is only one invoker binding and its not default so
1236 create a default binding to allow the link to have a value
1237 when accessed without an invoker active.
1238 */
1239 StringRefAddr addr = (StringRefAddr)reference.get(0);
1240 String target = (String)addr.getContent();
1241 StringRefAddr addr1 = new StringRefAddr("default", target);
1242 reference.add(addr1);
1243 }
1244 Util.bind(envCtx, ref.getName(), reference);
1245 }
1246 else
1247 {
1248 // Bind the bean level ejb-ref/jndi-name
1249 if (ref.getJndiName() == null)
1250 {
1251 throw new DeploymentException("ejb-ref " + ref.getName() + ", expected either ejb-link in ejb-jar.xml " + "or jndi-name in jboss.xml");
1252 }
1253 Util.bind(envCtx, ref.getName(), new LinkRef(ref.getJndiName()));
1254 }
1255 }
1256 }
1257 }
1258
1259 // Bind Local EJB references
1260 {
1261 Iterator i = beanMetaData.getEjbLocalReferences();
1262 while (i.hasNext())
1263 {
1264 EjbLocalRefMetaData ref = (EjbLocalRefMetaData)i.next();
1265 String refName = ref.getName();
1266 log.debug("Binding an EJBLocalReference " + ref.getName());
1267
1268 if (ref.getLink() != null)
1269 {
1270 // Internal link
1271 log.debug("Binding " + refName + " to bean source: " + ref.getLink());
1272
1273 String jndiName = ref.getJndiName();
1274
1275 Util.bind(envCtx, ref.getName(), new LinkRef(jndiName));
1276 }
1277 else
1278 {
1279 // Bind the bean level ejb-local-ref/local-jndi-name
1280 if (ref.getJndiName() == null)
1281 {
1282 throw new DeploymentException("ejb-local-ref " + ref.getName() + ", expected either ejb-link in ejb-jar.xml " + "or local-jndi-name in jboss.xml");
1283 }
1284 Util.bind(envCtx, ref.getName(), new LinkRef(ref.getJndiName()));
1285 }
1286 }
1287 }
1288
1289 // Bind service references
1290 {
1291 ClassLoader loader = unit.getClassLoader();
1292 UnifiedVirtualFile vfsRoot = new VirtualFileAdaptor(unit.getRoot());
1293 Iterator<ServiceReferenceMetaData> serviceReferences = beanMetaData.getServiceReferences();
1294 if (serviceReferences != null)
1295 {
1296 while (serviceReferences.hasNext())
1297 {
1298 ServiceReferenceMetaData sref = serviceReferences.next();
1299 String refName = sref.getServiceRefName();
1300 new ServiceReferenceHandler().bindServiceRef(envCtx, refName, vfsRoot, loader, sref);
1301 }
1302 }
1303 }
1304
1305 // Bind resource references
1306 {
1307 Iterator i = beanMetaData.getResourceReferences();
1308
1309 // let's play guess the cast game ;) New metadata should fix this.
1310 ApplicationMetaData application = beanMetaData.getApplicationMetaData();
1311
1312 while (i.hasNext())
1313 {
1314 ResourceRefMetaData ref = (ResourceRefMetaData)i.next();
1315
1316 String resourceName = ref.getResourceName();
1317 String finalName = application.getResourceByName(resourceName);
1318 String resType = ref.getType();
1319 // If there was no resource-manager specified then an immeadiate
1320 // jndi-name or res-url name should have been given
1321 if (finalName == null)
1322 finalName = ref.getJndiName();
1323
1324 if (finalName == null && resType.equals("java.net.URL") == false)
1325 {
1326 // the application assembler did not provide a resource manager
1327 // if the type is javax.sql.Datasoure use the default one
1328
1329 if (ref.getType().equals("javax.sql.DataSource"))
1330 {
1331 // Go through JNDI and look for DataSource - use the first one
1332 Context dsCtx = new InitialContext();
1333 try
1334 {
1335 // Check if it is available in JNDI
1336 dsCtx.lookup("java:/DefaultDS");
1337 finalName = "java:/DefaultDS";
1338 }
1339 catch (Exception e)
1340 {
1341 log.debug("failed to lookup DefaultDS; ignoring", e);
1342 }
1343 finally
1344 {
1345 dsCtx.close();
1346 }
1347 }
1348
1349 // Default failed? Warn user and move on
1350 // POTENTIALLY DANGEROUS: should this be a critical error?
1351 if (finalName == null)
1352 {
1353 log.warn("No resource manager found for " + ref.getResourceName());
1354 continue;
1355 }
1356 }
1357
1358 if (resType.equals("java.net.URL"))
1359 {
1360 // URL bindings
1361 if (ref.getResURL() != null)
1362 {
1363 // The URL string was given by the res-url
1364 log.debug("Binding URL: " + ref.getRefName() + " to JDNI ENC as: " + ref.getResURL());
1365 URL resURL = new URL(ref.getResURL());
1366 Util.bind(envCtx, ref.getRefName(), resURL);
1367 }
1368 else
1369 {
1370 log.debug("Binding URL: " + ref.getRefName() + " to: " + finalName);
1371 Object bind = null;
1372 if (ref.getJndiName() != null)
1373 {
1374 // Was the url given as a jndi-name reference to link to it
1375 bind = new LinkRef(finalName);
1376 }
1377 else
1378 {
1379 // The url string was given via a resource-name mapping
1380 bind = new URL(finalName);
1381 }
1382 Util.bind(envCtx, ref.getRefName(), bind);
1383 }
1384 }
1385 else
1386 {
1387 // Resource Manager bindings, should validate the type...
1388 log.debug("Binding resource manager: " + ref.getRefName() + " to JDNI ENC as: " + finalName);
1389 Util.bind(envCtx, ref.getRefName(), new LinkRef(finalName));
1390 }
1391 }
1392 }
1393
1394 // Bind resource env references
1395 {
1396 Iterator i = beanMetaData.getResourceEnvReferences();
1397 while (i.hasNext())
1398 {
1399 ResourceEnvRefMetaData resRef = (ResourceEnvRefMetaData)i.next();
1400 String encName = resRef.getRefName();
1401 String jndiName = resRef.getJndiName();
1402 // Should validate the type...
1403 log.debug("Binding env resource: " + encName + " to JDNI ENC as: " + jndiName);
1404 Util.bind(envCtx, encName, new LinkRef(jndiName));
1405 }
1406 }
1407
1408 // Bind message destination references
1409 {
1410 Iterator i = beanMetaData.getMessageDestinationReferences();
1411
1412 while (i.hasNext())
1413 {
1414 MessageDestinationRefMetaData ref = (MessageDestinationRefMetaData)i.next();
1415
1416 String refName = ref.getRefName();
1417 String jndiName = ref.getJNDIName();
1418 String link = ref.getLink();
1419 if (link != null)
1420 {
1421 if (jndiName == null)
1422 {
1423 MessageDestinationMetaData messageDestination = getMessageDestination(link);
1424 if (messageDestination == null)
1425 throw new DeploymentException("message-destination-ref '" + refName + "' message-destination-link '" + link
1426 + "' not found and no jndi-name in jboss.xml");
1427 else
1428 {
1429 String linkJNDIName = messageDestination.getJndiName();
1430 if (linkJNDIName == null)
1431 log.warn("message-destination '" + link + "' has no jndi-name in jboss.xml");
1432 else
1433 jndiName = linkJNDIName;
1434 }
1435 }
1436 else
1437 log.warn("message-destination-ref '" + refName + "' ignoring message-destination-link '" + link + "' because it has a jndi-name in jboss.xml");
1438 }
1439 else if (jndiName == null)
1440 throw new DeploymentException("message-destination-ref '" + refName + "' has no message-destination-link in ejb-jar.xml and no jndi-name in jboss.xml");
1441 Util.bind(envCtx, refName, new LinkRef(jndiName));
1442 }
1443 }
1444
1445 // Create a java:comp/env/security/security-domain link to the container
1446 // or application security-domain if one exists so that access to the
1447 // security manager can be made without knowing the global jndi name.
1448
1449 String securityDomain = metaData.getContainerConfiguration().getSecurityDomain();
1450 if (securityDomain == null)
1451 securityDomain = metaData.getApplicationMetaData().getSecurityDomain();
1452 if (securityDomain != null)
1453 {
1454 log.debug("Binding securityDomain: " + securityDomain + " to JDNI ENC as: security/security-domain");
1455
1456 Util.bind(envCtx, "security/security-domain", new LinkRef(securityDomain));
1457 Util.bind(envCtx, "security/subject", new LinkRef(securityDomain + "/subject"));
1458 Util.bind(envCtx, "security/realmMapping", new LinkRef(securityDomain + "/realmMapping"));
1459 Util.bind(envCtx, "security/authorizationMgr", new LinkRef(securityDomain + "/authorizationMgr"));
1460 }
1461
1462 log.debug("End java:comp/env for EJB: " + beanMetaData.getEjbName());
1463 }
1464
1465 public MessageDestinationMetaData getMessageDestination(String link)
1466 {
1467 return EjbUtil50.findMessageDestination(null, unit, link);
1468 }
1469
1470 /**
1471 *The <code>teardownEnvironment</code> method unbinds everything from
1472 * the comp/env context. It would be better do destroy the env context
1473 * but destroyContext is not currently implemented..
1474 *
1475 * @exception Exception if an error occurs
1476 */
1477 private void teardownEnvironment() throws Exception
1478 {
1479 Context ctx = (Context)new InitialContext().lookup("java:comp");
1480 ctx.unbind("env");
1481 log.debug("Removed bindings from java:comp/env for EJB: " + getBeanMetaData().getEjbName());
1482 ctx.unbind("TransactionSynchronizationRegistry");
1483 log.debug("Unbound java:comp/TransactionSynchronizationRegistry for EJB: " + getBeanMetaData().getEjbName());
1484 try
1485 {
1486 NonSerializableFactory.unbind("ORB");
1487 log.debug("Unbound java:comp/ORB for EJB: " + getBeanMetaData().getEjbName());
1488
1489 NonSerializableFactory.unbind("HandleDelegate");
1490 log.debug("Unbound java:comp/HandleDelegate for EJB: " + getBeanMetaData().getEjbName());
1491 }
1492 catch (NamingException ignored)
1493 {
1494 }
1495 }
1496
1497 /**
1498 * The base class for container interceptors.
1499 *
1500 * <p>
1501 * All container interceptors perform the same basic functionality
1502 * and only differ slightly.
1503 */
1504 protected abstract class AbstractContainerInterceptor implements Interceptor
1505 {
1506 protected final Logger log = Logger.getLogger(this.getClass());
1507
1508 public void setContainer(Container con)
1509 {
1510 }
1511
1512 public void setNext(Interceptor interceptor)
1513 {
1514 }
1515
1516 public Interceptor getNext()
1517 {
1518 return null;
1519 }
1520
1521 public void create()
1522 {
1523 }
1524
1525 public void start()
1526 {
1527 }
1528
1529 public void stop()
1530 {
1531 }
1532
1533 public void destroy()
1534 {
1535 }
1536
1537 protected void rethrow(Exception e) throws Exception
1538 {
1539 if (e instanceof IllegalAccessException)
1540 {
1541 // Throw this as a bean exception...(?)
1542 throw new EJBException(e);
1543 }
1544 else if (e instanceof InvocationTargetException)
1545 {
1546 Throwable t = ((InvocationTargetException)e).getTargetException();
1547
1548 if (t instanceof EJBException)
1549 {
1550 throw (EJBException)t;
1551 }
1552 else if (t instanceof Exception)
1553 {
1554 throw (Exception)t;
1555 }
1556 else if (t instanceof Error)
1557 {
1558 throw (Error)t;
1559 }
1560 else
1561 {
1562 throw new NestedError("Unexpected Throwable", t);
1563 }
1564 }
1565
1566 throw e;
1567 }
1568
1569 // Monitorable implementation ------------------------------------
1570
1571 public void sample(Object s)
1572 {
1573 // Just here to because Monitorable request it but will be removed soon
1574 }
1575
1576 public Map retrieveStatistic()
1577 {
1578 return null;
1579 }
1580
1581 public void resetStatistic()
1582 {
1583 }
1584 }
1585
1586 /** Perform the MBeanServer.invoke op in a PrivilegedExceptionAction if
1587 * running with a security manager.
1588 */
1589 class MBeanServerAction implements PrivilegedExceptionAction
1590 {
1591 private ObjectName target;
1592 String method;
1593 Object[] args;
1594 String[] sig;
1595
1596 MBeanServerAction()
1597 {
1598 }
1599
1600 MBeanServerAction(ObjectName target, String method, Object[] args, String[] sig)
1601 {
1602 this.target = target;
1603 this.method = method;
1604 this.args = args;
1605 this.sig = sig;
1606 }
1607
1608 public Object run() throws Exception
1609 {
1610 Object rtnValue = server.invoke(target, method, args, sig);
1611 return rtnValue;
1612 }
1613
1614 Object invoke(ObjectName target, String method, Object[] args, String[] sig) throws Exception
1615 {
1616 SecurityManager sm = System.getSecurityManager();
1617 Object rtnValue = null;
1618 if (sm == null)
1619 {
1620 // Direct invocation on MBeanServer
1621 rtnValue = server.invoke(target, method, args, sig);
1622 }
1623 else
1624 {
1625 try
1626 {
1627 // Encapsulate the invocation in a PrivilegedExceptionAction
1628 MBeanServerAction action = new MBeanServerAction(target, method, args, sig);
1629 rtnValue = AccessController.doPrivileged(action);
1630 }
1631 catch (PrivilegedActionException e)
1632 {
1633 Exception ex = e.getException();
1634 throw ex;
1635 }
1636 }
1637 return rtnValue;
1638 }
1639 }
1640 }