0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.catalina.core;
0019:
0020: import java.lang.reflect.Method;
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.PrintStream;
0024: import java.util.ArrayList;
0025: import java.util.Enumeration;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Properties;
0029: import java.util.Stack;
0030: import java.security.AccessController;
0031: import java.security.PrivilegedActionException;
0032: import java.security.PrivilegedExceptionAction;
0033: import javax.servlet.Servlet;
0034: import javax.servlet.ServletConfig;
0035: import javax.servlet.ServletContext;
0036: import javax.servlet.ServletException;
0037: import javax.servlet.ServletRequest;
0038: import javax.servlet.ServletResponse;
0039: import javax.servlet.SingleThreadModel;
0040: import javax.servlet.UnavailableException;
0041: import javax.management.ListenerNotFoundException;
0042: import javax.management.MBeanNotificationInfo;
0043: import javax.management.Notification;
0044: import javax.management.NotificationBroadcasterSupport;
0045: import javax.management.NotificationEmitter;
0046: import javax.management.NotificationFilter;
0047: import javax.management.NotificationListener;
0048: import javax.management.ObjectName;
0049:
0050: import org.apache.PeriodicEventListener;
0051: import org.apache.catalina.Container;
0052: import org.apache.catalina.ContainerServlet;
0053: import org.apache.catalina.Context;
0054: import org.apache.catalina.Globals;
0055: import org.apache.catalina.InstanceEvent;
0056: import org.apache.catalina.InstanceListener;
0057: import org.apache.catalina.LifecycleException;
0058: import org.apache.catalina.Loader;
0059: import org.apache.catalina.Wrapper;
0060: import org.apache.catalina.security.SecurityUtil;
0061: import org.apache.catalina.util.Enumerator;
0062: import org.apache.catalina.util.InstanceSupport;
0063: import org.apache.tomcat.util.log.SystemLogHandler;
0064: import org.apache.tomcat.util.modeler.Registry;
0065:
0066: /**
0067: * Standard implementation of the <b>Wrapper</b> interface that represents
0068: * an individual servlet definition. No child Containers are allowed, and
0069: * the parent Container must be a Context.
0070: *
0071: * @author Craig R. McClanahan
0072: * @author Remy Maucherat
0073: * @version $Revision: 505593 $ $Date: 2007-02-10 01:54:56 +0100 (sam., 10 févr. 2007) $
0074: */
0075: public class StandardWrapper extends ContainerBase implements
0076: ServletConfig, Wrapper, NotificationEmitter {
0077:
0078: protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
0079: .getLog(StandardWrapper.class);
0080:
0081: protected static final String[] DEFAULT_SERVLET_METHODS = new String[] {
0082: "GET", "HEAD", "POST" };
0083:
0084: // ----------------------------------------------------------- Constructors
0085:
0086: /**
0087: * Create a new StandardWrapper component with the default basic Valve.
0088: */
0089: public StandardWrapper() {
0090:
0091: super ();
0092: swValve = new StandardWrapperValve();
0093: pipeline.setBasic(swValve);
0094: broadcaster = new NotificationBroadcasterSupport();
0095:
0096: if (restrictedServlets == null) {
0097: restrictedServlets = new Properties();
0098: try {
0099: InputStream is = this
0100: .getClass()
0101: .getClassLoader()
0102: .getResourceAsStream(
0103: "org/apache/catalina/core/RestrictedServlets.properties");
0104: if (is != null) {
0105: restrictedServlets.load(is);
0106: } else {
0107: log
0108: .error(sm
0109: .getString("standardWrapper.restrictedServletsResource"));
0110: }
0111: } catch (IOException e) {
0112: log
0113: .error(
0114: sm
0115: .getString("standardWrapper.restrictedServletsResource"),
0116: e);
0117: }
0118: }
0119:
0120: }
0121:
0122: // ----------------------------------------------------- Instance Variables
0123:
0124: /**
0125: * The date and time at which this servlet will become available (in
0126: * milliseconds since the epoch), or zero if the servlet is available.
0127: * If this value equals Long.MAX_VALUE, the unavailability of this
0128: * servlet is considered permanent.
0129: */
0130: protected long available = 0L;
0131:
0132: /**
0133: * The broadcaster that sends j2ee notifications.
0134: */
0135: protected NotificationBroadcasterSupport broadcaster = null;
0136:
0137: /**
0138: * The count of allocations that are currently active (even if they
0139: * are for the same instance, as will be true on a non-STM servlet).
0140: */
0141: protected int countAllocated = 0;
0142:
0143: /**
0144: * The facade associated with this wrapper.
0145: */
0146: protected StandardWrapperFacade facade = new StandardWrapperFacade(
0147: this );
0148:
0149: /**
0150: * The descriptive information string for this implementation.
0151: */
0152: protected static final String info = "org.apache.catalina.core.StandardWrapper/1.0";
0153:
0154: /**
0155: * The (single) initialized instance of this servlet.
0156: */
0157: protected Servlet instance = null;
0158:
0159: /**
0160: * The support object for our instance listeners.
0161: */
0162: protected InstanceSupport instanceSupport = new InstanceSupport(
0163: this );
0164:
0165: /**
0166: * The context-relative URI of the JSP file for this servlet.
0167: */
0168: protected String jspFile = null;
0169:
0170: /**
0171: * The load-on-startup order value (negative value means load on
0172: * first call) for this servlet.
0173: */
0174: protected int loadOnStartup = -1;
0175:
0176: /**
0177: * Mappings associated with the wrapper.
0178: */
0179: protected ArrayList mappings = new ArrayList();
0180:
0181: /**
0182: * The initialization parameters for this servlet, keyed by
0183: * parameter name.
0184: */
0185: protected HashMap parameters = new HashMap();
0186:
0187: /**
0188: * The security role references for this servlet, keyed by role name
0189: * used in the servlet. The corresponding value is the role name of
0190: * the web application itself.
0191: */
0192: protected HashMap references = new HashMap();
0193:
0194: /**
0195: * The run-as identity for this servlet.
0196: */
0197: protected String runAs = null;
0198:
0199: /**
0200: * The notification sequence number.
0201: */
0202: protected long sequenceNumber = 0;
0203:
0204: /**
0205: * The fully qualified servlet class name for this servlet.
0206: */
0207: protected String servletClass = null;
0208:
0209: /**
0210: * Does this servlet implement the SingleThreadModel interface?
0211: */
0212: protected boolean singleThreadModel = false;
0213:
0214: /**
0215: * Are we unloading our servlet instance at the moment?
0216: */
0217: protected boolean unloading = false;
0218:
0219: /**
0220: * Maximum number of STM instances.
0221: */
0222: protected int maxInstances = 20;
0223:
0224: /**
0225: * Number of instances currently loaded for a STM servlet.
0226: */
0227: protected int nInstances = 0;
0228:
0229: /**
0230: * Stack containing the STM instances.
0231: */
0232: protected Stack instancePool = null;
0233:
0234: /**
0235: * Wait time for servlet unload in ms.
0236: */
0237: protected long unloadDelay = 2000;
0238:
0239: /**
0240: * True if this StandardWrapper is for the JspServlet
0241: */
0242: protected boolean isJspServlet;
0243:
0244: /**
0245: * The ObjectName of the JSP monitoring mbean
0246: */
0247: protected ObjectName jspMonitorON;
0248:
0249: /**
0250: * Should we swallow System.out
0251: */
0252: protected boolean swallowOutput = false;
0253:
0254: // To support jmx attributes
0255: protected StandardWrapperValve swValve;
0256: protected long loadTime = 0;
0257: protected int classLoadTime = 0;
0258:
0259: /**
0260: * Static class array used when the SecurityManager is turned on and
0261: * <code>Servlet.init</code> is invoked.
0262: */
0263: protected static Class[] classType = new Class[] { ServletConfig.class };
0264:
0265: /**
0266: * Static class array used when the SecurityManager is turned on and
0267: * <code>Servlet.service</code> is invoked.
0268: */
0269: protected static Class[] classTypeUsedInService = new Class[] {
0270: ServletRequest.class, ServletResponse.class };
0271:
0272: /**
0273: * Restricted servlets (which can only be loaded by a privileged webapp).
0274: */
0275: protected static Properties restrictedServlets = null;
0276:
0277: // ------------------------------------------------------------- Properties
0278:
0279: /**
0280: * Return the available date/time for this servlet, in milliseconds since
0281: * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
0282: * that unavailability is permanent and any request for this servlet will return
0283: * an SC_NOT_FOUND error. If this date/time is in the future, any request for
0284: * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero,
0285: * the servlet is currently available.
0286: */
0287: public long getAvailable() {
0288:
0289: return (this .available);
0290:
0291: }
0292:
0293: /**
0294: * Set the available date/time for this servlet, in milliseconds since the
0295: * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
0296: * that unavailability is permanent and any request for this servlet will return
0297: * an SC_NOT_FOUND error. If this date/time is in the future, any request for
0298: * this servlet will return an SC_SERVICE_UNAVAILABLE error.
0299: *
0300: * @param available The new available date/time
0301: */
0302: public void setAvailable(long available) {
0303:
0304: long oldAvailable = this .available;
0305: if (available > System.currentTimeMillis())
0306: this .available = available;
0307: else
0308: this .available = 0L;
0309: support.firePropertyChange("available", new Long(oldAvailable),
0310: new Long(this .available));
0311:
0312: }
0313:
0314: /**
0315: * Return the number of active allocations of this servlet, even if they
0316: * are all for the same instance (as will be true for servlets that do
0317: * not implement <code>SingleThreadModel</code>.
0318: */
0319: public int getCountAllocated() {
0320:
0321: return (this .countAllocated);
0322:
0323: }
0324:
0325: public String getEngineName() {
0326: return ((StandardContext) getParent()).getEngineName();
0327: }
0328:
0329: /**
0330: * Return descriptive information about this Container implementation and
0331: * the corresponding version number, in the format
0332: * <code><description>/<version></code>.
0333: */
0334: public String getInfo() {
0335:
0336: return (info);
0337:
0338: }
0339:
0340: /**
0341: * Return the InstanceSupport object for this Wrapper instance.
0342: */
0343: public InstanceSupport getInstanceSupport() {
0344:
0345: return (this .instanceSupport);
0346:
0347: }
0348:
0349: /**
0350: * Return the context-relative URI of the JSP file for this servlet.
0351: */
0352: public String getJspFile() {
0353:
0354: return (this .jspFile);
0355:
0356: }
0357:
0358: /**
0359: * Set the context-relative URI of the JSP file for this servlet.
0360: *
0361: * @param jspFile JSP file URI
0362: */
0363: public void setJspFile(String jspFile) {
0364:
0365: String oldJspFile = this .jspFile;
0366: this .jspFile = jspFile;
0367: support.firePropertyChange("jspFile", oldJspFile, this .jspFile);
0368:
0369: // Each jsp-file needs to be represented by its own JspServlet and
0370: // corresponding JspMonitoring mbean, because it may be initialized
0371: // with its own init params
0372: isJspServlet = true;
0373:
0374: }
0375:
0376: /**
0377: * Return the load-on-startup order value (negative value means
0378: * load on first call).
0379: */
0380: public int getLoadOnStartup() {
0381:
0382: if (isJspServlet && loadOnStartup < 0) {
0383: /*
0384: * JspServlet must always be preloaded, because its instance is
0385: * used during registerJMX (when registering the JSP
0386: * monitoring mbean)
0387: */
0388: return Integer.MAX_VALUE;
0389: } else {
0390: return (this .loadOnStartup);
0391: }
0392: }
0393:
0394: /**
0395: * Set the load-on-startup order value (negative value means
0396: * load on first call).
0397: *
0398: * @param value New load-on-startup value
0399: */
0400: public void setLoadOnStartup(int value) {
0401:
0402: int oldLoadOnStartup = this .loadOnStartup;
0403: this .loadOnStartup = value;
0404: support.firePropertyChange("loadOnStartup", new Integer(
0405: oldLoadOnStartup), new Integer(this .loadOnStartup));
0406:
0407: }
0408:
0409: /**
0410: * Set the load-on-startup order value from a (possibly null) string.
0411: * Per the specification, any missing or non-numeric value is converted
0412: * to a zero, so that this servlet will still be loaded at startup
0413: * time, but in an arbitrary order.
0414: *
0415: * @param value New load-on-startup value
0416: */
0417: public void setLoadOnStartupString(String value) {
0418:
0419: try {
0420: setLoadOnStartup(Integer.parseInt(value));
0421: } catch (NumberFormatException e) {
0422: setLoadOnStartup(0);
0423: }
0424: }
0425:
0426: public String getLoadOnStartupString() {
0427: return Integer.toString(getLoadOnStartup());
0428: }
0429:
0430: /**
0431: * Return maximum number of instances that will be allocated when a single
0432: * thread model servlet is used.
0433: */
0434: public int getMaxInstances() {
0435:
0436: return (this .maxInstances);
0437:
0438: }
0439:
0440: /**
0441: * Set the maximum number of instances that will be allocated when a single
0442: * thread model servlet is used.
0443: *
0444: * @param maxInstances New value of maxInstances
0445: */
0446: public void setMaxInstances(int maxInstances) {
0447:
0448: int oldMaxInstances = this .maxInstances;
0449: this .maxInstances = maxInstances;
0450: support.firePropertyChange("maxInstances", oldMaxInstances,
0451: this .maxInstances);
0452:
0453: }
0454:
0455: /**
0456: * Set the parent Container of this Wrapper, but only if it is a Context.
0457: *
0458: * @param container Proposed parent Container
0459: */
0460: public void setParent(Container container) {
0461:
0462: if ((container != null) && !(container instanceof Context))
0463: throw new IllegalArgumentException(sm
0464: .getString("standardWrapper.notContext"));
0465: if (container instanceof StandardContext) {
0466: swallowOutput = ((StandardContext) container)
0467: .getSwallowOutput();
0468: unloadDelay = ((StandardContext) container)
0469: .getUnloadDelay();
0470: }
0471: super .setParent(container);
0472:
0473: }
0474:
0475: /**
0476: * Return the run-as identity for this servlet.
0477: */
0478: public String getRunAs() {
0479:
0480: return (this .runAs);
0481:
0482: }
0483:
0484: /**
0485: * Set the run-as identity for this servlet.
0486: *
0487: * @param runAs New run-as identity value
0488: */
0489: public void setRunAs(String runAs) {
0490:
0491: String oldRunAs = this .runAs;
0492: this .runAs = runAs;
0493: support.firePropertyChange("runAs", oldRunAs, this .runAs);
0494:
0495: }
0496:
0497: /**
0498: * Return the fully qualified servlet class name for this servlet.
0499: */
0500: public String getServletClass() {
0501:
0502: return (this .servletClass);
0503:
0504: }
0505:
0506: /**
0507: * Set the fully qualified servlet class name for this servlet.
0508: *
0509: * @param servletClass Servlet class name
0510: */
0511: public void setServletClass(String servletClass) {
0512:
0513: String oldServletClass = this .servletClass;
0514: this .servletClass = servletClass;
0515: support.firePropertyChange("servletClass", oldServletClass,
0516: this .servletClass);
0517: if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) {
0518: isJspServlet = true;
0519: }
0520: }
0521:
0522: /**
0523: * Set the name of this servlet. This is an alias for the normal
0524: * <code>Container.setName()</code> method, and complements the
0525: * <code>getServletName()</code> method required by the
0526: * <code>ServletConfig</code> interface.
0527: *
0528: * @param name The new name of this servlet
0529: */
0530: public void setServletName(String name) {
0531:
0532: setName(name);
0533:
0534: }
0535:
0536: /**
0537: * Return <code>true</code> if the servlet class represented by this
0538: * component implements the <code>SingleThreadModel</code> interface.
0539: */
0540: public boolean isSingleThreadModel() {
0541:
0542: try {
0543: loadServlet();
0544: } catch (Throwable t) {
0545: ;
0546: }
0547: return (singleThreadModel);
0548:
0549: }
0550:
0551: /**
0552: * Is this servlet currently unavailable?
0553: */
0554: public boolean isUnavailable() {
0555:
0556: if (available == 0L)
0557: return (false);
0558: else if (available <= System.currentTimeMillis()) {
0559: available = 0L;
0560: return (false);
0561: } else
0562: return (true);
0563:
0564: }
0565:
0566: /**
0567: * Gets the names of the methods supported by the underlying servlet.
0568: *
0569: * This is the same set of methods included in the Allow response header
0570: * in response to an OPTIONS request method processed by the underlying
0571: * servlet.
0572: *
0573: * @return Array of names of the methods supported by the underlying
0574: * servlet
0575: */
0576: public String[] getServletMethods() throws ServletException {
0577:
0578: Class servletClazz = loadServlet().getClass();
0579: if (!javax.servlet.http.HttpServlet.class
0580: .isAssignableFrom(servletClazz)) {
0581: return DEFAULT_SERVLET_METHODS;
0582: }
0583:
0584: HashSet allow = new HashSet();
0585: allow.add("TRACE");
0586: allow.add("OPTIONS");
0587:
0588: Method[] methods = getAllDeclaredMethods(servletClazz);
0589: for (int i = 0; methods != null && i < methods.length; i++) {
0590: Method m = methods[i];
0591:
0592: if (m.getName().equals("doGet")) {
0593: allow.add("GET");
0594: allow.add("HEAD");
0595: } else if (m.getName().equals("doPost")) {
0596: allow.add("POST");
0597: } else if (m.getName().equals("doPut")) {
0598: allow.add("PUT");
0599: } else if (m.getName().equals("doDelete")) {
0600: allow.add("DELETE");
0601: }
0602: }
0603:
0604: String[] methodNames = new String[allow.size()];
0605: return (String[]) allow.toArray(methodNames);
0606:
0607: }
0608:
0609: // --------------------------------------------------------- Public Methods
0610:
0611: /**
0612: * Execute a periodic task, such as reloading, etc. This method will be
0613: * invoked inside the classloading context of this container. Unexpected
0614: * throwables will be caught and logged.
0615: */
0616: public void backgroundProcess() {
0617: super .backgroundProcess();
0618:
0619: if (!started)
0620: return;
0621:
0622: if (getServlet() != null
0623: && (getServlet() instanceof PeriodicEventListener)) {
0624: ((PeriodicEventListener) getServlet()).periodicEvent();
0625: }
0626: }
0627:
0628: /**
0629: * Extract the root cause from a servlet exception.
0630: *
0631: * @param e The servlet exception
0632: */
0633: public static Throwable getRootCause(ServletException e) {
0634: Throwable rootCause = e;
0635: Throwable rootCauseCheck = null;
0636: // Extra aggressive rootCause finding
0637: int loops = 0;
0638: do {
0639: loops++;
0640: rootCauseCheck = rootCause.getCause();
0641: if (rootCauseCheck != null)
0642: rootCause = rootCauseCheck;
0643: } while (rootCauseCheck != null && (loops < 20));
0644: return rootCause;
0645: }
0646:
0647: /**
0648: * Refuse to add a child Container, because Wrappers are the lowest level
0649: * of the Container hierarchy.
0650: *
0651: * @param child Child container to be added
0652: */
0653: public void addChild(Container child) {
0654:
0655: throw new IllegalStateException(sm
0656: .getString("standardWrapper.notChild"));
0657:
0658: }
0659:
0660: /**
0661: * Add a new servlet initialization parameter for this servlet.
0662: *
0663: * @param name Name of this initialization parameter to add
0664: * @param value Value of this initialization parameter to add
0665: */
0666: public void addInitParameter(String name, String value) {
0667:
0668: synchronized (parameters) {
0669: parameters.put(name, value);
0670: }
0671: fireContainerEvent("addInitParameter", name);
0672:
0673: }
0674:
0675: /**
0676: * Add a new listener interested in InstanceEvents.
0677: *
0678: * @param listener The new listener
0679: */
0680: public void addInstanceListener(InstanceListener listener) {
0681:
0682: instanceSupport.addInstanceListener(listener);
0683:
0684: }
0685:
0686: /**
0687: * Add a mapping associated with the Wrapper.
0688: *
0689: * @param mapping The new wrapper mapping
0690: */
0691: public void addMapping(String mapping) {
0692:
0693: synchronized (mappings) {
0694: mappings.add(mapping);
0695: }
0696: fireContainerEvent("addMapping", mapping);
0697:
0698: }
0699:
0700: /**
0701: * Add a new security role reference record to the set of records for
0702: * this servlet.
0703: *
0704: * @param name Role name used within this servlet
0705: * @param link Role name used within the web application
0706: */
0707: public void addSecurityReference(String name, String link) {
0708:
0709: synchronized (references) {
0710: references.put(name, link);
0711: }
0712: fireContainerEvent("addSecurityReference", name);
0713:
0714: }
0715:
0716: /**
0717: * Return the associated servlet instance.
0718: */
0719: public Servlet getServlet() {
0720: return instance;
0721: }
0722:
0723: /**
0724: * Allocate an initialized instance of this Servlet that is ready to have
0725: * its <code>service()</code> method called. If the servlet class does
0726: * not implement <code>SingleThreadModel</code>, the (only) initialized
0727: * instance may be returned immediately. If the servlet class implements
0728: * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
0729: * that this instance is not allocated again until it is deallocated by a
0730: * call to <code>deallocate()</code>.
0731: *
0732: * @exception ServletException if the servlet init() method threw
0733: * an exception
0734: * @exception ServletException if a loading error occurs
0735: */
0736: public Servlet allocate() throws ServletException {
0737:
0738: // If we are currently unloading this servlet, throw an exception
0739: if (unloading)
0740: throw new ServletException(sm.getString(
0741: "standardWrapper.unloading", getName()));
0742:
0743: // If not SingleThreadedModel, return the same instance every time
0744: if (!singleThreadModel) {
0745:
0746: // Load and initialize our instance if necessary
0747: if (instance == null) {
0748: synchronized (this ) {
0749: if (instance == null) {
0750: try {
0751: if (log.isDebugEnabled())
0752: log
0753: .debug("Allocating non-STM instance");
0754:
0755: instance = loadServlet();
0756: } catch (ServletException e) {
0757: throw e;
0758: } catch (Throwable e) {
0759: throw new ServletException(
0760: sm
0761: .getString("standardWrapper.allocate"),
0762: e);
0763: }
0764: }
0765: }
0766: }
0767:
0768: if (!singleThreadModel) {
0769: if (log.isTraceEnabled())
0770: log.trace(" Returning non-STM instance");
0771: countAllocated++;
0772: return (instance);
0773: }
0774:
0775: }
0776:
0777: synchronized (instancePool) {
0778:
0779: while (countAllocated >= nInstances) {
0780: // Allocate a new instance if possible, or else wait
0781: if (nInstances < maxInstances) {
0782: try {
0783: instancePool.push(loadServlet());
0784: nInstances++;
0785: } catch (ServletException e) {
0786: throw e;
0787: } catch (Throwable e) {
0788: throw new ServletException(sm
0789: .getString("standardWrapper.allocate"),
0790: e);
0791: }
0792: } else {
0793: try {
0794: instancePool.wait();
0795: } catch (InterruptedException e) {
0796: ;
0797: }
0798: }
0799: }
0800: if (log.isTraceEnabled())
0801: log.trace(" Returning allocated STM instance");
0802: countAllocated++;
0803: return (Servlet) instancePool.pop();
0804:
0805: }
0806:
0807: }
0808:
0809: /**
0810: * Return this previously allocated servlet to the pool of available
0811: * instances. If this servlet class does not implement SingleThreadModel,
0812: * no action is actually required.
0813: *
0814: * @param servlet The servlet to be returned
0815: *
0816: * @exception ServletException if a deallocation error occurs
0817: */
0818: public void deallocate(Servlet servlet) throws ServletException {
0819:
0820: // If not SingleThreadModel, no action is required
0821: if (!singleThreadModel) {
0822: countAllocated--;
0823: return;
0824: }
0825:
0826: // Unlock and free this instance
0827: synchronized (instancePool) {
0828: countAllocated--;
0829: instancePool.push(servlet);
0830: instancePool.notify();
0831: }
0832:
0833: }
0834:
0835: /**
0836: * Return the value for the specified initialization parameter name,
0837: * if any; otherwise return <code>null</code>.
0838: *
0839: * @param name Name of the requested initialization parameter
0840: */
0841: public String findInitParameter(String name) {
0842:
0843: synchronized (parameters) {
0844: return ((String) parameters.get(name));
0845: }
0846:
0847: }
0848:
0849: /**
0850: * Return the names of all defined initialization parameters for this
0851: * servlet.
0852: */
0853: public String[] findInitParameters() {
0854:
0855: synchronized (parameters) {
0856: String results[] = new String[parameters.size()];
0857: return ((String[]) parameters.keySet().toArray(results));
0858: }
0859:
0860: }
0861:
0862: /**
0863: * Return the mappings associated with this wrapper.
0864: */
0865: public String[] findMappings() {
0866:
0867: synchronized (mappings) {
0868: return (String[]) mappings.toArray(new String[mappings
0869: .size()]);
0870: }
0871:
0872: }
0873:
0874: /**
0875: * Return the security role link for the specified security role
0876: * reference name, if any; otherwise return <code>null</code>.
0877: *
0878: * @param name Security role reference used within this servlet
0879: */
0880: public String findSecurityReference(String name) {
0881:
0882: synchronized (references) {
0883: return ((String) references.get(name));
0884: }
0885:
0886: }
0887:
0888: /**
0889: * Return the set of security role reference names associated with
0890: * this servlet, if any; otherwise return a zero-length array.
0891: */
0892: public String[] findSecurityReferences() {
0893:
0894: synchronized (references) {
0895: String results[] = new String[references.size()];
0896: return ((String[]) references.keySet().toArray(results));
0897: }
0898:
0899: }
0900:
0901: /**
0902: * FIXME: Fooling introspection ...
0903: */
0904: public Wrapper findMappingObject() {
0905: return (Wrapper) getMappingObject();
0906: }
0907:
0908: /**
0909: * Load and initialize an instance of this servlet, if there is not already
0910: * at least one initialized instance. This can be used, for example, to
0911: * load servlets that are marked in the deployment descriptor to be loaded
0912: * at server startup time.
0913: * <p>
0914: * <b>IMPLEMENTATION NOTE</b>: Servlets whose classnames begin with
0915: * <code>org.apache.catalina.</code> (so-called "container" servlets)
0916: * are loaded by the same classloader that loaded this class, rather than
0917: * the classloader for the current web application.
0918: * This gives such classes access to Catalina internals, which are
0919: * prevented for classes loaded for web applications.
0920: *
0921: * @exception ServletException if the servlet init() method threw
0922: * an exception
0923: * @exception ServletException if some other loading problem occurs
0924: */
0925: public synchronized void load() throws ServletException {
0926: instance = loadServlet();
0927: }
0928:
0929: /**
0930: * Load and initialize an instance of this servlet, if there is not already
0931: * at least one initialized instance. This can be used, for example, to
0932: * load servlets that are marked in the deployment descriptor to be loaded
0933: * at server startup time.
0934: */
0935: public synchronized Servlet loadServlet() throws ServletException {
0936:
0937: // Nothing to do if we already have an instance or an instance pool
0938: if (!singleThreadModel && (instance != null))
0939: return instance;
0940:
0941: PrintStream out = System.out;
0942: if (swallowOutput) {
0943: SystemLogHandler.startCapture();
0944: }
0945:
0946: Servlet servlet;
0947: try {
0948: long t1 = System.currentTimeMillis();
0949: // If this "servlet" is really a JSP file, get the right class.
0950: // HOLD YOUR NOSE - this is a kludge that avoids having to do special
0951: // case Catalina-specific code in Jasper - it also requires that the
0952: // servlet path be replaced by the <jsp-file> element content in
0953: // order to be completely effective
0954: String actualClass = servletClass;
0955: if ((actualClass == null) && (jspFile != null)) {
0956: Wrapper jspWrapper = (Wrapper) ((Context) getParent())
0957: .findChild(Constants.JSP_SERVLET_NAME);
0958: if (jspWrapper != null) {
0959: actualClass = jspWrapper.getServletClass();
0960: // Merge init parameters
0961: String paramNames[] = jspWrapper
0962: .findInitParameters();
0963: for (int i = 0; i < paramNames.length; i++) {
0964: if (parameters.get(paramNames[i]) == null) {
0965: parameters.put(paramNames[i], jspWrapper
0966: .findInitParameter(paramNames[i]));
0967: }
0968: }
0969: }
0970: }
0971:
0972: // Complain if no servlet class has been specified
0973: if (actualClass == null) {
0974: unavailable(null);
0975: throw new ServletException(sm.getString(
0976: "standardWrapper.notClass", getName()));
0977: }
0978:
0979: // Acquire an instance of the class loader to be used
0980: Loader loader = getLoader();
0981: if (loader == null) {
0982: unavailable(null);
0983: throw new ServletException(sm.getString(
0984: "standardWrapper.missingLoader", getName()));
0985: }
0986:
0987: ClassLoader classLoader = loader.getClassLoader();
0988:
0989: // Special case class loader for a container provided servlet
0990: //
0991: if (isContainerProvidedServlet(actualClass)
0992: && !((Context) getParent()).getPrivileged()) {
0993: // If it is a priviledged context - using its own
0994: // class loader will work, since it's a child of the container
0995: // loader
0996: classLoader = this .getClass().getClassLoader();
0997: }
0998:
0999: // Load the specified servlet class from the appropriate class loader
1000: Class classClass = null;
1001: try {
1002: if (SecurityUtil.isPackageProtectionEnabled()) {
1003: final ClassLoader fclassLoader = classLoader;
1004: final String factualClass = actualClass;
1005: try {
1006: classClass = (Class) AccessController
1007: .doPrivileged(new PrivilegedExceptionAction() {
1008: public Object run()
1009: throws Exception {
1010: if (fclassLoader != null) {
1011: return fclassLoader
1012: .loadClass(factualClass);
1013: } else {
1014: return Class
1015: .forName(factualClass);
1016: }
1017: }
1018: });
1019: } catch (PrivilegedActionException pax) {
1020: Exception ex = pax.getException();
1021: if (ex instanceof ClassNotFoundException) {
1022: throw (ClassNotFoundException) ex;
1023: } else {
1024: getServletContext().log(
1025: "Error loading " + fclassLoader
1026: + " " + factualClass, ex);
1027: }
1028: }
1029: } else {
1030: if (classLoader != null) {
1031: classClass = classLoader.loadClass(actualClass);
1032: } else {
1033: classClass = Class.forName(actualClass);
1034: }
1035: }
1036: } catch (ClassNotFoundException e) {
1037: unavailable(null);
1038: getServletContext().log(
1039: "Error loading " + classLoader + " "
1040: + actualClass, e);
1041: throw new ServletException(sm.getString(
1042: "standardWrapper.missingClass", actualClass), e);
1043: }
1044:
1045: if (classClass == null) {
1046: unavailable(null);
1047: throw new ServletException(sm.getString(
1048: "standardWrapper.missingClass", actualClass));
1049: }
1050:
1051: // Instantiate and initialize an instance of the servlet class itself
1052: try {
1053: servlet = (Servlet) classClass.newInstance();
1054: // Annotation processing
1055: if (!((Context) getParent()).getIgnoreAnnotations()) {
1056: if (getParent() instanceof StandardContext) {
1057: ((StandardContext) getParent())
1058: .getAnnotationProcessor()
1059: .processAnnotations(servlet);
1060: ((StandardContext) getParent())
1061: .getAnnotationProcessor()
1062: .postConstruct(servlet);
1063: }
1064: }
1065: } catch (ClassCastException e) {
1066: unavailable(null);
1067: // Restore the context ClassLoader
1068: throw new ServletException(sm.getString(
1069: "standardWrapper.notServlet", actualClass), e);
1070: } catch (Throwable e) {
1071: unavailable(null);
1072:
1073: // Added extra log statement for Bugzilla 36630:
1074: // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
1075: if (log.isDebugEnabled()) {
1076: log.debug(
1077: sm.getString("standardWrapper.instantiate",
1078: actualClass), e);
1079: }
1080:
1081: // Restore the context ClassLoader
1082: throw new ServletException(sm.getString(
1083: "standardWrapper.instantiate", actualClass), e);
1084: }
1085:
1086: // Check if loading the servlet in this web application should be
1087: // allowed
1088: if (!isServletAllowed(servlet)) {
1089: throw new SecurityException(sm.getString(
1090: "standardWrapper.privilegedServlet",
1091: actualClass));
1092: }
1093:
1094: // Special handling for ContainerServlet instances
1095: if ((servlet instanceof ContainerServlet)
1096: && (isContainerProvidedServlet(actualClass) || ((Context) getParent())
1097: .getPrivileged())) {
1098: ((ContainerServlet) servlet).setWrapper(this );
1099: }
1100:
1101: classLoadTime = (int) (System.currentTimeMillis() - t1);
1102: // Call the initialization method of this servlet
1103: try {
1104: instanceSupport.fireInstanceEvent(
1105: InstanceEvent.BEFORE_INIT_EVENT, servlet);
1106:
1107: if (Globals.IS_SECURITY_ENABLED) {
1108:
1109: Object[] args = new Object[] { ((ServletConfig) facade) };
1110: SecurityUtil.doAsPrivilege("init", servlet,
1111: classType, args);
1112: args = null;
1113: } else {
1114: servlet.init(facade);
1115: }
1116:
1117: // Invoke jspInit on JSP pages
1118: if ((loadOnStartup >= 0) && (jspFile != null)) {
1119: // Invoking jspInit
1120: DummyRequest req = new DummyRequest();
1121: req.setServletPath(jspFile);
1122: req.setQueryString("jsp_precompile=true");
1123: DummyResponse res = new DummyResponse();
1124:
1125: if (Globals.IS_SECURITY_ENABLED) {
1126: Object[] args = new Object[] { req, res };
1127: SecurityUtil.doAsPrivilege("service", servlet,
1128: classTypeUsedInService, args);
1129: args = null;
1130: } else {
1131: servlet.service(req, res);
1132: }
1133: }
1134: instanceSupport.fireInstanceEvent(
1135: InstanceEvent.AFTER_INIT_EVENT, servlet);
1136: } catch (UnavailableException f) {
1137: instanceSupport.fireInstanceEvent(
1138: InstanceEvent.AFTER_INIT_EVENT, servlet, f);
1139: unavailable(f);
1140: throw f;
1141: } catch (ServletException f) {
1142: instanceSupport.fireInstanceEvent(
1143: InstanceEvent.AFTER_INIT_EVENT, servlet, f);
1144: // If the servlet wanted to be unavailable it would have
1145: // said so, so do not call unavailable(null).
1146: throw f;
1147: } catch (Throwable f) {
1148: getServletContext().log("StandardWrapper.Throwable", f);
1149: instanceSupport.fireInstanceEvent(
1150: InstanceEvent.AFTER_INIT_EVENT, servlet, f);
1151: // If the servlet wanted to be unavailable it would have
1152: // said so, so do not call unavailable(null).
1153: throw new ServletException(sm.getString(
1154: "standardWrapper.initException", getName()), f);
1155: }
1156:
1157: // Register our newly initialized instance
1158: singleThreadModel = servlet instanceof SingleThreadModel;
1159: if (singleThreadModel) {
1160: if (instancePool == null)
1161: instancePool = new Stack();
1162: }
1163: fireContainerEvent("load", this );
1164:
1165: loadTime = System.currentTimeMillis() - t1;
1166: } finally {
1167: if (swallowOutput) {
1168: String log = SystemLogHandler.stopCapture();
1169: if (log != null && log.length() > 0) {
1170: if (getServletContext() != null) {
1171: getServletContext().log(log);
1172: } else {
1173: out.println(log);
1174: }
1175: }
1176: }
1177: }
1178: return servlet;
1179:
1180: }
1181:
1182: /**
1183: * Remove the specified initialization parameter from this servlet.
1184: *
1185: * @param name Name of the initialization parameter to remove
1186: */
1187: public void removeInitParameter(String name) {
1188:
1189: synchronized (parameters) {
1190: parameters.remove(name);
1191: }
1192: fireContainerEvent("removeInitParameter", name);
1193:
1194: }
1195:
1196: /**
1197: * Remove a listener no longer interested in InstanceEvents.
1198: *
1199: * @param listener The listener to remove
1200: */
1201: public void removeInstanceListener(InstanceListener listener) {
1202:
1203: instanceSupport.removeInstanceListener(listener);
1204:
1205: }
1206:
1207: /**
1208: * Remove a mapping associated with the wrapper.
1209: *
1210: * @param mapping The pattern to remove
1211: */
1212: public void removeMapping(String mapping) {
1213:
1214: synchronized (mappings) {
1215: mappings.remove(mapping);
1216: }
1217: fireContainerEvent("removeMapping", mapping);
1218:
1219: }
1220:
1221: /**
1222: * Remove any security role reference for the specified role name.
1223: *
1224: * @param name Security role used within this servlet to be removed
1225: */
1226: public void removeSecurityReference(String name) {
1227:
1228: synchronized (references) {
1229: references.remove(name);
1230: }
1231: fireContainerEvent("removeSecurityReference", name);
1232:
1233: }
1234:
1235: /**
1236: * Return a String representation of this component.
1237: */
1238: public String toString() {
1239:
1240: StringBuffer sb = new StringBuffer();
1241: if (getParent() != null) {
1242: sb.append(getParent().toString());
1243: sb.append(".");
1244: }
1245: sb.append("StandardWrapper[");
1246: sb.append(getName());
1247: sb.append("]");
1248: return (sb.toString());
1249:
1250: }
1251:
1252: /**
1253: * Process an UnavailableException, marking this servlet as unavailable
1254: * for the specified amount of time.
1255: *
1256: * @param unavailable The exception that occurred, or <code>null</code>
1257: * to mark this servlet as permanently unavailable
1258: */
1259: public void unavailable(UnavailableException unavailable) {
1260: getServletContext().log(
1261: sm.getString("standardWrapper.unavailable", getName()));
1262: if (unavailable == null)
1263: setAvailable(Long.MAX_VALUE);
1264: else if (unavailable.isPermanent())
1265: setAvailable(Long.MAX_VALUE);
1266: else {
1267: int unavailableSeconds = unavailable
1268: .getUnavailableSeconds();
1269: if (unavailableSeconds <= 0)
1270: unavailableSeconds = 60; // Arbitrary default
1271: setAvailable(System.currentTimeMillis()
1272: + (unavailableSeconds * 1000L));
1273: }
1274:
1275: }
1276:
1277: /**
1278: * Unload all initialized instances of this servlet, after calling the
1279: * <code>destroy()</code> method for each instance. This can be used,
1280: * for example, prior to shutting down the entire servlet engine, or
1281: * prior to reloading all of the classes from the Loader associated with
1282: * our Loader's repository.
1283: *
1284: * @exception ServletException if an exception is thrown by the
1285: * destroy() method
1286: */
1287: public synchronized void unload() throws ServletException {
1288:
1289: // Nothing to do if we have never loaded the instance
1290: if (!singleThreadModel && (instance == null))
1291: return;
1292: unloading = true;
1293:
1294: // Loaf a while if the current instance is allocated
1295: // (possibly more than once if non-STM)
1296: if (countAllocated > 0) {
1297: int nRetries = 0;
1298: long delay = unloadDelay / 20;
1299: while ((nRetries < 21) && (countAllocated > 0)) {
1300: if ((nRetries % 10) == 0) {
1301: log.info(sm.getString("standardWrapper.waiting",
1302: new Integer(countAllocated)));
1303: }
1304: try {
1305: Thread.sleep(delay);
1306: } catch (InterruptedException e) {
1307: ;
1308: }
1309: nRetries++;
1310: }
1311: }
1312:
1313: PrintStream out = System.out;
1314: if (swallowOutput) {
1315: SystemLogHandler.startCapture();
1316: }
1317:
1318: // Call the servlet destroy() method
1319: try {
1320: instanceSupport.fireInstanceEvent(
1321: InstanceEvent.BEFORE_DESTROY_EVENT, instance);
1322:
1323: if (Globals.IS_SECURITY_ENABLED) {
1324: SecurityUtil.doAsPrivilege("destroy", instance);
1325: SecurityUtil.remove(instance);
1326: } else {
1327: instance.destroy();
1328: }
1329:
1330: instanceSupport.fireInstanceEvent(
1331: InstanceEvent.AFTER_DESTROY_EVENT, instance);
1332:
1333: // Annotation processing
1334: if (!((Context) getParent()).getIgnoreAnnotations()) {
1335: ((StandardContext) getParent())
1336: .getAnnotationProcessor().preDestroy(instance);
1337: }
1338:
1339: } catch (Throwable t) {
1340: instanceSupport.fireInstanceEvent(
1341: InstanceEvent.AFTER_DESTROY_EVENT, instance, t);
1342: instance = null;
1343: instancePool = null;
1344: nInstances = 0;
1345: fireContainerEvent("unload", this );
1346: unloading = false;
1347: throw new ServletException(sm.getString(
1348: "standardWrapper.destroyException", getName()), t);
1349: } finally {
1350: // Write captured output
1351: if (swallowOutput) {
1352: String log = SystemLogHandler.stopCapture();
1353: if (log != null && log.length() > 0) {
1354: if (getServletContext() != null) {
1355: getServletContext().log(log);
1356: } else {
1357: out.println(log);
1358: }
1359: }
1360: }
1361: }
1362:
1363: // Deregister the destroyed instance
1364: instance = null;
1365:
1366: if (singleThreadModel && (instancePool != null)) {
1367: try {
1368: while (!instancePool.isEmpty()) {
1369: Servlet s = (Servlet) instancePool.pop();
1370: if (Globals.IS_SECURITY_ENABLED) {
1371: SecurityUtil.doAsPrivilege("destroy", s);
1372: SecurityUtil.remove(instance);
1373: } else {
1374: s.destroy();
1375: }
1376: // Annotation processing
1377: if (!((Context) getParent()).getIgnoreAnnotations()) {
1378: ((StandardContext) getParent())
1379: .getAnnotationProcessor().preDestroy(s);
1380: }
1381: }
1382: } catch (Throwable t) {
1383: instancePool = null;
1384: nInstances = 0;
1385: unloading = false;
1386: fireContainerEvent("unload", this );
1387: throw new ServletException(sm.getString(
1388: "standardWrapper.destroyException", getName()),
1389: t);
1390: }
1391: instancePool = null;
1392: nInstances = 0;
1393: }
1394:
1395: singleThreadModel = false;
1396:
1397: unloading = false;
1398: fireContainerEvent("unload", this );
1399:
1400: }
1401:
1402: // -------------------------------------------------- ServletConfig Methods
1403:
1404: /**
1405: * Return the initialization parameter value for the specified name,
1406: * if any; otherwise return <code>null</code>.
1407: *
1408: * @param name Name of the initialization parameter to retrieve
1409: */
1410: public String getInitParameter(String name) {
1411:
1412: return (findInitParameter(name));
1413:
1414: }
1415:
1416: /**
1417: * Return the set of initialization parameter names defined for this
1418: * servlet. If none are defined, an empty Enumeration is returned.
1419: */
1420: public Enumeration getInitParameterNames() {
1421:
1422: synchronized (parameters) {
1423: return (new Enumerator(parameters.keySet()));
1424: }
1425:
1426: }
1427:
1428: /**
1429: * Return the servlet context with which this servlet is associated.
1430: */
1431: public ServletContext getServletContext() {
1432:
1433: if (parent == null)
1434: return (null);
1435: else if (!(parent instanceof Context))
1436: return (null);
1437: else
1438: return (((Context) parent).getServletContext());
1439:
1440: }
1441:
1442: /**
1443: * Return the name of this servlet.
1444: */
1445: public String getServletName() {
1446:
1447: return (getName());
1448:
1449: }
1450:
1451: public long getProcessingTime() {
1452: return swValve.getProcessingTime();
1453: }
1454:
1455: public void setProcessingTime(long processingTime) {
1456: swValve.setProcessingTime(processingTime);
1457: }
1458:
1459: public long getMaxTime() {
1460: return swValve.getMaxTime();
1461: }
1462:
1463: public void setMaxTime(long maxTime) {
1464: swValve.setMaxTime(maxTime);
1465: }
1466:
1467: public long getMinTime() {
1468: return swValve.getMinTime();
1469: }
1470:
1471: public void setMinTime(long minTime) {
1472: swValve.setMinTime(minTime);
1473: }
1474:
1475: public int getRequestCount() {
1476: return swValve.getRequestCount();
1477: }
1478:
1479: public void setRequestCount(int requestCount) {
1480: swValve.setRequestCount(requestCount);
1481: }
1482:
1483: public int getErrorCount() {
1484: return swValve.getErrorCount();
1485: }
1486:
1487: public void setErrorCount(int errorCount) {
1488: swValve.setErrorCount(errorCount);
1489: }
1490:
1491: /**
1492: * Increment the error count used for monitoring.
1493: */
1494: public void incrementErrorCount() {
1495: swValve.setErrorCount(swValve.getErrorCount() + 1);
1496: }
1497:
1498: public long getLoadTime() {
1499: return loadTime;
1500: }
1501:
1502: public void setLoadTime(long loadTime) {
1503: this .loadTime = loadTime;
1504: }
1505:
1506: public int getClassLoadTime() {
1507: return classLoadTime;
1508: }
1509:
1510: // -------------------------------------------------------- Package Methods
1511:
1512: // -------------------------------------------------------- protected Methods
1513:
1514: /**
1515: * Add a default Mapper implementation if none have been configured
1516: * explicitly.
1517: *
1518: * @param mapperClass Java class name of the default Mapper
1519: */
1520: protected void addDefaultMapper(String mapperClass) {
1521:
1522: ; // No need for a default Mapper on a Wrapper
1523:
1524: }
1525:
1526: /**
1527: * Return <code>true</code> if the specified class name represents a
1528: * container provided servlet class that should be loaded by the
1529: * server class loader.
1530: *
1531: * @param classname Name of the class to be checked
1532: */
1533: protected boolean isContainerProvidedServlet(String classname) {
1534:
1535: if (classname.startsWith("org.apache.catalina.")) {
1536: return (true);
1537: }
1538: try {
1539: Class clazz = this .getClass().getClassLoader().loadClass(
1540: classname);
1541: return (ContainerServlet.class.isAssignableFrom(clazz));
1542: } catch (Throwable t) {
1543: return (false);
1544: }
1545:
1546: }
1547:
1548: /**
1549: * Return <code>true</code> if loading this servlet is allowed.
1550: */
1551: protected boolean isServletAllowed(Object servlet) {
1552:
1553: // Privileged webapps may load all servlets without restriction
1554: if (((Context) getParent()).getPrivileged()) {
1555: return true;
1556: }
1557:
1558: if (servlet instanceof ContainerServlet) {
1559: return (false);
1560: }
1561:
1562: Class clazz = servlet.getClass();
1563: while (clazz != null
1564: && !clazz.getName().equals(
1565: "javax.servlet.http.HttpServlet")) {
1566: if ("restricted".equals(restrictedServlets
1567: .getProperty(clazz.getName()))) {
1568: return (false);
1569: }
1570: clazz = clazz.getSuperclass();
1571: }
1572:
1573: return (true);
1574:
1575: }
1576:
1577: protected Method[] getAllDeclaredMethods(Class c) {
1578:
1579: if (c.equals(javax.servlet.http.HttpServlet.class)) {
1580: return null;
1581: }
1582:
1583: Method[] parentMethods = getAllDeclaredMethods(c
1584: .getSuperclass());
1585:
1586: Method[] this Methods = c.getDeclaredMethods();
1587: if (this Methods == null) {
1588: return parentMethods;
1589: }
1590:
1591: if ((parentMethods != null) && (parentMethods.length > 0)) {
1592: Method[] allMethods = new Method[parentMethods.length
1593: + this Methods.length];
1594: System.arraycopy(parentMethods, 0, allMethods, 0,
1595: parentMethods.length);
1596: System.arraycopy(this Methods, 0, allMethods,
1597: parentMethods.length, this Methods.length);
1598:
1599: this Methods = allMethods;
1600: }
1601:
1602: return this Methods;
1603: }
1604:
1605: // ------------------------------------------------------ Lifecycle Methods
1606:
1607: /**
1608: * Start this component, pre-loading the servlet if the load-on-startup
1609: * value is set appropriately.
1610: *
1611: * @exception LifecycleException if a fatal error occurs during startup
1612: */
1613: public void start() throws LifecycleException {
1614:
1615: // Send j2ee.state.starting notification
1616: if (this .getObjectName() != null) {
1617: Notification notification = new Notification(
1618: "j2ee.state.starting", this .getObjectName(),
1619: sequenceNumber++);
1620: broadcaster.sendNotification(notification);
1621: }
1622:
1623: // Start up this component
1624: super .start();
1625:
1626: if (oname != null)
1627: registerJMX((StandardContext) getParent());
1628:
1629: // Load and initialize an instance of this servlet if requested
1630: // MOVED TO StandardContext START() METHOD
1631:
1632: setAvailable(0L);
1633:
1634: // Send j2ee.state.running notification
1635: if (this .getObjectName() != null) {
1636: Notification notification = new Notification(
1637: "j2ee.state.running", this .getObjectName(),
1638: sequenceNumber++);
1639: broadcaster.sendNotification(notification);
1640: }
1641:
1642: }
1643:
1644: /**
1645: * Stop this component, gracefully shutting down the servlet if it has
1646: * been initialized.
1647: *
1648: * @exception LifecycleException if a fatal error occurs during shutdown
1649: */
1650: public void stop() throws LifecycleException {
1651:
1652: setAvailable(Long.MAX_VALUE);
1653:
1654: // Send j2ee.state.stopping notification
1655: if (this .getObjectName() != null) {
1656: Notification notification = new Notification(
1657: "j2ee.state.stopping", this .getObjectName(),
1658: sequenceNumber++);
1659: broadcaster.sendNotification(notification);
1660: }
1661:
1662: // Shut down our servlet instance (if it has been initialized)
1663: try {
1664: unload();
1665: } catch (ServletException e) {
1666: getServletContext().log(
1667: sm.getString("standardWrapper.unloadException",
1668: getName()), e);
1669: }
1670:
1671: // Shut down this component
1672: super .stop();
1673:
1674: // Send j2ee.state.stoppped notification
1675: if (this .getObjectName() != null) {
1676: Notification notification = new Notification(
1677: "j2ee.state.stopped", this .getObjectName(),
1678: sequenceNumber++);
1679: broadcaster.sendNotification(notification);
1680: }
1681:
1682: if (oname != null) {
1683: Registry.getRegistry(null, null).unregisterComponent(oname);
1684:
1685: // Send j2ee.object.deleted notification
1686: Notification notification = new Notification(
1687: "j2ee.object.deleted", this .getObjectName(),
1688: sequenceNumber++);
1689: broadcaster.sendNotification(notification);
1690: }
1691:
1692: if (isJspServlet && jspMonitorON != null) {
1693: Registry.getRegistry(null, null).unregisterComponent(
1694: jspMonitorON);
1695: }
1696:
1697: }
1698:
1699: protected void registerJMX(StandardContext ctx) {
1700:
1701: String parentName = ctx.getName();
1702: parentName = ("".equals(parentName)) ? "/" : parentName;
1703:
1704: String hostName = ctx.getParent().getName();
1705: hostName = (hostName == null) ? "DEFAULT" : hostName;
1706:
1707: String domain = ctx.getDomain();
1708:
1709: String webMod = "//" + hostName + parentName;
1710: String onameStr = domain + ":j2eeType=Servlet,name="
1711: + getName() + ",WebModule=" + webMod
1712: + ",J2EEApplication=" + ctx.getJ2EEApplication()
1713: + ",J2EEServer=" + ctx.getJ2EEServer();
1714: try {
1715: oname = new ObjectName(onameStr);
1716: controller = oname;
1717: Registry.getRegistry(null, null).registerComponent(this ,
1718: oname, null);
1719:
1720: // Send j2ee.object.created notification
1721: if (this .getObjectName() != null) {
1722: Notification notification = new Notification(
1723: "j2ee.object.created", this .getObjectName(),
1724: sequenceNumber++);
1725: broadcaster.sendNotification(notification);
1726: }
1727: } catch (Exception ex) {
1728: log.info("Error registering servlet with jmx " + this );
1729: }
1730:
1731: if (isJspServlet) {
1732: // Register JSP monitoring mbean
1733: onameStr = domain + ":type=JspMonitor,name=" + getName()
1734: + ",WebModule=" + webMod + ",J2EEApplication="
1735: + ctx.getJ2EEApplication() + ",J2EEServer="
1736: + ctx.getJ2EEServer();
1737: try {
1738: jspMonitorON = new ObjectName(onameStr);
1739: Registry.getRegistry(null, null).registerComponent(
1740: instance, jspMonitorON, null);
1741: } catch (Exception ex) {
1742: log.info("Error registering JSP monitoring with jmx "
1743: + instance);
1744: }
1745: }
1746: }
1747:
1748: /* Remove a JMX notficationListener
1749: * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
1750: */
1751: public void removeNotificationListener(
1752: NotificationListener listener, NotificationFilter filter,
1753: Object object) throws ListenerNotFoundException {
1754: broadcaster
1755: .removeNotificationListener(listener, filter, object);
1756:
1757: }
1758:
1759: protected MBeanNotificationInfo[] notificationInfo;
1760:
1761: /* Get JMX Broadcaster Info
1762: * @TODO use StringManager for international support!
1763: * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
1764: * @see javax.management.NotificationBroadcaster#getNotificationInfo()
1765: */
1766: public MBeanNotificationInfo[] getNotificationInfo() {
1767:
1768: if (notificationInfo == null) {
1769: notificationInfo = new MBeanNotificationInfo[] {
1770: new MBeanNotificationInfo(
1771: new String[] { "j2ee.object.created" },
1772: Notification.class.getName(),
1773: "servlet is created"),
1774: new MBeanNotificationInfo(
1775: new String[] { "j2ee.state.starting" },
1776: Notification.class.getName(),
1777: "servlet is starting"),
1778: new MBeanNotificationInfo(
1779: new String[] { "j2ee.state.running" },
1780: Notification.class.getName(),
1781: "servlet is running"),
1782: new MBeanNotificationInfo(
1783: new String[] { "j2ee.state.stopped" },
1784: Notification.class.getName(),
1785: "servlet start to stopped"),
1786: new MBeanNotificationInfo(
1787: new String[] { "j2ee.object.stopped" },
1788: Notification.class.getName(),
1789: "servlet is stopped"),
1790: new MBeanNotificationInfo(
1791: new String[] { "j2ee.object.deleted" },
1792: Notification.class.getName(),
1793: "servlet is deleted") };
1794:
1795: }
1796:
1797: return notificationInfo;
1798: }
1799:
1800: /* Add a JMX-NotificationListener
1801: * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
1802: */
1803: public void addNotificationListener(NotificationListener listener,
1804: NotificationFilter filter, Object object)
1805: throws IllegalArgumentException {
1806: broadcaster.addNotificationListener(listener, filter, object);
1807: }
1808:
1809: /**
1810: * Remove a JMX-NotificationListener
1811: * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
1812: */
1813: public void removeNotificationListener(NotificationListener listener)
1814: throws ListenerNotFoundException {
1815: broadcaster.removeNotificationListener(listener);
1816: }
1817:
1818: // ------------------------------------------------------------- Attributes
1819:
1820: public boolean isEventProvider() {
1821: return false;
1822: }
1823:
1824: public boolean isStateManageable() {
1825: return false;
1826: }
1827:
1828: public boolean isStatisticsProvider() {
1829: return false;
1830: }
1831:
1832: }
|