KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > EJBDeployer


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.io.File JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.net.URLClassLoader JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.Set JavaDoc;
32
33 import javax.management.ObjectName JavaDoc;
34 import javax.security.jacc.PolicyContext JavaDoc;
35 import javax.transaction.TransactionManager JavaDoc;
36
37 import org.jboss.deployment.DeploymentException;
38 import org.jboss.deployment.DeploymentInfo;
39 import org.jboss.deployment.J2eeApplicationMetaData;
40 import org.jboss.deployment.SubDeployerExt;
41 import org.jboss.deployment.SubDeployerSupport;
42 import org.jboss.ejb.plugins.EnterpriseBeanPolicyContextHandler;
43 import org.jboss.logging.Logger;
44 import org.jboss.metadata.ApplicationMetaData;
45 import org.jboss.metadata.MetaData;
46 import org.jboss.metadata.XmlFileLoader;
47 import org.jboss.mx.loading.LoaderRepositoryFactory;
48 import org.jboss.mx.util.MBeanProxyExt;
49 import org.jboss.mx.util.ObjectNameConverter;
50 import org.jboss.system.ServiceControllerMBean;
51 import org.jboss.verifier.BeanVerifier;
52 import org.jboss.verifier.event.VerificationEvent;
53 import org.jboss.verifier.event.VerificationListener;
54 import org.w3c.dom.Element JavaDoc;
55
56 /**
57  * A EJBDeployer is used to deploy EJB applications. It can be given a
58  * URL to an EJB-jar or EJB-JAR XML file, which will be used to instantiate
59  * containers and make them available for invocation.
60  *
61  * @jmx:mbean
62  * name="jboss.ejb:service=EJBDeployer"
63  * extends="org.jboss.deployment.SubDeployerMBean"
64  *
65  * @see Container
66  *
67  * @version <tt>$Revision: 41517 $</tt>
68  * @author <a HREF="mailto:rickard.oberg@telkel.com">Rickard Öberg</a>
69  * @author <a HREF="mailto:marc.fleury@telkel.com">Marc Fleury</a>
70  * @author <a HREF="mailto:jplindfo@helsinki.fi">Juha Lindfors</a>
71  * @author <a HREF="mailto:sebastien.alborini@m4x.org">Sebastien Alborini</a>
72  * @author <a HREF="mailto:peter.antman@tim.se">Peter Antman</a>
73  * @author <a HREF="mailto:scott.stark@jboss.org">Scott Stark</a>
74  * @author <a HREF="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>
75  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
76  * @author <a HREF="mailto:christoph.jung@infor.de">Christoph G. Jung</a>
77  * @author <a HREF="mailto:thomas.diesler@arcor.de">Thomas Diesler</a>
78  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
79  */

80 public class EJBDeployer extends SubDeployerSupport
81    implements EJBDeployerMBean
82 {
83    /** The suffixes we accept, along with their relative order */
84    private static final String JavaDoc[] DEFAULT_ENHANCED_SUFFIXES = new String JavaDoc[] {
85          "400:.jar"
86    };
87    
88    private ServiceControllerMBean serviceController;
89
90    /** A map of current deployments. */
91    private HashMap JavaDoc deployments = new HashMap JavaDoc();
92
93    /** Verify EJB-jar contents on deployments */
94    private boolean verifyDeployments;
95
96    /** Enable verbose verification. */
97    private boolean verifierVerbose;
98
99    /** Enable strict verification: deploy JAR only if Verifier reports
100     * no problems */

101    private boolean strictVerifier;
102
103    /** Enable metrics interceptor */
104    private boolean metricsEnabled;
105
106    /** A flag indicating if deployment descriptors should be validated */
107    private boolean validateDTDs;
108
109    /** Service name for the web service */
110    private ObjectName JavaDoc webServiceName;
111
112    private ObjectName JavaDoc transactionManagerServiceName;
113    private TransactionManager JavaDoc tm;
114
115    private boolean callByValue;
116    
117    /** Hold a proxy reference to myself, used when registering to MainDeployer */
118    private SubDeployerExt thisProxy;
119    
120    /**
121     * Default CTOR
122     */

123    public EJBDeployer()
124    {
125       setEnhancedSuffixes(DEFAULT_ENHANCED_SUFFIXES);
126    }
127    
128    /**
129     * @jmx:managed-attribute
130     *
131     * @return whether ear deployments should be call by value
132     */

133    public boolean isCallByValue()
134    {
135       return callByValue;
136    }
137    
138    /**
139     * @jmx:managed-attribute
140     *
141     * @param callByValue whether ear deployments should be call by value
142     */

143    public void setCallByValue(boolean callByValue)
144    {
145       this.callByValue = callByValue;
146    }
147    
148    /**
149     * Returns the deployed applications.
150     *
151     * @jmx:managed-operation
152     */

153    public Iterator JavaDoc listDeployedApplications()
154    {
155       return deployments.values().iterator();
156    }
157
158    /**
159     * Get a reference to the ServiceController
160     */

161    protected void startService() throws Exception JavaDoc
162    {
163       serviceController = (ServiceControllerMBean)
164          MBeanProxyExt.create(ServiceControllerMBean.class,
165                               ServiceControllerMBean.OBJECT_NAME, server);
166       tm = (TransactionManager JavaDoc)getServer().getAttribute(transactionManagerServiceName,
167                                                         "TransactionManager");
168
169       // Register the JAAC EJB PolicyContextHandlers
170
// Each context handler can only be registered once per vm
171
Set JavaDoc keys = PolicyContext.getHandlerKeys();
172       if (!keys.contains(EnterpriseBeanPolicyContextHandler.EJB_CONTEXT_KEY))
173       {
174             EnterpriseBeanPolicyContextHandler beanHandler = new EnterpriseBeanPolicyContextHandler();
175             PolicyContext.registerHandler(EnterpriseBeanPolicyContextHandler.EJB_CONTEXT_KEY,
176                   beanHandler, false);
177       }
178       if (!keys.contains(BeanMetaDataPolicyContextHandler.METADATA_CONTEXT_KEY))
179       {
180          BeanMetaDataPolicyContextHandler metadataHandler = new BeanMetaDataPolicyContextHandler();
181          PolicyContext.registerHandler(BeanMetaDataPolicyContextHandler.METADATA_CONTEXT_KEY,
182                metadataHandler, false);
183       }
184       if (!keys.contains(EJBArgsPolicyContextHandler.EJB_ARGS_KEY))
185       {
186          EJBArgsPolicyContextHandler argsHandler = new EJBArgsPolicyContextHandler();
187          PolicyContext.registerHandler(EJBArgsPolicyContextHandler.EJB_ARGS_KEY,
188                argsHandler, false);
189       }
190       if (!keys.contains(SOAPMsgPolicyContextHandler.SEI_ARGS_KEY))
191       {
192          SOAPMsgPolicyContextHandler msgHandler = new SOAPMsgPolicyContextHandler();
193          PolicyContext.registerHandler(SOAPMsgPolicyContextHandler.SEI_ARGS_KEY,
194                msgHandler, false);
195       }
196
197       // make a proxy to myself, so that calls from the MainDeployer
198
// can go through the MBeanServer, so interceptors can be added
199
thisProxy = (SubDeployerExt)
200          MBeanProxyExt.create(SubDeployerExt.class, super.getServiceName(), super.getServer());
201       
202       // Register with the main deployer
203
mainDeployer.addDeployer(thisProxy);
204    }
205
206    /**
207     * Implements the template method in superclass. This method stops all the
208     * applications in this server.
209     */

210    protected void stopService() throws Exception JavaDoc
211    {
212
213       for( Iterator JavaDoc modules = deployments.values().iterator();
214          modules.hasNext(); )
215       {
216          DeploymentInfo di = (DeploymentInfo) modules.next();
217          stop(di);
218       }
219
220       // avoid concurrent modification exception
221
for( Iterator JavaDoc modules = new ArrayList JavaDoc(deployments.values()).iterator();
222          modules.hasNext(); )
223       {
224          DeploymentInfo di = (DeploymentInfo) modules.next();
225          destroy(di);
226       }
227       deployments.clear();
228
229       // deregister with MainDeployer
230
mainDeployer.removeDeployer(thisProxy);
231
232       serviceController = null;
233       tm = null;
234    }
235
236    /**
237     * Enables/disables the application bean verification upon deployment.
238     *
239     * @jmx:managed-attribute
240     *
241     * @param verify true to enable; false to disable
242     */

243    public void setVerifyDeployments( boolean verify )
244    {
245       verifyDeployments = verify;
246    }
247
248    /**
249     * Returns the state of bean verifier (on/off)
250     *
251     * @jmx:managed-attribute
252     *
253     * @return true if enabled; false otherwise
254     */

255    public boolean getVerifyDeployments()
256    {
257       return verifyDeployments;
258    }
259
260    /**
261     * Enables/disables the verbose mode on the verifier.
262     *
263     * @jmx:managed-attribute
264     *
265     * @param verbose true to enable; false to disable
266     */

267    public void setVerifierVerbose(boolean verbose)
268    {
269       verifierVerbose = verbose;
270    }
271
272    /**
273     * Returns the state of the bean verifier (verbose/non-verbose mode)
274     *
275     * @jmx:managed-attribute
276     *
277     * @return true if enabled; false otherwise
278     */

279    public boolean getVerifierVerbose()
280    {
281       return verifierVerbose;
282    }
283
284    /**
285     * Enables/disables the strict mode on the verifier.
286     *
287     * @jmx:managed-attribute
288     *
289     * @param strictVerifier <code>true</code> to enable; <code>false</code>
290     * to disable
291     */

292    public void setStrictVerifier( boolean strictVerifier )
293    {
294       this.strictVerifier = strictVerifier;
295    }
296
297    /**
298     * Returns the mode of the bean verifier (strict/non-strict mode)
299     *
300     * @jmx:managed-attribute
301     *
302     * @return <code>true</code> if the Verifier is in strict mode,
303     * <code>false</code> otherwise
304     */

305    public boolean getStrictVerifier()
306    {
307       return strictVerifier;
308    }
309
310
311    /**
312     * Enables/disables the metrics interceptor for containers.
313     *
314     * @jmx:managed-attribute
315     *
316     * @param enable true to enable; false to disable
317     */

318    public void setMetricsEnabled(boolean enable)
319    {
320       metricsEnabled = enable;
321    }
322
323    /**
324     * Checks if this container factory initializes the metrics interceptor.
325     *
326     * @jmx:managed-attribute
327     *
328     * @return true if metrics are enabled; false otherwise
329     */

330    public boolean isMetricsEnabled()
331    {
332       return metricsEnabled;
333    }
334
335    /**
336     * Get the flag indicating that ejb-jar.dtd, jboss.dtd &amp;
337     * jboss-web.dtd conforming documents should be validated
338     * against the DTD.
339     *
340     * @jmx:managed-attribute
341     */

342    public boolean getValidateDTDs()
343    {
344       return validateDTDs;
345    }
346
347    /**
348     * Set the flag indicating that ejb-jar.dtd, jboss.dtd &amp;
349     * jboss-web.dtd conforming documents should be validated
350     * against the DTD.
351     *
352     * @jmx:managed-attribute
353     */

354    public void setValidateDTDs(boolean validate)
355    {
356       this.validateDTDs = validate;
357    }
358
359
360    /**
361     * Get the WebServiceName value.
362     * @return the WebServiceName value.
363     *
364     * @jmx:managed-attribute
365     */

366    public ObjectName JavaDoc getWebServiceName()
367    {
368       return webServiceName;
369    }
370
371    /**
372     * Set the WebServiceName value.
373     * @param webServiceName The new WebServiceName value.
374     *
375     * @jmx:managed-attribute
376     */

377    public void setWebServiceName(ObjectName JavaDoc webServiceName)
378    {
379       this.webServiceName = webServiceName;
380    }
381
382
383    /**
384     * Get the TransactionManagerServiceName value.
385     * @return the TransactionManagerServiceName value.
386     *
387     * @jmx:managed-attribute
388     */

389    public ObjectName JavaDoc getTransactionManagerServiceName()
390    {
391       return transactionManagerServiceName;
392    }
393
394    /**
395     * Set the TransactionManagerServiceName value.
396     * @param transactionManagerServiceName The new TransactionManagerServiceName value.
397     *
398     * @jmx:managed-attribute
399     */

400    public void setTransactionManagerServiceName(ObjectName JavaDoc transactionManagerServiceName)
401    {
402       this.transactionManagerServiceName = transactionManagerServiceName;
403    }
404
405    public boolean accepts(DeploymentInfo di)
406    {
407       // To be accepted the deployment's root name must end in .jar or .jar/
408
if (super.accepts(di) == false)
409       {
410          return false;
411       }
412       // However the jar must also contain at least one ejb-jar.xml
413
boolean accepts = false;
414       try
415       {
416          URL JavaDoc dd = di.localCl.findResource("META-INF/ejb-jar.xml");
417          if (dd == null)
418          {
419             return false;
420          }
421          String JavaDoc urlStr = di.url.getFile();
422
423          // If the DD url is not a subset of the urlStr then this is coming
424
// from a jar referenced by the deployment jar manifest and the
425
// this deployment jar it should not be treated as an ejb-jar
426
if( di.localUrl != null )
427          {
428             urlStr = di.localUrl.toString();
429          }
430
431          String JavaDoc ddStr = dd.toString();
432          if ( ddStr.indexOf(urlStr) >= 0 )
433          {
434             accepts = true;
435          }
436       }
437       catch( Exception JavaDoc ignore )
438       {
439       }
440
441       return accepts;
442    }
443
444    public void init(DeploymentInfo di)
445       throws DeploymentException
446    {
447       log.debug("init, "+di.shortName);
448       try
449       {
450          if( di.url.getProtocol().equalsIgnoreCase("file") )
451          {
452             File JavaDoc file = new File JavaDoc(di.url.getFile());
453
454             if( !file.isDirectory() )
455             {
456                // If not directory we watch the package
457
di.watch = di.url;
458             }
459             else
460             {
461                // If directory we watch the xml files
462
di.watch = new URL JavaDoc(di.url, "META-INF/ejb-jar.xml");
463             }
464          }
465          else
466          {
467             // We watch the top only, no directory support
468
di.watch = di.url;
469          }
470
471          // Check for a loader-repository
472
XmlFileLoader xfl = new XmlFileLoader();
473          InputStream JavaDoc in = di.localCl.getResourceAsStream("META-INF/jboss.xml");
474          if( in != null )
475          {
476             try
477             {
478                Element JavaDoc jboss = xfl.getDocument(in, "META-INF/jboss.xml").getDocumentElement();
479                // Check for a ejb level class loading config
480
Element JavaDoc loader = MetaData.getOptionalChild(jboss, "loader-repository");
481                if( loader != null )
482                {
483                   LoaderRepositoryFactory.LoaderRepositoryConfig config =
484                         LoaderRepositoryFactory.parseRepositoryConfig(loader);
485                   di.setRepositoryInfo(config);
486                }
487             }
488             finally
489             {
490                in.close();
491             }
492          }
493       }
494       catch (Exception JavaDoc e)
495       {
496          if (e instanceof DeploymentException)
497             throw (DeploymentException)e;
498          throw new DeploymentException( "failed to initialize", e );
499       }
500
501       // invoke super-class initialization
502
super.init(di);
503    }
504
505    /**
506     * This is here as a reminder that we may not want to allow ejb jars to
507     * have arbitrary sub deployments. Currently we do.
508     * @param di
509     * @throws DeploymentException
510     */

511    protected void processNestedDeployments(DeploymentInfo di)
512       throws DeploymentException
513    {
514       super.processNestedDeployments(di);
515    }
516
517    public synchronized void create(DeploymentInfo di)
518       throws DeploymentException
519    {
520       log.debug("create, "+di.shortName);
521       ApplicationMetaData ejbMetaData = null;
522       try
523       {
524          // Initialize the annotations classloader
525
URL JavaDoc loaderURL = (di.localUrl != null ? di.localUrl : di.url);
526          di.annotationsCl = new URLClassLoader JavaDoc(new URL JavaDoc[] { loaderURL }, di.ucl);
527          
528          // Create a file loader with which to load the files
529
XmlFileLoader efm = new XmlFileLoader(validateDTDs);
530          efm.setClassLoader(di.localCl);
531
532          // redirect to alternative DD
533
URL JavaDoc alternativeDD = null;
534          if (di.alternativeDD != null)
535          {
536             String JavaDoc contentsDir = new File JavaDoc(di.url.getPath()).getParent();
537             alternativeDD = new URL JavaDoc("file:/" + contentsDir + "/" + di.alternativeDD);
538          }
539
540          // Load XML
541
di.metaData = ejbMetaData = efm.load(alternativeDD);
542
543          // inherit the security setup from jboss-app.xml
544
if (di.parent != null && di.parent.metaData instanceof J2eeApplicationMetaData)
545          {
546             J2eeApplicationMetaData appMetaData = (J2eeApplicationMetaData)di.parent.metaData;
547
548             if (ejbMetaData.getSecurityDomain() == null)
549                ejbMetaData.setSecurityDomain(appMetaData.getSecurityDomain());
550
551             if (ejbMetaData.getUnauthenticatedPrincipal() == null)
552                ejbMetaData.setUnauthenticatedPrincipal(appMetaData.getUnauthenticatedPrincipal());
553
554             ejbMetaData.getAssemblyDescriptor().mergeSecurityRoles(appMetaData.getSecurityRoles());
555          }
556       }
557       catch (Exception JavaDoc e)
558       {
559          if (e instanceof DeploymentException)
560             throw (DeploymentException)e;
561          throw new DeploymentException( "Failed to load metaData", e );
562       }
563
564       if( verifyDeployments )
565       {
566          // we have a positive attitude
567
boolean allOK = true;
568
569          // wrapping this into a try - catch block to prevent errors in
570
// verifier from stopping the deployment
571
try
572          {
573             BeanVerifier verifier = new BeanVerifier();
574
575             // add a listener so we can log the results
576
verifier.addVerificationListener(new VerificationListener()
577                {
578                   Logger verifierLog = Logger.getLogger(EJBDeployer.class,
579                      "verifier" );
580
581                   public void beanChecked(VerificationEvent event)
582                   {
583                      verifierLog.debug( "Bean checked: " + event.getMessage() );
584                   }
585
586                   public void specViolation(VerificationEvent event)
587                   {
588                      verifierLog.warn( "EJB spec violation: " +
589                         (verifierVerbose ? event.getVerbose() : event.getMessage()));
590                   }
591                });
592
593             log.debug("Verifying " + di.url);
594             verifier.verify( di.url, (ApplicationMetaData) di.metaData,
595                di.ucl );
596
597             allOK = verifier.getSuccess();
598          }
599          catch (Throwable JavaDoc t)
600          {
601             log.warn("Verify failed; continuing", t );
602             allOK = false;
603          }
604
605          // If the verifier is in strict mode and an error/warning
606
// was found in the Verification process, throw a Deployment
607
// Exception
608
if( strictVerifier && !allOK )
609          {
610             throw new DeploymentException( "Verification of Enterprise " +
611                "Beans failed, see above for error messages." );
612          }
613
614       }
615
616       // Create an MBean for the EJB module
617
try
618       {
619          EjbModule ejbModule = new EjbModule(di, tm, webServiceName);
620          String JavaDoc name = ejbMetaData.getJmxName();
621          if( name == null )
622          {
623             name = EjbModule.BASE_EJB_MODULE_NAME + ",module=" + di.shortName;
624          }
625          // Build an escaped JMX name including deployment shortname
626
ObjectName JavaDoc ejbModuleName = ObjectNameConverter.convert(name);
627          // Check that the name is not registered
628
if( server.isRegistered(ejbModuleName) == true )
629          {
630             log.debug("The EJBModule name: "+ejbModuleName
631                +"is already registered, adding uid="+System.identityHashCode(ejbModule));
632             name = name + ",uid="+System.identityHashCode(ejbModule);
633             ejbModuleName = ObjectNameConverter.convert(name);
634          }
635
636          server.registerMBean(ejbModule, ejbModuleName);
637          di.deployedObject = ejbModuleName;
638
639          log.debug( "Deploying: " + di.url );
640          // Invoke the create life cycle method
641
serviceController.create(di.deployedObject);
642       }
643       catch (Exception JavaDoc e)
644       {
645          throw new DeploymentException("Error during create of EjbModule: "
646             + di.url, e);
647       }
648       super.create(di);
649    }
650
651    public synchronized void start(DeploymentInfo di)
652       throws DeploymentException
653    {
654       try
655       {
656          // Start application
657
log.debug( "start application, deploymentInfo: " + di +
658                     ", short name: " + di.shortName +
659                     ", parent short name: " +
660                     (di.parent == null ? "null" : di.parent.shortName) );
661
662          serviceController.start(di.deployedObject);
663
664          log.info( "Deployed: " + di.url );
665
666          // Register deployment. Use the application name in the hashtable
667
// FIXME: this is obsolete!! (really?!)
668
deployments.put(di.url, di);
669       }
670       catch (Exception JavaDoc e)
671       {
672          stop(di);
673          destroy(di);
674
675          throw new DeploymentException( "Could not deploy " + di.url, e );
676       }
677       super.start(di);
678    }
679
680    public void stop(DeploymentInfo di)
681       throws DeploymentException
682    {
683       log.info( "Undeploying: " + di.url );
684
685       try
686       {
687          if (di.deployedObject != null)
688             serviceController.stop(di.deployedObject);
689       }
690       catch (Exception JavaDoc e)
691       {
692          throw new DeploymentException( "problem stopping ejb module: " +
693             di.url, e );
694       }
695       super.stop(di);
696    }
697
698    public void destroy(DeploymentInfo di)
699       throws DeploymentException
700    {
701       // FIXME: If the put() is obsolete above, this is obsolete, too
702
deployments.remove(di.url);
703
704       try
705       {
706          if (di.deployedObject != null)
707          {
708             serviceController.destroy( di.deployedObject );
709             serviceController.remove( di.deployedObject );
710          }
711       }
712       catch (Exception JavaDoc e)
713       {
714          throw new DeploymentException( "problem destroying ejb module: " +
715             di.url, e );
716       }
717       super.destroy(di);
718    }
719 }
720
Popular Tags