KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > tc5 > TomcatDeployer


1 /*
2  * JBoss, Home of Professional Open Source
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.web.tomcat.tc5;
8
9 import java.io.File JavaDoc;
10 import java.io.FileOutputStream JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.net.URL JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Set JavaDoc;
18 import java.util.zip.ZipEntry JavaDoc;
19 import java.util.zip.ZipFile JavaDoc;
20 import java.security.CodeSource JavaDoc;
21 import java.security.cert.Certificate JavaDoc;
22
23 import javax.management.Attribute JavaDoc;
24 import javax.management.ObjectInstance JavaDoc;
25 import javax.management.ObjectName JavaDoc;
26
27 import org.apache.catalina.Loader;
28 import org.apache.catalina.session.StandardManager;
29 import org.jboss.deployment.DeploymentException;
30 import org.jboss.deployment.DeploymentInfo;
31 import org.jboss.metadata.WebMetaData;
32 import org.jboss.web.AbstractWebContainer;
33 import org.jboss.web.AbstractWebDeployer;
34 import org.jboss.web.WebApplication;
35 import org.jboss.web.tomcat.security.JaccContextValve;
36 import org.jboss.web.tomcat.security.SecurityAssociationValve;
37 import org.jboss.web.tomcat.security.CustomPrincipalValve;
38 import org.jboss.web.tomcat.tc5.session.ClusteredSessionValve;
39 import org.jboss.web.tomcat.tc5.session.ClusteringNotSupportedException;
40 import org.jboss.web.tomcat.tc5.session.InstantSnapshotManager;
41 import org.jboss.web.tomcat.tc5.session.IntervalSnapshotManager;
42 import org.jboss.web.tomcat.tc5.session.AbstractJBossManager;
43 import org.jboss.web.tomcat.tc5.session.SnapshotManager;
44
45 /**
46  * The tomcat web application deployer
47  *
48  * @author Scott.Stark@jboss.org
49  * @author Costin Manolache
50  * @version $Revision: 1.26.2.10 $
51  */

52 public class TomcatDeployer extends AbstractWebDeployer
53 {
54    /**
55     * The name of the war level context configuration descriptor
56     */

57    private static final String JavaDoc CONTEXT_CONFIG_FILE = "WEB-INF/context.xml";
58
59    private DeployerConfig config;
60    private String JavaDoc[] javaVMs =
61       {" jboss.management.local:J2EEServer=Local,j2eeType=JVM,name=localhost"};
62    private String JavaDoc serverName = "jboss";
63    private HashMap JavaDoc vhostToHostNames = new HashMap JavaDoc();
64
65    public void init(Object JavaDoc containerConfig) throws Exception JavaDoc
66    {
67       this.config = (DeployerConfig) containerConfig;
68       super.setJava2ClassLoadingCompliance(config.isJava2ClassLoadingCompliance());
69       super.setUnpackWars(config.isUnpackWars());
70       super.setLenientEjbLink(config.isLenientEjbLink());
71       super.setDefaultSecurityDomain(config.getDefaultSecurityDomain());
72    }
73
74    /**
75     * Perform the tomcat specific deployment steps.
76     */

77    protected void performDeploy(WebApplication appInfo, String JavaDoc warUrl,
78       AbstractWebContainer.WebDescriptorParser webAppParser)
79       throws Exception JavaDoc
80    {
81       WebMetaData metaData = appInfo.getMetaData();
82       String JavaDoc hostName = null;
83       // Get any jboss-web/virtual-hosts
84
Iterator JavaDoc vhostNames = metaData.getVirtualHosts();
85       // Map the virtual hosts onto the configured hosts
86
Iterator JavaDoc hostNames = mapVirtualHosts(vhostNames);
87       if (hostNames.hasNext())
88       {
89          hostName = hostNames.next().toString();
90       }
91       performDeployInternal(hostName, appInfo, warUrl, webAppParser);
92       while (hostNames.hasNext())
93       {
94          String JavaDoc additionalHostName = hostNames.next().toString();
95          performDeployInternal(additionalHostName, appInfo, warUrl, webAppParser);
96       }
97    }
98
99    protected void performDeployInternal(String JavaDoc hostName,
100       WebApplication appInfo, String JavaDoc warUrl,
101       AbstractWebContainer.WebDescriptorParser webAppParser)
102       throws Exception JavaDoc
103    {
104
105       WebMetaData metaData = appInfo.getMetaData();
106       String JavaDoc ctxPath = metaData.getContextRoot();
107       if (ctxPath.equals("/") || ctxPath.equals("/ROOT") || ctxPath.equals(""))
108       {
109          log.debug("deploy root context=" + ctxPath);
110          ctxPath = "/";
111          metaData.setContextRoot(ctxPath);
112       }
113       log.info("deploy, ctxPath=" + ctxPath + ", warUrl=" + warUrl);
114
115       URL JavaDoc url = new URL JavaDoc(warUrl);
116
117       ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
118       /* If we are using the jboss class loader we need to augment its path
119       to include the WEB-INF/{lib,classes} dirs or else scoped class loading
120       does not see the war level overrides. The call to setWarURL adds these
121       paths to the deployment UCL.
122       */

123       Loader webLoader = null;
124       if (config.isUseJBossWebLoader())
125       {
126          WebCtxLoader jbossLoader = new WebCtxLoader(loader);
127          jbossLoader.setWarURL(url);
128          webLoader = jbossLoader;
129       }
130       else
131       {
132          String JavaDoc[] pkgs = config.getFilteredPackages();
133          WebAppLoader jbossLoader = new WebAppLoader(loader, pkgs);
134          webLoader = jbossLoader;
135       }
136
137       // We need to establish the JNDI ENC prior to the start
138
// of the web container so that init on startup servlets are able
139
// to interact with their ENC. We hook into the context lifecycle
140
// events to be notified of the start of the
141
// context as this occurs before the servlets are started.
142
if (appInfo.getAppData() == null)
143          webAppParser.parseWebAppDescriptors(loader, appInfo.getMetaData());
144
145       appInfo.setName(url.getPath());
146       appInfo.setClassLoader(loader);
147       appInfo.setURL(url);
148
149       String JavaDoc objectNameS = config.getCatalinaDomain()
150          + ":j2eeType=WebModule,name=//" +
151          ((hostName == null) ? "localhost" : hostName)
152          + ctxPath + ",J2EEApplication=none,J2EEServer=none";
153
154       ObjectName JavaDoc objectName = new ObjectName JavaDoc(objectNameS);
155
156       if (server.isRegistered(objectName))
157       {
158          log.debug("Already exists, destroying " + objectName);
159          server.invoke(objectName, "destroy", new Object JavaDoc[]{},
160             new String JavaDoc[]{});
161       }
162
163       server.createMBean("org.apache.commons.modeler.BaseModelMBean",
164          objectName, new Object JavaDoc[]{config.getContextClassName()},
165          new String JavaDoc[]{"java.lang.String"});
166
167       // Find and set config file on the context
168
// If WAR is packed, expand config file to temp folder
169
String JavaDoc ctxConfig = null;
170       try
171       {
172          ctxConfig = findConfig(url);
173       }
174       catch (IOException JavaDoc e)
175       {
176          log.debug("No " + CONTEXT_CONFIG_FILE + " in " + url, e);
177       }
178
179       server.setAttribute(objectName, new Attribute JavaDoc("docBase", url.getFile()));
180
181       server.setAttribute(objectName, new Attribute JavaDoc("configFile", ctxConfig));
182
183       server.setAttribute(objectName, new Attribute JavaDoc
184          ("defaultContextXml", "context.xml"));
185       server.setAttribute(objectName, new Attribute JavaDoc
186          ("defaultWebXml", "conf/web.xml"));
187
188       server.setAttribute(objectName, new Attribute JavaDoc("javaVMs", javaVMs));
189
190       server.setAttribute(objectName, new Attribute JavaDoc("server", serverName));
191
192       server.setAttribute(objectName, new Attribute JavaDoc
193          ("saveConfig", Boolean.FALSE));
194
195       if (webLoader != null)
196       {
197          server.setAttribute(objectName, new Attribute JavaDoc
198             ("loader", webLoader));
199       }
200       else
201       {
202          server.setAttribute(objectName, new Attribute JavaDoc
203             ("parentClassLoader", loader));
204       }
205
206       server.setAttribute(objectName, new Attribute JavaDoc
207          ("delegate", new Boolean JavaDoc(getJava2ClassLoadingCompliance())));
208
209       String JavaDoc[] jspCP = getCompileClasspath(loader);
210       StringBuffer JavaDoc classpath = new StringBuffer JavaDoc();
211       for (int u = 0; u < jspCP.length; u++)
212       {
213          String JavaDoc repository = jspCP[u];
214          if (repository == null)
215             continue;
216          if (repository.startsWith("file://"))
217             repository = repository.substring(7);
218          else if (repository.startsWith("file:"))
219             repository = repository.substring(5);
220          else
221             continue;
222          if (repository == null)
223             continue;
224          // ok it is a file. Make sure that is is a directory or jar file
225
File JavaDoc fp = new File JavaDoc(repository);
226          if (!fp.isDirectory())
227          {
228             // if it is not a directory, try to open it as a zipfile.
229
try
230             {
231                ZipFile JavaDoc zip = new ZipFile JavaDoc(fp);
232                zip.close();
233             }
234             catch (IOException JavaDoc e)
235             {
236                continue;
237             }
238
239          }
240          if (u > 0)
241             classpath.append(File.pathSeparator);
242          classpath.append(repository);
243       }
244
245       server.setAttribute(objectName, new Attribute JavaDoc
246          ("compilerClasspath", classpath.toString()));
247
248       // Set the session cookies flag according to metadata
249
switch (metaData.getSessionCookies())
250       {
251          case WebMetaData.SESSION_COOKIES_ENABLED:
252             server.setAttribute(objectName, new Attribute JavaDoc
253                ("cookies", new Boolean JavaDoc(true)));
254             log.debug("Enabling session cookies");
255             break;
256          case WebMetaData.SESSION_COOKIES_DISABLED:
257             server.setAttribute(objectName, new Attribute JavaDoc
258                ("cookies", new Boolean JavaDoc(false)));
259             log.debug("Disabling session cookies");
260             break;
261          default:
262             log.debug("Using session cookies default setting");
263       }
264
265       // Add a valve to estalish the JACC context before authorization valves
266
Certificate JavaDoc[] certs = null;
267       CodeSource JavaDoc cs = new CodeSource JavaDoc(url, certs);
268       JaccContextValve jaccValve = new JaccContextValve(metaData.getJaccContextID(), cs);
269       server.invoke(objectName, "addValve",
270          new Object JavaDoc[]{jaccValve},
271          new String JavaDoc[]{"org.apache.catalina.Valve"});
272
273       // Init the container; this will also start it
274
server.invoke(objectName, "init", new Object JavaDoc[]{}, new String JavaDoc[]{});
275
276       if (metaData.getDistributable())
277       {
278          // Try to initate clustering, fallback to standard if no clustering is available
279
try
280          {
281             AbstractJBossManager manager = null;
282             String JavaDoc managerClassName = config.getManagerClass();
283             Class JavaDoc managerClass = Thread.currentThread().getContextClassLoader().loadClass(managerClassName);
284             manager = (AbstractJBossManager) managerClass.newInstance();
285             String JavaDoc name = "//" + ((hostName == null) ? "localhost" : hostName) + ctxPath;
286             manager.init(name, metaData, config.isUseJK(), config.isUseLocalCache());
287             server.setAttribute(objectName, new Attribute JavaDoc("manager", manager));
288
289             if (manager instanceof AbstractJBossManager)
290             {
291                // choose the snapshot manager
292
SnapshotManager snap = null;
293                String JavaDoc snapshotMode = config.getSnapshotMode();
294                int snapshotInterval = config.getSnapshotInterval();
295                if (snapshotMode.equals("instant"))
296                {
297                   snap = new InstantSnapshotManager(manager, ctxPath);
298                }
299                else if (snapshotMode.equals("interval"))
300                {
301                   snap = new IntervalSnapshotManager(manager, ctxPath, snapshotInterval);
302                }
303                else
304                {
305                   log.error("Snapshot mode must be 'instant' or 'interval' - using 'instant'");
306                   snap = new InstantSnapshotManager(manager, ctxPath);
307                }
308                // Adding session snapshot valve
309
Object JavaDoc valve = new ClusteredSessionValve(snap);
310                server.invoke(objectName, "addValve",
311                   new Object JavaDoc[]{valve},
312                   new String JavaDoc[]{"org.apache.catalina.Valve"});
313             }
314             else
315             {
316                throw new ClusteringNotSupportedException("managerClass " + managerClassName + " not known");
317             }
318
319             log.debug("Enabled clustering support for ctxPath=" + ctxPath);
320          }
321          catch (ClusteringNotSupportedException e)
322          {
323             log.error("Failed to setup clustering, clustering disabled");
324          }
325       }
326
327       /* Add security association valve after the authorization
328       valves so that the authenticated user may be associated with the
329       request thread/session.
330       */

331       SecurityAssociationValve valve = new SecurityAssociationValve(metaData,
332          config.getSecurityManagerService());
333       valve.setSubjectAttributeName(config.getSubjectAttributeName());
334       server.invoke(objectName, "addValve",
335          new Object JavaDoc[]{valve},
336          new String JavaDoc[]{"org.apache.catalina.Valve"});
337
338       /* Install a CustomPrincipalValve after the standard valves to allow
339          any request custom principal to be seen by the web app
340       */

341       CustomPrincipalValve cpvalve = new CustomPrincipalValve();
342       server.invoke(objectName, "addValve",
343          new Object JavaDoc[]{cpvalve},
344          new String JavaDoc[]{"org.apache.catalina.Valve"});
345
346       // Retrieve the state, and throw an exception in case of a failure
347
Integer JavaDoc state = (Integer JavaDoc) server.getAttribute(objectName, "state");
348       if (state.intValue() != 1)
349       {
350          throw new DeploymentException("URL " + warUrl + " deployment failed");
351       }
352
353       // make the context class loader known to the WebMetaData, ws4ee needs it
354
// to instanciate service endpoint pojos that live in this webapp
355
Loader ctxLoader = (Loader) server.getAttribute(objectName, "loader");
356       metaData.setContextLoader(ctxLoader.getClassLoader());
357
358       appInfo.setAppData(objectName);
359
360       // Create mbeans for the servlets
361
DeploymentInfo di = webAppParser.getDeploymentInfo();
362       di.deployedObject = objectName;
363       ObjectName JavaDoc servletQuery = new ObjectName JavaDoc
364          (config.getCatalinaDomain() + ":j2eeType=Servlet,WebModule="
365          + objectName.getKeyProperty("name") + ",*");
366       Iterator JavaDoc iterator = server.queryMBeans(servletQuery, null).iterator();
367       while (iterator.hasNext())
368       {
369          di.mbeans.add(((ObjectInstance JavaDoc) iterator.next()).getObjectName());
370       }
371
372       log.debug("Initialized: " + appInfo + " " + objectName);
373
374    }
375
376
377    /**
378     * Called as part of the undeploy() method template to ask the
379     * subclass for perform the web container specific undeployment steps.
380     */

381    protected void performUndeploy(String JavaDoc warUrl, WebApplication appInfo)
382       throws Exception JavaDoc
383    {
384       if (appInfo == null)
385       {
386          log.debug("performUndeploy, no WebApplication found for URL "
387             + warUrl);
388          return;
389       }
390
391       log.info("undeploy, ctxPath=" + appInfo.getMetaData().getContextRoot()
392          + ", warUrl=" + warUrl);
393
394       WebMetaData metaData = appInfo.getMetaData();
395       String JavaDoc hostName = null;
396       Iterator JavaDoc hostNames = metaData.getVirtualHosts();
397       if (hostNames.hasNext())
398       {
399          hostName = hostNames.next().toString();
400       }
401       performUndeployInternal(hostName, warUrl, appInfo);
402       while (hostNames.hasNext())
403       {
404          String JavaDoc additionalHostName = hostNames.next().toString();
405          performUndeployInternal(additionalHostName, warUrl, appInfo);
406       }
407
408    }
409
410    protected void performUndeployInternal(String JavaDoc hostName, String JavaDoc warUrl,
411       WebApplication appInfo)
412       throws Exception JavaDoc
413    {
414
415       WebMetaData metaData = appInfo.getMetaData();
416       String JavaDoc ctxPath = metaData.getContextRoot();
417
418       // If the server is gone, all apps were stopped already
419
if (server == null)
420          return;
421
422       ObjectName JavaDoc objectName = new ObjectName JavaDoc(config.getCatalinaDomain()
423          + ":j2eeType=WebModule,name=//" +
424          ((hostName == null) ? "localhost" : hostName)
425          + ctxPath + ",J2EEApplication=none,J2EEServer=none");
426
427       if (server.isRegistered(objectName))
428       {
429          // Contexts should be stopped by the host already
430
server.invoke(objectName, "destroy", new Object JavaDoc[]{},
431             new String JavaDoc[]{});
432       }
433
434    }
435
436    /**
437     * Resolve the input virtual host names to the names of the configured Hosts
438     * @param vhostNames Iterator<String> for the jboss-web/virtual-host elements
439     * @return Iterator<String> of the unique Host names
440     * @throws Exception
441     */

442    protected synchronized Iterator JavaDoc mapVirtualHosts(Iterator JavaDoc vhostNames)
443       throws Exception JavaDoc
444    {
445       if( vhostToHostNames.size() == 0 )
446       {
447          // Query the configured Host mbeans
448
String JavaDoc hostQuery = config.getCatalinaDomain() + ":type=Host,*";
449          ObjectName JavaDoc query = new ObjectName JavaDoc(hostQuery);
450          Set JavaDoc hosts = server.queryNames(query, null);
451          Iterator JavaDoc iter = hosts.iterator();
452          while( iter.hasNext() )
453          {
454             ObjectName JavaDoc host = (ObjectName JavaDoc) iter.next();
455             String JavaDoc name = host.getKeyProperty("host");
456             if( name != null )
457             {
458                vhostToHostNames.put(name, name);
459                 String JavaDoc[] aliases = (String JavaDoc[])
460                     server.invoke(host, "findAliases", null, null);
461                int count = aliases != null ? aliases.length : 0;
462                for(int n = 0;n < count; n ++)
463                {
464                   vhostToHostNames.put(aliases[n], name);
465                }
466             }
467          }
468       }
469
470       // Map the virtual host names to the hosts
471
HashSet JavaDoc hosts = new HashSet JavaDoc();
472       while( vhostNames.hasNext() )
473       {
474          String JavaDoc vhost = (String JavaDoc) vhostNames.next();
475          String JavaDoc host = (String JavaDoc) vhostToHostNames.get(vhost);
476          if( host == null )
477          {
478             log.warn("Failed to map vhost: "+vhost);
479             // This will cause a new host to be created
480
host = vhost;
481          }
482          hosts.add(host);
483       }
484       return hosts.iterator();
485    }
486
487    private String JavaDoc findConfig(URL JavaDoc warURL) throws IOException JavaDoc
488    {
489       String JavaDoc result = null;
490       // See if the warUrl is a dir or a file
491
File JavaDoc warFile = new File JavaDoc(warURL.getFile());
492       if (warURL.getProtocol().equals("file") && warFile.isDirectory() == true)
493       {
494          File JavaDoc webDD = new File JavaDoc(warFile, CONTEXT_CONFIG_FILE);
495          if (webDD.exists() == true) result = webDD.getAbsolutePath();
496       }
497       else
498       {
499          ZipFile JavaDoc zipFile = new ZipFile JavaDoc(warFile);
500          ZipEntry JavaDoc entry = zipFile.getEntry(CONTEXT_CONFIG_FILE);
501          if (entry != null)
502          {
503             InputStream JavaDoc zipIS = zipFile.getInputStream(entry);
504             byte[] buffer = new byte[512];
505             int bytes;
506             result = warFile.getAbsolutePath() + "-context.xml";
507             FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(result);
508             while ((bytes = zipIS.read(buffer)) > 0)
509             {
510                fos.write(buffer, 0, bytes);
511             }
512             zipIS.close();
513             fos.close();
514          }
515          zipFile.close();
516       }
517       return result;
518    }
519
520 }
521
Popular Tags