0001: /**
0002: * JOnAS: Java(TM) Open Application Server
0003: * Copyright (C) 2005-2006 Bull S.A.
0004: * Contact: jonas-team@objectweb.org
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2.1 of the License, or any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
0019: * USA
0020: *
0021: * --------------------------------------------------------------------------
0022: * $Id: CatalinaJWebContainerServiceImpl.java 9906 2007-01-09 10:25:37Z benoitf $
0023: * --------------------------------------------------------------------------
0024: */package org.objectweb.jonas.web.catalina55;
0025:
0026: import java.io.File;
0027: import java.io.FileInputStream;
0028: import java.io.FileNotFoundException;
0029: import java.io.InputStream;
0030: import java.net.URL;
0031: import java.rmi.RemoteException;
0032: import java.util.ArrayList;
0033: import java.util.Iterator;
0034: import java.util.List;
0035: import java.util.StringTokenizer;
0036: import java.util.Vector;
0037:
0038: import javax.management.InstanceAlreadyExistsException;
0039: import javax.management.MBeanRegistrationException;
0040: import javax.management.MBeanServer;
0041: import javax.management.MalformedObjectNameException;
0042: import javax.management.NotCompliantMBeanException;
0043: import javax.management.ObjectName;
0044: import javax.naming.LinkRef;
0045: import javax.naming.NamingException;
0046: import javax.naming.Reference;
0047: import javax.naming.StringRefAddr;
0048:
0049: import org.xml.sax.InputSource;
0050:
0051: import org.apache.catalina.Container;
0052: import org.apache.catalina.Context;
0053: import org.apache.catalina.Engine;
0054: import org.apache.catalina.Host;
0055: import org.apache.catalina.Lifecycle;
0056: import org.apache.catalina.LifecycleException;
0057: import org.apache.catalina.Realm;
0058: import org.apache.catalina.Server;
0059: import org.apache.catalina.Service;
0060: import org.apache.catalina.connector.Connector;
0061: import org.apache.catalina.core.StandardContext;
0062: import org.apache.catalina.core.StandardEngine;
0063: import org.apache.catalina.core.StandardServer;
0064: import org.apache.catalina.deploy.ContextResource;
0065: import org.apache.catalina.deploy.NamingResources;
0066: import org.apache.catalina.startup.ContextConfig;
0067: import org.apache.commons.modeler.Registry;
0068: import org.apache.tomcat.util.digester.Digester;
0069:
0070: import org.objectweb.jonas_lib.I18n;
0071:
0072: import org.objectweb.jonas.jmx.J2eeObjectName;
0073: import org.objectweb.jonas.jmx.JonasObjectName;
0074: import org.objectweb.jonas.security.realm.web.catalina55.JACC;
0075: import org.objectweb.jonas.server.LoaderManager;
0076: import org.objectweb.jonas.service.ServiceException;
0077: import org.objectweb.jonas.web.AbsJWebContainerServiceImpl;
0078: import org.objectweb.jonas.web.JWebContainerServiceException;
0079: import org.objectweb.jonas.web.lib.PermissionManager;
0080: import org.objectweb.jonas.web.wrapper.CatalinaJWebContainerService;
0081:
0082: import org.objectweb.util.monolog.api.BasicLevel;
0083:
0084: /**
0085: * This class provides an implementation of the Catalina service
0086: * (as web container service).
0087: * @author Florent Benoit
0088: * @author Ludovic Bert (Tomcat 4.0)
0089: */
0090: public class CatalinaJWebContainerServiceImpl extends
0091: AbsJWebContainerServiceImpl implements
0092: CatalinaJWebContainerService {
0093:
0094: /**
0095: * Relative path of the configuration file
0096: */
0097: protected static final String CONFIG_FILE = "conf/server.xml";
0098:
0099: /**
0100: * Internationalization
0101: */
0102: private static I18n i18n = null;
0103:
0104: /**
0105: * The reference on the catalina server.
0106: */
0107: private Server server = null;
0108:
0109: /**
0110: * The shared extensions class loader for this server.
0111: */
0112: private ClassLoader parentClassLoader = null;
0113:
0114: /**
0115: * Catalina loader
0116: */
0117: private ClassLoader catalinaLoader = null;
0118:
0119: /**
0120: * Web container started ?
0121: */
0122: private boolean tomcatStarted = false;
0123:
0124: /**
0125: * Initialize the Catalina service.
0126: * @param ctx the configuration context of the service.
0127: * @throws ServiceException if the initialization failed.
0128: */
0129: protected void doInit(javax.naming.Context ctx)
0130: throws ServiceException {
0131: super .doInit(ctx);
0132:
0133: // Set the environment
0134: initCatalinaEnvironment();
0135:
0136: // parent ClassLoader
0137: LoaderManager lm = LoaderManager.getInstance();
0138: try {
0139: parentClassLoader = lm.getAppsLoader();
0140: catalinaLoader = lm.getCatalinaLoader();
0141: } catch (Exception e1) {
0142: throw new ServiceException(
0143: "Cannot get Application/Catalina ClassLoader", e1);
0144: }
0145:
0146: // Internationalization
0147: i18n = I18n.getInstance(CatalinaJWebContainerServiceImpl.class,
0148: catalinaLoader);
0149:
0150: // Add JOnAS-Tomcat mbean
0151: if (getLogger().isLoggable(BasicLevel.DEBUG)) {
0152: getLogger().log(BasicLevel.DEBUG,
0153: "Add mbeans descriptions to the JMX Registry");
0154: }
0155: InputStream stream = this
0156: .getClass()
0157: .getResourceAsStream(
0158: "/org/objectweb/jonas/web/catalina55/mbeans-descriptors.xml");
0159: try {
0160: Registry.loadRegistry(stream);
0161: stream.close();
0162: } catch (Exception e) {
0163: getLogger().log(
0164: BasicLevel.ERROR,
0165: "Can't add the mbeans description into Tomcat"
0166: + e.getMessage());
0167: }
0168:
0169: // Add MBean for Catalina Connector creation
0170: CatalinaConnectorFactory cf = new CatalinaConnectorFactory();
0171: MBeanServer mbeanServer = getMbeanServer();
0172: cf.setMyServer(mbeanServer);
0173: if (mbeanServer != null) {
0174: ObjectName on = null;
0175: try {
0176: on = JonasObjectName
0177: .catalinaConnectorFactory(getDomainName());
0178: mbeanServer.registerMBean(cf, on);
0179: } catch (MalformedObjectNameException e1) {
0180: getLogger()
0181: .log(BasicLevel.WARN,
0182: "Can't create Objectname for CatalinaConnectorFactory MBean");
0183: } catch (InstanceAlreadyExistsException e2) {
0184: getLogger()
0185: .log(
0186: BasicLevel.WARN,
0187: "MBean named "
0188: + on.toString()
0189: + "already registered in the MBean server");
0190: } catch (MBeanRegistrationException e2) {
0191: getLogger().log(BasicLevel.WARN,
0192: "Can't register MBean " + on.toString());
0193: e2.printStackTrace();
0194: } catch (NotCompliantMBeanException e2) {
0195: getLogger().log(BasicLevel.WARN,
0196: "Can't register MBean " + on.toString());
0197: e2.printStackTrace();
0198: }
0199: }
0200:
0201: // Add MBean for WebModule Proxy creation
0202: WebModuleProxy px = new WebModuleProxy();
0203: px.setMyServer(mbeanServer);
0204: if (mbeanServer != null) {
0205: ObjectName on = null;
0206: try {
0207: on = JonasObjectName.webModuleProxy(getDomainName());
0208: mbeanServer.registerMBean(px, on);
0209: } catch (MalformedObjectNameException e1) {
0210: getLogger()
0211: .log(BasicLevel.WARN,
0212: "Can't create Objectname for WebModuleProxy MBean");
0213: } catch (InstanceAlreadyExistsException e2) {
0214: getLogger()
0215: .log(
0216: BasicLevel.WARN,
0217: "MBean named "
0218: + on.toString()
0219: + "already registered in the MBean server");
0220: } catch (MBeanRegistrationException e2) {
0221: getLogger().log(BasicLevel.WARN,
0222: "Can't register MBean " + on.toString());
0223: e2.printStackTrace();
0224: } catch (NotCompliantMBeanException e2) {
0225: getLogger().log(BasicLevel.WARN,
0226: "Can't register MBean " + on.toString());
0227: e2.printStackTrace();
0228: }
0229: }
0230: }
0231:
0232: /**
0233: * Init the environment of catalina
0234: * set catalina.home, catalina.base and unset the tomcat naming
0235: * @throws ServiceException if catalina home is not set
0236: */
0237: protected void initCatalinaEnvironment() throws ServiceException {
0238:
0239: // if the user do not specify catalina.base,
0240: // set catalina.base to catalina.home.
0241: String catalinaHome = System.getProperty("catalina.home");
0242: if (catalinaHome != null) {
0243: if (System.getProperty("catalina.base") == null) {
0244: System.setProperty("catalina.base", catalinaHome);
0245: }
0246: } else {
0247: throw new ServiceException(
0248: "catalina.home property is not set");
0249: }
0250:
0251: // use the JOnAS naming instead of Tomcat naming
0252: System.setProperty("catalina.useNaming", "false");
0253: }
0254:
0255: /**
0256: * Start the Catalina service in a new thread
0257: * @throws ServiceException if the startup failed.
0258: */
0259: public void doStart() throws ServiceException {
0260:
0261: // Create the digester for the parsing of the server.xml.
0262: Digester digester = createServerDigester();
0263:
0264: // Execute the digester for the parsing of the server.xml.
0265: // And configure the catalina server.
0266: File configFile = null;
0267:
0268: try {
0269: configFile = getConfigFile();
0270: } catch (FileNotFoundException e) {
0271: String err = i18n.getMessage(
0272: "CatJWebServ.doStart.fileNotFound", configFile, e
0273: .getMessage());
0274: getLogger().log(BasicLevel.ERROR, err);
0275: throw new ServiceException(err, e);
0276: }
0277:
0278: try {
0279: InputSource is = new InputSource("file://"
0280: + configFile.getAbsolutePath());
0281: FileInputStream fis = new FileInputStream(configFile);
0282: is.setByteStream(fis);
0283: digester.push(this );
0284: digester.parse(is);
0285: fis.close();
0286: } catch (Exception e) {
0287: String err = i18n.getMessage(
0288: "CatJWebServ.doStart.readfileError", configFile, e
0289: .getMessage());
0290: getLogger().log(BasicLevel.ERROR, err);
0291: throw new ServiceException(err, e);
0292: }
0293:
0294: javax.naming.Context ctxOld = setGlobalNamingResources();
0295:
0296: // Set the Domain and the name for each known Engine
0297: Iterator it = getEngines().iterator();
0298: while (it.hasNext()) {
0299: StandardEngine oSE = (StandardEngine) it.next();
0300: // WARNING : the order of th two next lines is very important.
0301: // The domain must be set in first and the name after.
0302: // In the others cases, Tomcat 5 doesn't set correctly these two properties
0303: // because there are somes controls that forbid to have a difference between
0304: // the name and the domain. Certainly a bug !
0305: oSE.setDomain(getDomainName());
0306: oSE.setName(getDomainName());
0307: }
0308:
0309: // Finaly start catalina ...
0310: if (server instanceof Lifecycle) {
0311: try {
0312: server.initialize();
0313: ((Lifecycle) server).start();
0314: } catch (Exception e) {
0315: String err = i18n
0316: .getMessage("CatJWebServ.doStart.startCatalinaError");
0317: getLogger().log(BasicLevel.ERROR, err);
0318: throw new ServiceException(e.getMessage(), e);
0319: }
0320: }
0321: // Reset server context
0322: getNaming().setComponentContext(ctxOld);
0323:
0324: // Tomcat is started
0325: tomcatStarted = true;
0326:
0327: // ... and deploy wars of the jonas.properties
0328: super .doStart();
0329: }
0330:
0331: /**
0332: * Defines the naming resources for tomcat
0333: * only use for avoid null pointer when using a server.xml of
0334: * the original distribution
0335: * @return the previous naming context
0336: * @throws ServiceException if a naming exception occurs
0337: */
0338: protected javax.naming.Context setGlobalNamingResources()
0339: throws ServiceException {
0340: // Set the global context of the server
0341: NamingResources namingResources = server
0342: .getGlobalNamingResources();
0343: javax.naming.Context globalCtx = null;
0344: javax.naming.Context ctxold = null;
0345: try {
0346: globalCtx = getNaming().createEnvironmentContext(
0347: "catalina_global");
0348: ctxold = getNaming().setComponentContext(globalCtx);
0349:
0350: int i;
0351: // Resources
0352: ContextResource[] resources = namingResources
0353: .findResources();
0354: for (i = 0; i < resources.length; i++) {
0355: addResource(globalCtx, resources[i]);
0356: }
0357: } catch (NamingException e) {
0358: String err = i18n.getMessage(
0359: "CatJWebServ.doStart.populateEnvError", e
0360: .getMessage());
0361: getLogger().log(BasicLevel.ERROR, err);
0362: throw new ServiceException(err, e);
0363: }
0364: // Set the global naming context of the server
0365: ((StandardServer) server).setGlobalNamingContext(globalCtx);
0366: return ctxold;
0367: }
0368:
0369: /**
0370: * Stop the Catalina service.
0371: * @throws ServiceException if the stop failed.
0372: */
0373: protected void doStop() throws ServiceException {
0374: // Undeploy the wars ...
0375: super .doStop();
0376:
0377: // ... and shut down embedded catalina
0378: if (server instanceof Lifecycle) {
0379: try {
0380: ((Lifecycle) server).stop();
0381: } catch (Exception e) {
0382: String err = i18n
0383: .getMessage("CatJWebServ.doStop.stopCatalinaError");
0384: getLogger().log(BasicLevel.ERROR, err);
0385: throw new ServiceException(e.getMessage(), e);
0386: }
0387: }
0388:
0389: }
0390:
0391: /**
0392: * Deploy a specific WAR file specified in the context.
0393: * @param ctx the context which contains the configuration in order
0394: * to deploy the WAR.
0395: * @throws JWebContainerServiceException if the registration of the WAR
0396: * failed.
0397: */
0398: protected void doRegisterWar(javax.naming.Context ctx)
0399: throws JWebContainerServiceException {
0400: // Get the 7 parameters :
0401: // - warURL is the URL of the war to register (required param).
0402: // - contextRoot is the context root to which this application
0403: // should be installed (must be unique) (required param).
0404: // - hostName is the name of the host on which deploy the war
0405: // (optional param taken into account only if no <context> element
0406: // was declared in server.xml for this web application) .
0407: // - Name of the Ear application of this war if any
0408: // - java2DelegationModel the compliance to java2 delegation model
0409: // - parentCL the war classloader of this war.
0410: // - jonasDD JOnAS Deployment Desc content
0411: // - permissionManager JACC permission manager
0412:
0413: URL warURL = null;
0414: URL earURL = null;
0415: URL unpackedWarURL = null;
0416: String contextRoot = null;
0417: boolean java2DelegationModel = true;
0418: PermissionManager permissionManager = null;
0419: boolean inEarCase = true;
0420: String earAppName = null;
0421: String jonasDD = null;
0422: try {
0423: warURL = (URL) ctx.lookup("warURL");
0424: unpackedWarURL = (URL) ctx.lookup("unpackedWarURL");
0425: contextRoot = (String) ctx.lookup("contextRoot");
0426: Boolean bool = (Boolean) ctx.lookup("java2DelegationModel");
0427: java2DelegationModel = bool.booleanValue();
0428: jonasDD = (String) ctx.lookup("jonasDD");
0429: permissionManager = (PermissionManager) ctx
0430: .lookup("permissionManager");
0431: } catch (NamingException e) {
0432: String err = i18n
0433: .getMessage("CatJWebServ.doRegisterWar.gettingParamError");
0434: getLogger().log(BasicLevel.ERROR, err + e.getMessage());
0435: throw new JWebContainerServiceException(err, e);
0436: }
0437:
0438: try {
0439: earAppName = (String) ctx.lookup("earAppName");
0440: earURL = (URL) ctx.lookup("earURL");
0441: } catch (NamingException e) {
0442: // no ear case, so no ear application name
0443: inEarCase = false;
0444: // set earURL to something only to avoid null value
0445: earURL = warURL;
0446: }
0447:
0448: ClassLoader webClassLoader = null;
0449:
0450: try {
0451: webClassLoader = (ClassLoader) ctx.lookup("parentCL");
0452: } catch (NamingException e) {
0453: String err = i18n
0454: .getMessage("CatJWebServ.doRegisterWar.gettingParamError");
0455: getLogger().log(BasicLevel.ERROR, err + e.getMessage());
0456: throw new JWebContainerServiceException(err, e);
0457: }
0458:
0459: String hostName = null;
0460: try {
0461: hostName = (String) ctx.lookup("hostName");
0462: } catch (NamingException e) {
0463: hostName = "";
0464: }
0465:
0466: // Install a new web application, whose web application archive is
0467: // at the specified URL, into this container with the specified
0468: // context root.
0469: // A context root of "" (the empty string) should be used for the root
0470: // application for this container. Otherwise, the context root must
0471: // start with a slash.
0472:
0473: if (contextRoot.equals("/")) {
0474: contextRoot = "";
0475: } else {
0476: contextRoot = "/" + contextRoot;
0477: }
0478:
0479: // Install the war.
0480: File fWar = new File(warURL.getFile());
0481: //File fpackedWar = new File(packedWarURL.getFile());
0482:
0483: // Unpacked path of the war
0484: String destDir = null;
0485: if (fWar.isDirectory()) {
0486: destDir = warURL.getPath();
0487: } else {
0488: destDir = unpackedWarURL.getPath();
0489: }
0490:
0491: // META-INF/context.xml file
0492: File contextXmlFile = new File(destDir + File.separator
0493: + "META-INF" + File.separator + "context.xml");
0494:
0495: // Check if some contexts were configured in server.xml
0496: List jonasContexts = getConfiguredMatchingJonasContexts(
0497: contextRoot, fWar, destDir);
0498:
0499: Host deployer = null;
0500: // The context was not found in server.xml, a new context will be created.
0501: if (jonasContexts.isEmpty()) {
0502: // Find host on which deploy the context
0503: deployer = findHost(hostName);
0504:
0505: // Create context (false because not in server.xml)
0506: JOnASStandardContext context = new JOnASStandardContext(
0507: false, java2DelegationModel, inEarCase);
0508: context.setDocBase(destDir);
0509: context.setPath(contextRoot);
0510: ContextConfig config = new ContextConfig();
0511:
0512: // add the config
0513: ((Lifecycle) context).addLifecycleListener(config);
0514: jonasContexts.add(context);
0515: }
0516:
0517: // Configure these contexts and start them
0518: Iterator it = jonasContexts.iterator();
0519: while (it.hasNext()) {
0520: JOnASStandardContext jStdCtx = (JOnASStandardContext) it
0521: .next();
0522:
0523: // Set the parent class loader
0524: jStdCtx.setParentClassLoader(webClassLoader);
0525:
0526: // Delegation model
0527: jStdCtx.setDelegate(java2DelegationModel);
0528: if (getLogger().isLoggable(BasicLevel.DEBUG)) {
0529: getLogger().log(
0530: BasicLevel.DEBUG,
0531: "Webapp class loader java 2 delegation model set to "
0532: + java2DelegationModel);
0533: }
0534:
0535: // Add valve for setting unauthenticated user
0536: jStdCtx.addValve(new ResetAuthenticationValve());
0537:
0538: // META-INF/context.xml file support
0539: if (contextXmlFile.exists()) {
0540: jStdCtx.setConfigFile(contextXmlFile.getAbsolutePath());
0541: }
0542:
0543: // JSR 77
0544: jStdCtx.setJ2EEServer(getJonasServerName());
0545: jStdCtx.setServer(J2eeObjectName.J2EEServer(
0546: getDomainName(), getJonasServerName()).toString());
0547: if (getMbeanServer() != null) {
0548: try {
0549: String[] as = (String[]) getMbeanServer()
0550: .getAttribute(
0551: J2eeObjectName.J2EEServer(
0552: getDomainName(),
0553: getJonasServerName()),
0554: "javaVMs");
0555: jStdCtx.setJavaVMs(as);
0556: } catch (Exception e) {
0557: //String err = i18n.getMessage("CatJWebServ.doRegisterWar.startContextError", jStdCtx);
0558: //getLogger().log(BasicLevel.WARN, err + e.getMessage());
0559: getLogger().log(
0560: BasicLevel.WARN,
0561: "Set MBean JVM error : "
0562: + e.getClass().getName() + " "
0563: + e.getMessage());
0564: }
0565: }
0566: if (earAppName != null) {
0567: jStdCtx.setJ2EEApplication(earAppName);
0568: }
0569: jStdCtx.setJonasDeploymentDescriptor(jonasDD);
0570:
0571: // Set the realm
0572: Realm ctxRealm = jStdCtx.getRealm();
0573:
0574: // Take realm of parent
0575: if (ctxRealm == null) {
0576: ctxRealm = deployer.getRealm();
0577: }
0578:
0579: if (ctxRealm != null && ctxRealm instanceof JACC) {
0580: JACC jaccRealm = null;
0581: try {
0582: jaccRealm = (JACC) ((JACC) ctxRealm).clone();
0583: } catch (CloneNotSupportedException cnse) {
0584: String err = "Cannot clone the realm used by the existing context or its parent realm";
0585: getLogger().log(BasicLevel.ERROR,
0586: err + cnse.getMessage());
0587: throw new JWebContainerServiceException(err, cnse);
0588: }
0589: if (getLogger().isLoggable(BasicLevel.DEBUG)) {
0590: getLogger().log(
0591: BasicLevel.DEBUG,
0592: "Setting permission manager to "
0593: + permissionManager);
0594: }
0595: jaccRealm.setPermissionManager(permissionManager);
0596: jaccRealm.setContext(jStdCtx);
0597: // Set the new realm
0598: jStdCtx.setRealm(jaccRealm);
0599: }
0600:
0601: // Set the attributes transfered from the JOnAS War MBean.
0602: // Note that 'java2DelegationModel' and 'inEarCase' attributes
0603: // are passed asarguments to the JOnASStandardContext's constructor
0604: jStdCtx.setWarURL(warURL);
0605: if (inEarCase) {
0606: jStdCtx.setEarURL(earURL);
0607: }
0608:
0609: // ... and start it or add it
0610: if (jStdCtx.isInServerXml()) {
0611: try {
0612: jStdCtx.setLoader(null);
0613: jStdCtx.start();
0614: } catch (LifecycleException lce) {
0615: String err = i18n
0616: .getMessage(
0617: "CatJWebServ.doRegisterWar.startContextError",
0618: jStdCtx);
0619: getLogger().log(BasicLevel.ERROR,
0620: err + lce.getMessage());
0621: throw new JWebContainerServiceException(err, lce);
0622:
0623: }
0624: } else {
0625: // add it
0626: if (deployer == null) {
0627: String err = i18n.getMessage(
0628: "CatJWebServ.doRegisterWar.deployerIsNull",
0629: jStdCtx);
0630: getLogger().log(BasicLevel.ERROR, err);
0631: throw new JWebContainerServiceException(err);
0632: }
0633: deployer.addChild(jStdCtx);
0634: }
0635:
0636: // ...and check if it is now configured
0637: checkStartedContext(jStdCtx, permissionManager);
0638:
0639: // Store WebModule ObjectName in Context
0640: try {
0641: ctx.rebind("WebModule", jStdCtx.createObjectName(
0642: getDomainName(), jStdCtx.getParentName()));
0643: } catch (Exception e) {
0644: // NamingException or Mbean related Exception
0645: // TODO i18n
0646: String err = "Cannot rebind WebModule ObjectName in Context";
0647: getLogger().log(BasicLevel.ERROR, err, e);
0648: throw new JWebContainerServiceException(err, e);
0649: }
0650: }
0651: }
0652:
0653: /**
0654: * Check if there is a previous JOnASStandardContext which match the current context
0655: * If true, deploy our context into the configured context
0656: * @param contextRoot name of the context that we want to find preconfigured contexts
0657: * @param fpackedWar file of the original war file
0658: * @param destDir name of the unpacked directory of the war file
0659: * @return true if a context was found and used
0660: */
0661: protected List getConfiguredMatchingJonasContexts(
0662: String contextRoot, File fpackedWar, String destDir) {
0663: ArrayList jonasContexts = new ArrayList();
0664: // Check contexts of all services to see if there is a configured context.
0665: // that we must use instead of creating a new one.
0666: // If a context is matching, we set its docbase and start it.
0667: Iterator it = getContexts().iterator();
0668: while (it.hasNext()) {
0669: Context ctx = (Context) it.next();
0670: // Continue if it is not a JOnAS context
0671: if (!(ctx instanceof JOnASStandardContext)) {
0672: continue;
0673: }
0674: JOnASStandardContext jStdCtx = (JOnASStandardContext) ctx;
0675: if (jStdCtx != null) {
0676: // Not created in server.xml file
0677: if (!jStdCtx.isInServerXml()) {
0678: continue;
0679: }
0680:
0681: // The context was configured ?
0682: String serverCtxRoot = jStdCtx.getPath();
0683: if (!serverCtxRoot.equals(contextRoot)) {
0684: continue;
0685: }
0686: if (jStdCtx.getPrivileged()) {
0687: // Can deploy a privileged context only if it's a .war file
0688: if (fpackedWar.isDirectory()) {
0689: String err = i18n
0690: .getMessage("CatJWebServ.getConfiguredMatchingJonasContexts.privilegedContextError");
0691: getLogger().log(BasicLevel.ERROR, err);
0692: }
0693: jStdCtx.setDocBase(fpackedWar.getPath());
0694: } else {
0695: jStdCtx.setDocBase(destDir);
0696: }
0697: jonasContexts.add(jStdCtx);
0698: }
0699: }
0700: return jonasContexts;
0701: }
0702:
0703: /**
0704: * Check that the context that was started was right configured
0705: * @param context context to check
0706: * @param permissionManager the permission manager used for JACC
0707: * @throws JWebContainerServiceException if the context was not right configured
0708: */
0709: protected void checkStartedContext(Context context,
0710: PermissionManager permissionManager)
0711: throws JWebContainerServiceException {
0712: // Check if the context was configured
0713: if (!context.getConfigured()) {
0714: String err = i18n.getMessage(
0715: "CatJWebServ.checkStartedContext.configuredFail",
0716: context.getName());
0717: getLogger().log(BasicLevel.ERROR, err);
0718: throw new JWebContainerServiceException(err);
0719: }
0720:
0721: // Check that JACC realm is correctly set
0722: Realm ctxRealm = context.getRealm();
0723: if (ctxRealm != null && ctxRealm instanceof JACC) {
0724: JACC jaccRealm = (JACC) ctxRealm;
0725: PermissionManager ctxPerm = jaccRealm
0726: .getPermissionManager();
0727: if (ctxPerm == null && permissionManager != null) {
0728: jaccRealm.setPermissionManager(permissionManager);
0729: // set context on the realm.
0730: jaccRealm.setContext(context);
0731: }
0732: }
0733: if (getLogger().isLoggable(BasicLevel.DEBUG)) {
0734: getLogger().log(BasicLevel.DEBUG,
0735: "context " + context + " started");
0736: }
0737:
0738: }
0739:
0740: /**
0741: * Gets all the engines of the current Tomcat server
0742: * @return all the engines of the current Tomcat server
0743: * @throws JWebContainerServiceException if engines can not be retrieved
0744: */
0745: protected synchronized List getEngines()
0746: throws JWebContainerServiceException {
0747: List engines = new ArrayList();
0748: Service[] services = server.findServices();
0749:
0750: // Get contexts of each engine of each service
0751: for (int s = 0; s < services.length; s++) {
0752: Container cont = services[s].getContainer();
0753: if (!(cont instanceof Engine)) {
0754: String err = "The container of the service must be an engine (server.xml)";
0755: throw new JWebContainerServiceException(err);
0756: }
0757: engines.add(cont);
0758: }
0759: return engines;
0760: }
0761:
0762: /**
0763: * Gets all the contexts of the current Tomcat server
0764: * @return all the contexts of the current Tomcat server
0765: * @throws JWebContainerServiceException if contexts can not be retrieved
0766: */
0767: protected synchronized List getContexts()
0768: throws JWebContainerServiceException {
0769: List contexts = new ArrayList();
0770:
0771: Iterator itEngines = getEngines().iterator();
0772: while (itEngines.hasNext()) {
0773: Engine engine = (Engine) itEngines.next();
0774: Container[] hosts = engine.findChildren();
0775:
0776: for (int j = 0; j < hosts.length; j++) {
0777: Container[] containers = hosts[j].findChildren();
0778: for (int k = 0; k < containers.length; k++) {
0779: Container container = containers[k];
0780: if (container instanceof Context) {
0781: contexts.add(container);
0782: }
0783: }
0784: }
0785: }
0786: return contexts;
0787: }
0788:
0789: /**
0790: * Undeploy a specific WAR file specified in the context.
0791: * @param ctx the context which contains the configuration in order
0792: * to undeploy a WAR.
0793: * @throws JWebContainerServiceException if the unregistration failed.
0794: */
0795: protected void doUnRegisterWar(javax.naming.Context ctx)
0796: throws JWebContainerServiceException {
0797:
0798: // Get the 2 parameters :
0799: // - contextRoot is the context root to be removed (required param).
0800: // - hostName is the name of the host to remove the war (optional).
0801: String contextRoot = null;
0802: try {
0803: contextRoot = (String) ctx.lookup("contextRoot");
0804: } catch (NamingException e) {
0805: String err = i18n
0806: .getMessage("CatJWebServ.doUnRegisterWar.gettingParamError");
0807: getLogger().log(BasicLevel.ERROR, err + e.getMessage());
0808: throw new JWebContainerServiceException(err, e);
0809: }
0810:
0811: if (contextRoot.equals("/")) {
0812: contextRoot = "";
0813: } else {
0814: contextRoot = "/" + contextRoot;
0815: }
0816:
0817: String hostName = null;
0818: try {
0819: hostName = (String) ctx.lookup("hostName");
0820: } catch (NamingException e) {
0821: if (getLogger().isLoggable(BasicLevel.DEBUG)) {
0822: getLogger().log(BasicLevel.DEBUG,
0823: "No define hostname for this context");
0824: }
0825: }
0826:
0827: // Undeploy all matching context if there is no hostname provided
0828: if (hostName == null) {
0829: boolean found = false;
0830: Iterator it = getContexts().iterator();
0831: while (it.hasNext()) {
0832: Context context = (Context) it.next();
0833: String serverCtxRoot = context.getPath();
0834: if (serverCtxRoot.equals(contextRoot)) {
0835: removeContext(context);
0836: found = true;
0837: break;
0838: }
0839: }
0840: if (!found) {
0841: String err = i18n.getMessage(
0842: "CatJWebServ.doUnRegisterWar.undeployError",
0843: contextRoot);
0844: getLogger().log(BasicLevel.ERROR, err);
0845: throw new JWebContainerServiceException(err);
0846: }
0847: } else {
0848: // Remove the specified Context from the set of defined Contexts
0849: // for its associated Host.
0850: Host host = findHost(hostName);
0851: org.apache.catalina.Context context = host.map(contextRoot);
0852: if (context != null) {
0853: removeContext(context);
0854: } else {
0855: String err = i18n.getMessage(
0856: "CatJWebServ.doUnRegisterWar.undeployError",
0857: contextRoot);
0858: getLogger().log(BasicLevel.ERROR, err);
0859: throw new JWebContainerServiceException(err);
0860: }
0861: }
0862: }
0863:
0864: /**
0865: * Remove the specified Context from the set of defined Contexts for its
0866: * associated Host. If this is the last Context for this Host, the Host
0867: * will also be removed.
0868: *
0869: * @param context The Context to be removed
0870: * @throws JWebContainerServiceException if the context can not be removed
0871: */
0872: public synchronized void removeContext(Context context)
0873: throws JWebContainerServiceException {
0874:
0875: // Is this Context actually among those that are deployed ?
0876: boolean found = false;
0877: Iterator it = getContexts().iterator();
0878: while (it.hasNext() && !found) {
0879: if (context == (Context) it.next()) {
0880: found = true;
0881: }
0882: }
0883:
0884: if (!found) {
0885: return;
0886: }
0887: // Remove this Context from the associated Host
0888: // Or stop it if it is a JOnAS standard context (to keep the configuration)
0889: if (context instanceof JOnASStandardContext) {
0890: JOnASStandardContext jctx = (JOnASStandardContext) context;
0891: if (jctx.isInServerXml()) {
0892: try {
0893: ((JOnASStandardContext) context).stop();
0894: } catch (LifecycleException le) {
0895: throw new JWebContainerServiceException(
0896: "Cannot stop context (" + le.getMessage()
0897: + ")");
0898: }
0899: } else {
0900: // must not persist
0901: context.getParent().removeChild(context);
0902: // Bug Tomcat 5 doesn't remove MBean WebModule
0903: // Delete the next line when will be fixed
0904: // Bug Tomcat 5 : begin
0905: if (getMbeanServer() != null) {
0906: try {
0907: // unregister WebModule MBean
0908: getMbeanServer().unregisterMBean(
0909: jctx.getJmxName());
0910: } catch (Exception e) {
0911: getLogger().log(
0912: BasicLevel.ERROR,
0913: "Cannot remove the MBean for the WebModule "
0914: + jctx.getObjectName() + " : "
0915: + e.getMessage());
0916: }
0917: }
0918: }
0919: } else {
0920: context.getParent().removeChild(context);
0921: // Bug Tomcat 5 doesn't remove MBean WebModule
0922: // Delete the next line when will be fixed
0923: // Bug Tomcat 5 : begin
0924: if (context instanceof StandardContext) {
0925: StandardContext ctx = (StandardContext) context;
0926: if (getMbeanServer() != null) {
0927: try {
0928: // unregister WebModule MBean
0929: getMbeanServer().unregisterMBean(
0930: ctx.getJmxName());
0931: } catch (Exception e) {
0932: getLogger().log(
0933: BasicLevel.ERROR,
0934: "Cannot remove the MBean for the WebModule "
0935: + ctx.getObjectName() + " : "
0936: + e.getMessage());
0937: }
0938: }
0939: }
0940: }
0941:
0942: }
0943:
0944: /**
0945: * The server is started ?
0946: * @return boolean true if the catalina container is running.
0947: */
0948: public boolean isTomcatStarted() {
0949: return tomcatStarted;
0950: }
0951:
0952: /**
0953: * Set the server instance we are configuring.
0954: *
0955: * @param server The new server
0956: */
0957: public void setServer(Server server) {
0958: this .server = server;
0959: }
0960:
0961: /**
0962: * Return a File object representing the server.xml configuration file.
0963: * @return a File object representing the server.xml configuration file.
0964: * @throws FileNotFoundException if the configuration file is not found.
0965: */
0966: protected File getConfigFile() throws FileNotFoundException {
0967: String fileName = System.getProperty("catalina.base");
0968: fileName = fileName + File.separator + CONFIG_FILE;
0969: File file = new File(fileName);
0970: if (!file.exists()) {
0971: String err = i18n
0972: .getMessage(
0973: "CatJWebServ.getConfigFile.findfileError",
0974: fileName);
0975: throw new FileNotFoundException(err);
0976: }
0977: return (file);
0978: }
0979:
0980: /**
0981: * Find the specified host.
0982: * @param hostName the name of the host to find.
0983: * @return the host found.
0984: * @throws JWebContainerServiceException if the specified host cannot be
0985: * found.
0986: */
0987: public Host findHost(String hostName)
0988: throws JWebContainerServiceException {
0989:
0990: Service[] services = server.findServices();
0991: // Check number of services
0992: if (services.length < 1) {
0993: String err = "At least one service must be define in the server.xml of Tomcat";
0994: throw new JWebContainerServiceException(err);
0995: }
0996:
0997: // Two cases :
0998: // 1/ No host specified
0999: // -> defaulthost of the engine of the first service.
1000: // 2) A host is specified in the jonas-web.xml
1001: // -> find the host and deploy on this host
1002:
1003: if (hostName == null || hostName.equals("")) {
1004: // First case
1005:
1006: //Take first service
1007: Service service = services[0];
1008:
1009: Container cont = service.getContainer();
1010: if (!(cont instanceof Engine)) {
1011: String err = "The container of the service must be an engine";
1012: throw new JWebContainerServiceException(err);
1013: }
1014:
1015: Engine engine = (Engine) cont;
1016: String defaultHost = engine.getDefaultHost();
1017: if (defaultHost == null) {
1018: String err = "Default host must be specified in server.xml or host must be specified in jonas-web.xml";
1019: throw new JWebContainerServiceException(err);
1020: }
1021: Container child = engine.findChild(defaultHost);
1022: // found, return it
1023: if (child instanceof Host) {
1024: return (Host) child;
1025: }
1026: // else error
1027: String err = "Default host " + defaultHost + " not found";
1028: throw new JWebContainerServiceException(err);
1029: }
1030: // Get all hosts.
1031: Vector hosts = new Vector();
1032:
1033: for (int s = 0; s < services.length; s++) {
1034: Container cont = services[s].getContainer();
1035: if (!(cont instanceof Engine)) {
1036: String err = "The container of a service must be an engine";
1037: throw new JWebContainerServiceException(err);
1038: }
1039: Engine engine = (Engine) cont;
1040: Container child = engine.findChild(hostName);
1041: if (child instanceof Host) {
1042: hosts.addElement(child);
1043: }
1044: }
1045:
1046: // error
1047: if (hosts.size() == 0) {
1048: // No host found.
1049: String err = "Host " + hostName
1050: + " not found in all services/Engine of server.xml";
1051: throw new JWebContainerServiceException(err);
1052: }
1053:
1054: // first element
1055: return (Host) hosts.elementAt(0);
1056: }
1057:
1058: /**
1059: * Set the specified resources in the naming context.
1060: * @param ctx the context where the bindings are set.
1061: * @param resource the resource to bind.
1062: * @throws JWebContainerServiceException if the bind failed.
1063: */
1064: private void addResource(javax.naming.Context ctx,
1065: ContextResource resource)
1066: throws JWebContainerServiceException {
1067:
1068: String name = resource.getName();
1069: String type = resource.getType();
1070: String registryName = name;
1071:
1072: // Add only UserDatabase resources
1073: if (!type.equals("org.apache.catalina.UserDatabase")) {
1074: return;
1075: }
1076:
1077: // Create a reference to the resource.
1078: Reference ref = new Reference(
1079: "org.apache.catalina.UserDatabase",
1080: "org.apache.catalina.users.MemoryUserDatabaseFactory",
1081: null);
1082:
1083: // Add extra parameters
1084: Iterator params = resource.listProperties();
1085: while (params.hasNext()) {
1086: String paramName = (String) params.next();
1087: String paramValue = (String) resource
1088: .getProperty(paramName);
1089: StringRefAddr refAddr = new StringRefAddr(paramName,
1090: paramValue);
1091: ref.add(refAddr);
1092: }
1093: try {
1094: javax.naming.Context ictx = getNaming().getInitialContext();
1095:
1096: // Bind into registry
1097: ictx.rebind(registryName, ref);
1098:
1099: // Bind LinkRef
1100: LinkRef lref = new LinkRef(registryName);
1101: ctx.rebind(name, lref);
1102:
1103: } catch (Exception e) {
1104: e.printStackTrace();
1105: String err = "Can't add the resource " + name;
1106: throw new JWebContainerServiceException(err, e);
1107: }
1108: }
1109:
1110: /**
1111: * Create and configure the Digester that will be used for the xml
1112: * parsing of the configuration file.
1113: * @return Digester the digester containing the rules for the xml parsing
1114: * of the server.xml.
1115: */
1116: protected Digester createServerDigester() {
1117:
1118: // Initialize the digester
1119: Digester digester = new Digester();
1120: digester.setValidating(false);
1121: digester.addRuleSet(new JCatalinaRuleSet(parentClassLoader));
1122:
1123: // Use context class loader.
1124: // Could avoid problem for users putting digester in JONAS_ROOT/lib/ext folder
1125: digester.setUseContextClassLoader(true);
1126: return (digester);
1127:
1128: }
1129:
1130: /**
1131: * Update info of the serverName and serverVersion
1132: */
1133: protected void updateServerInfos() {
1134: String infos = org.apache.catalina.util.ServerInfo
1135: .getServerInfo();
1136: StringTokenizer st = new StringTokenizer(infos, "/");
1137: if (st.countTokens() != 2) {
1138: setServerName(infos);
1139: setServerVersion("");
1140: } else {
1141: setServerName(st.nextToken());
1142: setServerVersion(st.nextToken());
1143: }
1144: }
1145:
1146: /**
1147: * Return the Default host name of the web container.
1148: * @return the Default host name of the web container.
1149: * @throws JWebContainerServiceException when default host cannot
1150: * be resolved (multiple services).
1151: */
1152: public String getDefaultHost() throws JWebContainerServiceException {
1153: Engine engine = (Engine) getFirstService().getContainer();
1154: return engine.getDefaultHost();
1155: }
1156:
1157: /**
1158: * Return the Default HTTP port number of the web container. Returns the first
1159: * connector port if more than one are defined.
1160: * @return the Default HTTP port number of the web container.
1161: * @throws JWebContainerServiceException when default HTTP port cannot be
1162: * resolved or none are defined.
1163: */
1164: public String getDefaultHttpPort()
1165: throws JWebContainerServiceException {
1166: return String.valueOf(getFirstConnectorFromScheme("http")
1167: .getPort());
1168: }
1169:
1170: /**
1171: * @param scheme URL scheme (http, ...)
1172: * @return Returns a List of Connectors for the given scheme (http, https, ...)
1173: */
1174: private Connector getFirstConnectorFromScheme(String scheme) {
1175: Service svc = getFirstService();
1176: // take the first service
1177: Connector[] conn = svc.findConnectors();
1178: Vector httpConn = new Vector();
1179: for (int i = 0; i < conn.length; i++) {
1180: if (conn[i].getScheme().equalsIgnoreCase(scheme)) {
1181: httpConn.add(conn[i]);
1182: }
1183: }
1184:
1185: if (httpConn.isEmpty()) {
1186: // No connectors defined
1187: throw new JWebContainerServiceException(
1188: "No Connectors found for scheme '" + scheme
1189: + "' in " + CONFIG_FILE);
1190: }
1191:
1192: Connector c = (Connector) httpConn.get(0);
1193:
1194: // Check if there are more than one HTTP connectors specified, if so, warn the administrator.
1195: if (httpConn.size() > 1) {
1196: if (getLogger().isLoggable(BasicLevel.WARN)) {
1197: getLogger().log(
1198: BasicLevel.WARN,
1199: "Found multiple Connectors for scheme '"
1200: + scheme + "' in " + CONFIG_FILE
1201: + ", using first by default! (port:"
1202: + c.getPort() + ")");
1203: }
1204: }
1205:
1206: return c;
1207: }
1208:
1209: /**
1210: * @return Returns the first found Service
1211: */
1212: private Service getFirstService() {
1213: Service[] svc = server.findServices();
1214: // throw exception if no service is defined
1215: if ((svc == null) || (svc.length == 0)) {
1216: // No Services specified.
1217: throw new JWebContainerServiceException(
1218: "No Services found in " + CONFIG_FILE);
1219: }
1220: // Check if there are more than one services specified and if so, warn the administrator.
1221: if (svc.length > 1) {
1222: if (getLogger().isLoggable(BasicLevel.WARN)) {
1223: getLogger().log(
1224: BasicLevel.WARN,
1225: "Found multiple Services in " + CONFIG_FILE
1226: + ", using first by default!");
1227: }
1228: }
1229: return svc[0];
1230: }
1231:
1232: /**
1233: * Return the Default HTTPS port number of the web container (can
1234: * be null if multiple HTTPS connector has been set).
1235: * @return the Default HTTPS port number of the web container.
1236: * @throws JWebContainerServiceException when default HTTPS port cannot be
1237: * resolved (0 occurences).
1238: */
1239: public String getDefaultHttpsPort()
1240: throws JWebContainerServiceException {
1241: return String.valueOf(getFirstConnectorFromScheme("https")
1242: .getPort());
1243: }
1244:
1245: /**
1246: * Register a WAR by delegating the operation to the registerWar()
1247: * method. This is used for JMX management.
1248: * @param fileName the name of the war to deploy.
1249: * @throws RemoteException if rmi call failed.
1250: * @throws JWebContainerServiceException if the registration failed.
1251: */
1252: public void registerWarMBean(String fileName)
1253: throws RemoteException, JWebContainerServiceException {
1254: ClassLoader old = null;
1255: try {
1256: old = Thread.currentThread().getContextClassLoader();
1257: Thread.currentThread()
1258: .setContextClassLoader(catalinaLoader);
1259: super .registerWarMBean(fileName);
1260: } catch (Exception e) {
1261: throw new ServiceException(
1262: "Exception during registering war", e);
1263: } finally {
1264: if (old != null) {
1265: Thread.currentThread().setContextClassLoader(old);
1266: }
1267: }
1268: }
1269:
1270: /**
1271: * Unregister a WAR by delegating the operation to the unRegisterWar()
1272: * method. This is used for JMX management.
1273: * @param fileName the name of the war to undeploy.
1274: * @throws RemoteException if rmi call failed.
1275: * @throws JWebContainerServiceException if the unregistration failed.
1276: */
1277: public void unRegisterWarMBean(String fileName)
1278: throws RemoteException, JWebContainerServiceException {
1279: ClassLoader old = null;
1280: try {
1281: old = Thread.currentThread().getContextClassLoader();
1282: Thread.currentThread()
1283: .setContextClassLoader(catalinaLoader);
1284: super .unRegisterWarMBean(fileName);
1285: } catch (Exception e) {
1286: throw new ServiceException(
1287: "Exception during unregistering war", e);
1288: } finally {
1289: if (old != null) {
1290: Thread.currentThread().setContextClassLoader(old);
1291: }
1292: }
1293: }
1294: }
|