001: /*
002: * Tomcat: The deployer for the tomcat daemon
003: * Copyright (C) 2007 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * TomcatWrapper.java
020: */
021:
022: // package path
023: package com.rift.coad.daemon.tomcat;
024:
025: // java imports
026: import java.net.InetAddress;
027: import java.io.File;
028: import java.net.URLClassLoader;
029: import java.net.URL;
030: import java.util.Map;
031: import java.util.HashMap;
032: import javax.management.MBeanServer;
033: import javax.management.ObjectName;
034:
035: // log 4 j imports
036: import org.apache.log4j.Logger;
037:
038: // configuration
039: import com.rift.coad.lib.common.FileUtil;
040: import com.rift.coad.lib.configuration.ConfigurationFactory;
041: import com.rift.coad.lib.configuration.Configuration;
042:
043: // tomcat imports
044: import com.rift.coad.lib.naming.NamingDirector;
045: import org.apache.catalina.Context;
046: import org.apache.catalina.Engine;
047: import org.apache.catalina.Host;
048: import org.apache.catalina.Session;
049: import org.apache.catalina.connector.Connector;
050: import org.apache.catalina.Loader;
051: import org.apache.catalina.loader.StandardClassLoader;
052: import org.apache.catalina.Lifecycle;
053: import org.apache.catalina.Container;
054: import org.apache.catalina.Server;
055: import org.apache.catalina.Service;
056: import org.apache.catalina.security.SecurityClassLoad;
057: import org.apache.catalina.startup.*;
058: import org.apache.tomcat.util.modeler.Registry;
059:
060: /**
061: * This object is responsible for wrappping the tomcat startup
062: *
063: * @author brett chaldecott
064: */
065: public class TomcatWrapper {
066:
067: // logger
068: private static Logger log = Logger.getLogger(TomcatWrapper.class
069: .getName());
070: private static String TOMCAT_DEPLOY_DIR = "/webapps";
071: private static String TOMCAT_CONF_DIR = "/conf";
072: private static String TOMCAT_MANAGER = "manager";
073: private static String TOMCAT_ROOT = "ROOT";
074: private static String TOMCAT_SERVER_CONFIG = "server.xml";
075: private static String TOMCAT_WEB_CONFIG = "web.xml";
076:
077: // private member variables
078: private String defaultHost = null;
079: private String basePath = null;
080:
081: // default host and root context
082: private Catalina tomcat = null;
083: private Map contexts = new HashMap();
084: private ClassLoader masterLoader = null;
085: private ClassLoader childLoader = null;
086: private MBeanServer mBeanServer = null;
087: private ObjectName oName = null;
088:
089: /**
090: * Creates a new instance of TomcatWrapper
091: */
092: public TomcatWrapper() throws TomcatException {
093: ClassLoader currentLoader = Thread.currentThread()
094: .getContextClassLoader();
095: try {
096: // work around for the Apache jndi problems
097: String originalPkgPefix = System
098: .getProperty(javax.naming.Context.URL_PKG_PREFIXES);
099:
100: // setup the class loaders
101: masterLoader = createClassLoader(
102: ((URLClassLoader) currentLoader).getURLs(),
103: currentLoader);
104: childLoader = createClassLoader(
105: ((URLClassLoader) currentLoader).getURLs(),
106: masterLoader);
107: SecurityClassLoad.securityClassLoad(childLoader);
108: Thread.currentThread().setContextClassLoader(childLoader);
109: Configuration configuration = ConfigurationFactory
110: .getInstance().getConfig(this .getClass());
111:
112: // basic config
113: basePath = configuration.getString("TomcatBasePath");
114:
115: // clear out the directory
116: clearWebAppDirectory();
117:
118: // clear out the configuration
119: clearConfigDirectory();
120:
121: // setup the catalina home directory
122: System.setProperty("CatalinaHome", basePath);
123: tomcat = new Catalina();
124: tomcat.setParentClassLoader(childLoader);
125: tomcat.setCatalinaHome(basePath);
126:
127: // start tomcat
128: log.info("Starting the engine.");
129: tomcat.start();
130: log.info("Engine started");
131:
132: // force reset of naming search path as Tomcat assumes it is the
133: // owner of the path
134: System.setProperty(javax.naming.Context.URL_PKG_PREFIXES,
135: originalPkgPefix);
136:
137: // retrieve the reference to the bean server
138: mBeanServer = Registry.getRegistry(null, null)
139: .getMBeanServer();
140:
141: // the object name
142: oName = new ObjectName(
143: "Coadunation:type=Deployer,host=localhost");
144:
145: } catch (Exception ex) {
146: log.error("Failed to init tomcat : " + ex.getMessage(), ex);
147: throw new TomcatException("Failed to init tomcat : "
148: + ex.getMessage(), ex);
149: } finally {
150: Thread.currentThread().setContextClassLoader(currentLoader);
151: }
152:
153: }
154:
155: /**
156: * This method will load the specified war file.
157: */
158: public void loadWar(File war) {
159: ClassLoader currentLoader = Thread.currentThread()
160: .getContextClassLoader();
161: try {
162: log.info("Deploy the file [" + war.getPath() + "]");
163: Thread.currentThread().setContextClassLoader(childLoader);
164: String context = getWarContext(war);
165: // check if it is deployed
166: if (isDeployed(context)) {
167: unDeployed(context);
168: }
169: FileUtil.copyFile(war, new File(basePath
170: + TOMCAT_DEPLOY_DIR, context + ".war"));
171: check(context);
172: contexts.put(war.getPath(), context);
173: log.info("Deployed the file [" + war.getPath() + "]");
174: } catch (Exception ex) {
175: log.error("Failed to load the war file : "
176: + ex.getMessage(), ex);
177: } finally {
178: Thread.currentThread().setContextClassLoader(currentLoader);
179: }
180: }
181:
182: /**
183: * This method unloads the given war file.
184: *
185: * @param war The ware file object.
186: */
187: public void unloadWar(File war) {
188: ClassLoader currentLoader = Thread.currentThread()
189: .getContextClassLoader();
190: try {
191: Thread.currentThread().setContextClassLoader(childLoader);
192: log.info("Unload the file [" + war.getPath() + "]");
193: String context = (String) contexts.remove(war.getPath());
194: unDeployed(context);
195: } catch (Exception ex) {
196: log.error("Failed to unload the war file : "
197: + ex.getMessage(), ex);
198: } finally {
199: Thread.currentThread().setContextClassLoader(currentLoader);
200: }
201: }
202:
203: /**
204: * This method check if the specified object is deployed.
205: *
206: * @return True if context is deployed.
207: * @param context The context to deploy.
208: * @exception Exception
209: */
210: private boolean isDeployed(String context) throws Exception {
211: String[] params = { context };
212: String[] signature = { "java.lang.String" };
213: Boolean result = (Boolean) mBeanServer.invoke(oName,
214: "isDeployed", params, signature);
215: return result.booleanValue();
216: }
217:
218: /**
219: * This method check if the specified object is deployed.
220: *
221: * @return True if context is deployed.
222: * @param context The context to deploy.
223: * @exception Exception
224: */
225: private void check(String context) throws Exception {
226: String[] params = { context };
227: String[] signature = { "java.lang.String" };
228: mBeanServer.invoke(oName, "check", params, signature);
229: }
230:
231: /**
232: * This method will undeploy the object in the context
233: *
234: * @return True if context is deployed.
235: * @param context The context to deploy.
236: * @exception Exception
237: */
238: private void unDeployed(String context) throws Exception {
239: try {
240: log.info("Undeploy the context [" + context + "]");
241: String strippedContext = context.substring(1);
242: File[] files = new File(basePath + TOMCAT_DEPLOY_DIR)
243: .listFiles();
244: for (int index = 0; index < files.length; index++) {
245: if (files[index].getName().equals(strippedContext)
246: || files[index].getName().equals(
247: strippedContext + ".war")) {
248: log
249: .info("Delete the target [" + files[index]
250: + "]");
251: FileUtil.delTargetRecursive(files[index]);
252: }
253: }
254: check(context);
255: } catch (Exception ex) {
256: log.error("Failed to clear out the webapp directory :"
257: + ex.getMessage());
258: throw new TomcatException(
259: "Failed to clear out the webapp directory :"
260: + ex.getMessage());
261: }
262: }
263:
264: /**
265: * This method is called to stop tomcat
266: */
267: public void stop() {
268: try {
269: tomcat.stop();
270: } catch (Exception ex) {
271: log.error("Failed to stop tomcat : " + ex.getMessage(), ex);
272: }
273: }
274:
275: /**
276: * This method creates the new class loader
277: */
278: private ClassLoader createClassLoader(URL[] urls, ClassLoader parent) {
279: try {
280: String[] locations = new String[urls.length];
281: Integer[] types = new Integer[urls.length];
282: for (int index = 0; index < urls.length; index++) {
283: locations[index] = urls[index].toString();
284: types[index] = new Integer(3);
285: }
286: return ClassLoaderFactory.createClassLoader(locations,
287: types, parent);
288: } catch (Exception ex) {
289: log.error("Failed to create a new class loader : "
290: + ex.getMessage(), ex);
291: return parent;
292: }
293: }
294:
295: /**
296: * This method clears out the web app directory.
297: */
298: private void clearWebAppDirectory() throws TomcatException {
299: try {
300: File[] files = new File(basePath + TOMCAT_DEPLOY_DIR)
301: .listFiles();
302: for (int index = 0; index < files.length; index++) {
303: if (files[index].getName().equals(TOMCAT_ROOT)
304: || files[index].getName()
305: .equals(TOMCAT_MANAGER)) {
306: continue;
307: }
308: log.info("Remove the file [" + files[index] + "]");
309: FileUtil.delTargetRecursive(files[index]);
310: }
311: } catch (Exception ex) {
312: log.error("Failed to clear out the webapp directory :"
313: + ex.getMessage());
314: throw new TomcatException(
315: "Failed to clear out the webapp directory :"
316: + ex.getMessage());
317: }
318: }
319:
320: /**
321: * This method clears out the configuration directory.
322: */
323: private void clearConfigDirectory() throws TomcatException {
324: try {
325: File[] files = new File(basePath + TOMCAT_CONF_DIR)
326: .listFiles();
327: for (int index = 0; index < files.length; index++) {
328: if (files[index].getName().equals(TOMCAT_SERVER_CONFIG)
329: || files[index].getName().equals(
330: TOMCAT_WEB_CONFIG)) {
331: continue;
332: }
333: FileUtil.delTargetRecursive(files[index]);
334: }
335: } catch (Exception ex) {
336: log
337: .error("Failed to clear out the configuration directory :"
338: + ex.getMessage());
339: throw new TomcatException(
340: "Failed to clear out the configuration directory :"
341: + ex.getMessage());
342: }
343: }
344:
345: /**
346: * This method retrieves the context for the war file.
347: *
348: * @return The context for this file.
349: * @param war The war file.
350: */
351: private String getWarContext(File war) {
352: try {
353: TomcatXMLContext xmlParser = new TomcatXMLContext(
354: new URLClassLoader(new URL[] { war.toURL() }));
355: return xmlParser.getContext();
356: } catch (Exception ex) {
357: log.warn(
358: "Failed to retrieve the Tomcat context from the war ["
359: + ex.getMessage()
360: + "] defaulting to file name.", ex);
361: }
362: return war.getName().replaceAll(" ", "_");
363: }
364: }
|