KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > deployment > EARDeployer


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.deployment;
23
24 import java.io.File JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.FileInputStream JavaDoc;
28 import java.net.MalformedURLException JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.security.Policy JavaDoc;
31 import java.util.Enumeration JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.jar.JarEntry JavaDoc;
36 import java.util.jar.JarFile JavaDoc;
37 import java.util.jar.Manifest JavaDoc;
38 import java.util.jar.Attributes JavaDoc;
39 import java.util.jar.JarInputStream JavaDoc;
40
41 import javax.management.ObjectName JavaDoc;
42 import javax.security.jacc.PolicyConfiguration JavaDoc;
43 import javax.security.jacc.PolicyConfigurationFactory JavaDoc;
44
45 import org.jboss.metadata.MetaData;
46 import org.jboss.metadata.XmlFileLoader;
47 import org.jboss.mx.loading.LoaderRepositoryFactory;
48 import org.jboss.mx.loading.LoaderRepositoryFactory.LoaderRepositoryConfig;
49 import org.jboss.mx.util.MBeanProxyExt;
50 import org.jboss.system.ServiceControllerMBean;
51 import org.jboss.util.file.JarUtils;
52 import org.w3c.dom.Element JavaDoc;
53
54 /**
55  * Enterprise Archive Deployer.
56  *
57  * @author <a HREF="mailto:marc.fleury@jboss.org">Marc Fleury</a>
58  * @author Scott.Stark@jboss.org
59  * @version $Revision: 55160 $
60  */

61 public class EARDeployer extends SubDeployerSupport
62    implements EARDeployerMBean
63 {
64    /** The suffixes we accept, along with their relative order */
65    private static final String JavaDoc[] DEFAULT_ENHANCED_SUFFIXES = new String JavaDoc[] {
66          "650:.ear"
67    };
68    
69    private ServiceControllerMBean serviceController;
70
71    private boolean isolated = false;
72
73    private boolean callByValue = false;
74    
75    /**
76     * Default CTOR
77     */

78    public EARDeployer()
79    {
80       setEnhancedSuffixes(DEFAULT_ENHANCED_SUFFIXES);
81    }
82    
83    /**
84     * @return whether ear deployments should be isolated
85     */

86    public boolean isIsolated()
87    {
88       return isolated;
89    }
90    
91    /**
92     * @param isolated whether ear deployments should be isolated
93     */

94    public void setIsolated(boolean isolated)
95    {
96       this.isolated = isolated;
97    }
98    
99    /**
100     * @return whether ear deployments should be call by value
101     */

102    public boolean isCallByValue()
103    {
104       return callByValue;
105    }
106    
107    /**
108     * @param callByValue whether ear deployments should be call by value
109     */

110    public void setCallByValue(boolean callByValue)
111    {
112       this.callByValue = callByValue;
113    }
114    
115    protected void startService() throws Exception JavaDoc
116    {
117       serviceController = (ServiceControllerMBean)
118       MBeanProxyExt.create(ServiceControllerMBean.class,
119                            ServiceControllerMBean.OBJECT_NAME, server);
120       super.startService();
121    }
122    
123    public void init(DeploymentInfo di) throws DeploymentException
124    {
125       try
126       {
127          log.info("Init J2EE application: " + di.url);
128          InputStream JavaDoc in = di.localCl.getResourceAsStream("META-INF/application.xml");
129          boolean hasAppXml = in != null;
130          J2eeApplicationMetaData metaData = new J2eeApplicationMetaData();
131          if( hasAppXml )
132          {
133             /* Don't require validation of application.xml since an ear may
134             just contain a jboss sar specified in the jboss-app.xml descriptor.
135             */

136             XmlFileLoader xfl = new XmlFileLoader(false);
137             Element JavaDoc application = xfl.getDocument(in, "META-INF/application.xml").getDocumentElement();
138             metaData.importXml(application);
139             in.close();
140          }
141          else
142          {
143             // Scan the ear for modules
144
scanEar(metaData, di);
145          }
146          di.metaData = metaData;
147
148          // If there is a library-directory add its jars to the classpath
149
if( metaData.getLibraryDirectory() != null )
150          {
151             addLibraryJars(di, metaData.getLibraryDirectory());
152          }
153
154          // Check for a jboss-app.xml descriptor
155
Element JavaDoc loader = null;
156          in = di.localCl.getResourceAsStream("META-INF/jboss-app.xml");
157          if( in != null )
158          {
159             // Create a new parser with validation enabled for jboss-app.xml
160
XmlFileLoader xfl = new XmlFileLoader(true);
161             Element JavaDoc jbossApp = xfl.getDocument(in, "META-INF/jboss-app.xml").getDocumentElement();
162             in.close();
163             // Import module/service archives to metadata
164
metaData.importXml(jbossApp);
165             // Check for a loader-repository for scoping
166
loader = MetaData.getOptionalChild(jbossApp, "loader-repository");
167          }
168          initLoaderRepository(di, loader);
169
170          // resolve the watch
171
if (di.url.getProtocol().equals("file"))
172          {
173             File JavaDoc file = new File JavaDoc(di.url.getFile());
174             
175             // If not directory we watch the package
176
if (!file.isDirectory())
177             {
178                di.watch = di.url;
179             }
180             // If directory we watch the xml files
181
else
182             {
183                di.watch = new URL JavaDoc(di.url, "META-INF/application.xml");
184             }
185          }
186          else
187          {
188             // We watch the top only, no directory support
189
di.watch = di.url;
190          }
191          
192          // Obtain the sub-deployment list
193
File JavaDoc parentDir = null;
194          HashMap JavaDoc extractedJars = new HashMap JavaDoc();
195
196          if (di.isDirectory)
197          {
198             parentDir = new File JavaDoc(di.localUrl.getFile());
199          }
200          else
201          {
202             /* Extract each entry so that deployment modules can be processed
203              and any manifest entries referenced by the ear modules are located
204              in the same unpacked directory structure.
205             */

206             String JavaDoc urlPrefix = "jar:" + di.localUrl + "!/";
207             JarFile JavaDoc jarFile = new JarFile JavaDoc(di.localUrl.getFile());
208             // For each entry, test if deployable, if so
209
// extract it and store the related URL in map
210
for (Enumeration JavaDoc e = jarFile.entries(); e.hasMoreElements();)
211             {
212                JarEntry JavaDoc entry = (JarEntry JavaDoc)e.nextElement();
213                String JavaDoc name = entry.getName();
214                try
215                {
216                   URL JavaDoc url = new URL JavaDoc(urlPrefix + name);
217                   if (metaData.hasModule(name))
218                   {
219                      // Obtain a jar url for the nested jar
220
URL JavaDoc nestedURL = JarUtils.extractNestedJar(url, this.tempDeployDir);
221                      // and store in it in map
222
extractedJars.put(name, nestedURL);
223                      log.debug("Extracted deployable content: "+name);
224                   }
225                   else if( entry.isDirectory() == false )
226                   {
227                      JarUtils.extractNestedJar(url, this.tempDeployDir);
228                      log.debug("Extracted non-deployable content: "+name);
229                   }
230                }
231                catch (MalformedURLException JavaDoc mue)
232                {
233                   log.warn("Jar entry invalid. Ignoring: " + name, mue);
234                }
235                catch (IOException JavaDoc ex)
236                {
237                   log.warn("Failed to extract nested jar. Ignoring: " + name, ex);
238                }
239             }
240          }
241
242          // Create a top level JACC policy for linking app module policies
243
String JavaDoc contextID = di.shortName;
244          PolicyConfigurationFactory JavaDoc pcFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
245          PolicyConfiguration JavaDoc pc = pcFactory.getPolicyConfiguration(contextID, true);
246          di.context.put("javax.security.jacc.PolicyConfiguration", pc);
247
248          // Create subdeployments for the ear modules
249
for (Iterator JavaDoc iter = metaData.getModules(); iter.hasNext(); )
250          {
251             J2eeModuleMetaData mod = (J2eeModuleMetaData)iter.next();
252             String JavaDoc fileName = mod.getFileName();
253             if (fileName != null && (fileName = fileName.trim()).length() > 0)
254             {
255                DeploymentInfo sub = null;
256                if (di.isDirectory)
257                {
258                   File JavaDoc f = new File JavaDoc(parentDir, fileName);
259                   sub = new DeploymentInfo(f.toURL(), di, getServer());
260                }
261                else
262                {
263                   // The nested jar url was placed into extractedJars above
264
URL JavaDoc nestedURL = (URL JavaDoc) extractedJars.get(fileName);
265                   if( nestedURL == null )
266                      throw new DeploymentException("Failed to find module file: "+fileName);
267                   sub = new DeploymentInfo(nestedURL, di, getServer());
268                }
269
270                // Set the context-root on web modules
271
if( mod.isWeb() )
272                   sub.webContext = mod.getWebContext();
273
274                // Set the alternative deployment descriptor if there is one
275
if (mod.alternativeDD != null)
276                   sub.alternativeDD = mod.alternativeDD;
277
278                log.debug("Deployment Info: " + sub + ", isDirectory: " + sub.isDirectory);
279             }
280          }
281       }
282       catch (Exception JavaDoc e)
283       {
284          DeploymentException.rethrowAsDeploymentException("Error in accessing application metadata: ", e);
285       }
286       di.sortedSubDeployments=true;
287       super.init(di);
288    }
289
290    public void create(DeploymentInfo di) throws DeploymentException
291    {
292       super.create(di);
293
294       // Create an MBean for the EAR deployment
295
try
296       {
297          EARDeployment earDeployment = new EARDeployment(di);
298          String JavaDoc name = earDeployment.getJMXName();
299          ObjectName JavaDoc objectName = new ObjectName JavaDoc(name);
300          di.deployedObject = objectName;
301          server.registerMBean(earDeployment, objectName);
302          serviceController.create(di.deployedObject);
303       }
304       catch (Exception JavaDoc e)
305       {
306          DeploymentException.rethrowAsDeploymentException("Error during create of EARDeployment: " + di.url, e);
307       }
308    }
309    
310    public void start(DeploymentInfo di)
311       throws DeploymentException
312    {
313       super.start (di);
314       try
315       {
316          // Commit the top level policy configuration
317
PolicyConfiguration JavaDoc pc = (PolicyConfiguration JavaDoc)
318             di.context.get("javax.security.jacc.PolicyConfiguration");
319          pc.commit();
320          Policy.getPolicy().refresh();
321          serviceController.start(di.deployedObject);
322       }
323       catch (Exception JavaDoc e)
324       {
325          DeploymentException.rethrowAsDeploymentException("Error during start of EARDeployment: " + di.url, e);
326       }
327       log.info ("Started J2EE application: " + di.url);
328    }
329
330    public void stop(DeploymentInfo di) throws DeploymentException
331    {
332       try
333       {
334          if (di.deployedObject != null)
335             serviceController.stop(di.deployedObject);
336       }
337       catch (Exception JavaDoc e)
338       {
339          DeploymentException.rethrowAsDeploymentException("Error during stop of EARDeployment: " + di.url, e);
340       }
341       super.stop(di);
342    }
343
344    /**
345     * Describe <code>destroy</code> method here.
346     *
347     * @param di a <code>DeploymentInfo</code> value
348     * @exception DeploymentException if an error occurs
349     */

350    public void destroy(DeploymentInfo di) throws DeploymentException
351    {
352       log.info("Undeploying J2EE application, destroy step: " + di.url);
353       try
354       {
355          if (di.deployedObject != null)
356          {
357             serviceController.destroy(di.deployedObject);
358             serviceController.remove(di.deployedObject);
359          }
360       }
361       catch (Exception JavaDoc e)
362       {
363          DeploymentException.rethrowAsDeploymentException("Error during destroy of EARDeployment: " + di.url, e);
364       }
365       super.destroy(di);
366       log.info("Undeployed J2EE application: " + di.url);
367    }
368
369    /** Build the ear scoped repository
370     *
371     * @param di the deployment info passed to deploy
372     * @param loader the jboss-app/loader-repository element
373     * @throws Exception
374     */

375    protected void initLoaderRepository(DeploymentInfo di, Element JavaDoc loader)
376       throws Exception JavaDoc
377    {
378       if (loader == null)
379       {
380          if (isolated && di.parent == null)
381          {
382             J2eeApplicationMetaData metaData = (J2eeApplicationMetaData) di.metaData;
383             String JavaDoc name = EARDeployment.getJMXName(metaData, di) + ",extension=LoaderRepository";
384             ObjectName JavaDoc objectName = new ObjectName JavaDoc(name);
385
386             LoaderRepositoryConfig config = new LoaderRepositoryFactory.LoaderRepositoryConfig();
387             config.repositoryName = objectName;
388             di.setRepositoryInfo(config);
389          }
390          return;
391       }
392          
393       LoaderRepositoryConfig config = LoaderRepositoryFactory.parseRepositoryConfig(loader);
394       di.setRepositoryInfo(config);
395    }
396
397    /**
398     * Add -ds.xml and -service.xml as legitimate deployables.
399     */

400    protected boolean isDeployable(String JavaDoc name, URL JavaDoc url)
401    {
402       // super.isDeployable() should be enough, now that the list
403
// of supported suffixes is dynamically updated.
404
return super.isDeployable(name, url) ||
405          name.endsWith("-ds.xml") ||
406          name.endsWith("-service.xml") ||
407          name.endsWith(".har");
408    }
409
410    /** Override the default behavior of looking into the archive for deployables
411     * as only those explicitly listed in the application.xml and jboss-app.xml
412     * should be deployed.
413     *
414     * @param di
415     */

416    protected void processNestedDeployments(DeploymentInfo di)
417    {
418    }
419
420    /**
421    For an ear without an application.xml, determine modules via:
422    a. All ear modules with an extension of .war are considered web modules. The
423     context root of the web module is the name of the file relative to the root
424     of the application package, with the .war extension removed.
425    b. All ear modules with extension of .rar are considered resource adapters.
426    c. A directory named lib is considered to be the library directory, as
427     described in Section EE.8.2.1, “Bundled Libraries.”
428    d. For all ear modules with a filename extension of .jar, but not in the lib
429     directory, do the following:
430    i. If the JAR file contains a META-INF/MANIFEST.MF file with a Main-Class
431     attribute, or contains a META-INF/application-client.xml file, consider the
432     jar file to be an application client module.
433    ii. If the JAR file contains a META-INF/ejb-jar.xml file, or contains any
434    class with an EJB component annotation (Stateless, etc.), consider the JAR
435     file to be an EJB module.
436    iii. All other JAR files are ignored unless referenced by a JAR file
437     discovered above using one of the JAR file reference mechanisms such as the
438     Class-Path header in a manifest file.
439     * TODO: rewrite using vfs
440     * @param metaData
441     * @param di
442     */

443    private void scanEar(J2eeApplicationMetaData metaData, DeploymentInfo di)
444       throws IOException JavaDoc
445    {
446       if (di.isDirectory)
447       {
448          File JavaDoc earDir = new File JavaDoc(di.localUrl.getFile());
449          String JavaDoc[] content = earDir.list();
450          int length = content != null ? content.length : 0;
451          for(int n = 0; n < length; n ++)
452          {
453             String JavaDoc module = content[n];
454             if( module.endsWith(".war") )
455             {
456                J2eeModuleMetaData war = new J2eeModuleMetaData(J2eeModuleMetaData.WEB, module);
457                metaData.addModule(war);
458             }
459             else if( module.endsWith(".rar") )
460             {
461                J2eeModuleMetaData war = new J2eeModuleMetaData(J2eeModuleMetaData.CONNECTOR, module);
462                metaData.addModule(war);
463             }
464             else if( module.endsWith(".jar") )
465             {
466                File JavaDoc mfFile = new File JavaDoc(earDir, module+"/META-INF/MANIFEST.MF");
467                File JavaDoc clientXml = new File JavaDoc(earDir, module+"/META-INF/application-client.xml");
468                File JavaDoc ejbXml = new File JavaDoc(earDir, module+"/META-INF/ejb-jar.xml");
469                if( clientXml.exists() )
470                {
471                   J2eeModuleMetaData car = new J2eeModuleMetaData(J2eeModuleMetaData.CONNECTOR, module);
472                   metaData.addModule(car);
473                }
474                else if( mfFile.exists() )
475                {
476                   FileInputStream JavaDoc fis = new FileInputStream JavaDoc(mfFile);
477                   Manifest JavaDoc mf = new Manifest JavaDoc(fis);
478                   fis.close();
479                   Attributes JavaDoc attrs = mf.getMainAttributes();
480                   if( attrs.containsKey(Attributes.Name.MAIN_CLASS) )
481                   {
482                      J2eeModuleMetaData car = new J2eeModuleMetaData(J2eeModuleMetaData.CONNECTOR, module);
483                      metaData.addModule(car);
484                   }
485                }
486                else if( ejbXml.exists() )
487                {
488                   J2eeModuleMetaData ejb = new J2eeModuleMetaData(J2eeModuleMetaData.EJB, module);
489                   metaData.addModule(ejb);
490                }
491                else
492                {
493                   // TODO: scan for annotations
494
}
495             }
496          }
497       }
498       else
499       {
500          JarFile JavaDoc earFile = new JarFile JavaDoc(di.localUrl.getFile());
501          for (Enumeration JavaDoc e = earFile.entries(); e.hasMoreElements();)
502          {
503             JarEntry JavaDoc entry = (JarEntry JavaDoc)e.nextElement();
504             String JavaDoc module = entry.getName();
505             if( module.endsWith(".war") )
506             {
507                J2eeModuleMetaData war = new J2eeModuleMetaData(J2eeModuleMetaData.WEB, module);
508                metaData.addModule(war);
509             }
510             else if( module.endsWith(".rar") )
511             {
512                J2eeModuleMetaData war = new J2eeModuleMetaData(J2eeModuleMetaData.CONNECTOR, module);
513                metaData.addModule(war);
514             }
515             else if( module.endsWith(".jar") )
516             {
517                InputStream JavaDoc is = earFile.getInputStream(entry);
518                JarInputStream JavaDoc jis = new JarInputStream JavaDoc(is);
519                Manifest JavaDoc mf = jis.getManifest();
520                if( mf != null )
521                {
522                   Attributes JavaDoc attrs = mf.getMainAttributes();
523                   if( attrs.containsKey(Attributes.Name.MAIN_CLASS) )
524                   {
525                      J2eeModuleMetaData car = new J2eeModuleMetaData(J2eeModuleMetaData.CONNECTOR, module);
526                      metaData.addModule(car);
527                      jis.close();
528                      continue;
529                   }
530                }
531                JarEntry JavaDoc jarEntry = jis.getNextJarEntry();
532                while( jarEntry != null )
533                {
534                   String JavaDoc name = jarEntry.getName();
535                   if( name.equals("META-INF/application-client.xml") )
536                   {
537                      J2eeModuleMetaData car = new J2eeModuleMetaData(J2eeModuleMetaData.CONNECTOR, module);
538                      metaData.addModule(car);
539                   }
540                   else if( name.equals("META-INF/ejb-jar.xml") )
541                   {
542                      J2eeModuleMetaData ejb = new J2eeModuleMetaData(J2eeModuleMetaData.EJB, module);
543                      metaData.addModule(ejb);
544                   }
545                   jarEntry = jis.getNextJarEntry();
546                }
547                jis.close();
548                // TODO: scan for annotations
549
}
550          }
551       }
552    }
553
554    /**
555     * Add any ear library-directory jars to the deployment classpath
556     * @param di
557     * @param lib
558     * @throws IOException
559     */

560    private void addLibraryJars(DeploymentInfo di, String JavaDoc lib)
561       throws IOException JavaDoc
562    {
563       if (di.isDirectory)
564       {
565          File JavaDoc earDir = new File JavaDoc(di.localUrl.getFile(), lib);
566          String JavaDoc[] content = earDir.list();
567          int length = content != null ? content.length : 0;
568          for(int n = 0; n < length; n ++)
569          {
570             String JavaDoc path = "lib/" + content[n];
571             URL JavaDoc jarURL = new URL JavaDoc(di.localUrl, path);
572             di.addLibraryJar(jarURL);
573          }
574       }
575       else
576       {
577          JarFile JavaDoc earFile = new JarFile JavaDoc(di.localUrl.getFile());
578          for (Enumeration JavaDoc e = earFile.entries(); e.hasMoreElements();)
579          {
580             JarEntry JavaDoc entry = (JarEntry JavaDoc)e.nextElement();
581             String JavaDoc path = "lib/" + entry.getName();
582             URL JavaDoc jarURL = new URL JavaDoc(di.localUrl, path);
583             di.addLibraryJar(jarURL);
584          }
585       }
586    }
587
588 }
589
Popular Tags