0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationContext.java,v 1.39 2002/06/28 01:35:34 remm Exp $
0003: * $Revision: 1.39 $
0004: * $Date: 2002/06/28 01:35:34 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999 The Apache Software Foundation. All rights
0011: * reserved.
0012: *
0013: * Redistribution and use in source and binary forms, with or without
0014: * modification, are permitted provided that the following conditions
0015: * are met:
0016: *
0017: * 1. Redistributions of source code must retain the above copyright
0018: * notice, this list of conditions and the following disclaimer.
0019: *
0020: * 2. Redistributions in binary form must reproduce the above copyright
0021: * notice, this list of conditions and the following disclaimer in
0022: * the documentation and/or other materials provided with the
0023: * distribution.
0024: *
0025: * 3. The end-user documentation included with the redistribution, if
0026: * any, must include the following acknowlegement:
0027: * "This product includes software developed by the
0028: * Apache Software Foundation (http://www.apache.org/)."
0029: * Alternately, this acknowlegement may appear in the software itself,
0030: * if and wherever such third-party acknowlegements normally appear.
0031: *
0032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033: * Foundation" must not be used to endorse or promote products derived
0034: * from this software without prior written permission. For written
0035: * permission, please contact apache@apache.org.
0036: *
0037: * 5. Products derived from this software may not be called "Apache"
0038: * nor may "Apache" appear in their names without prior written
0039: * permission of the Apache Group.
0040: *
0041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052: * SUCH DAMAGE.
0053: * ====================================================================
0054: *
0055: * This software consists of voluntary contributions made by many
0056: * individuals on behalf of the Apache Software Foundation. For more
0057: * information on the Apache Software Foundation, please see
0058: * <http://www.apache.org/>.
0059: *
0060: * [Additional notices, if required by prior licensing conditions]
0061: *
0062: */
0063:
0064: package org.apache.catalina.core;
0065:
0066: import java.io.BufferedReader;
0067: import java.io.InputStream;
0068: import java.io.IOException;
0069: import java.io.File;
0070: import java.io.UnsupportedEncodingException;
0071: import java.net.MalformedURLException;
0072: import java.net.Socket;
0073: import java.net.URL;
0074: import java.security.AccessController;
0075: import java.security.Principal;
0076: import java.security.PrivilegedAction;
0077: import java.security.PrivilegedExceptionAction;
0078: import java.security.PrivilegedActionException;
0079: import java.util.ArrayList;
0080: import java.util.Arrays;
0081: import java.util.Collections;
0082: import java.util.Enumeration;
0083: import java.util.HashMap;
0084: import java.util.HashSet;
0085: import java.util.Iterator;
0086: import java.util.Locale;
0087: import java.util.Map;
0088: import java.util.Set;
0089: import javax.naming.NamingException;
0090: import javax.naming.Binding;
0091: import javax.naming.directory.DirContext;
0092: import javax.servlet.RequestDispatcher;
0093: import javax.servlet.Servlet;
0094: import javax.servlet.ServletContext;
0095: import javax.servlet.ServletContextAttributeEvent;
0096: import javax.servlet.ServletContextAttributeListener;
0097: import javax.servlet.ServletInputStream;
0098: import javax.servlet.ServletRequest;
0099: import javax.servlet.http.Cookie;
0100: import javax.servlet.http.HttpServletRequest;
0101: import javax.servlet.http.HttpSession;
0102: import org.apache.naming.resources.Resource;
0103: import org.apache.naming.resources.DirContextURLStreamHandler;
0104: import org.apache.naming.resources.DirContextURLConnection;
0105: import org.apache.catalina.Connector;
0106: import org.apache.catalina.Container;
0107: import org.apache.catalina.Context;
0108: import org.apache.catalina.Globals;
0109: import org.apache.catalina.Host;
0110: import org.apache.catalina.HttpRequest;
0111: import org.apache.catalina.Logger;
0112: import org.apache.catalina.Response;
0113: import org.apache.catalina.Wrapper;
0114: import org.apache.catalina.connector.HttpRequestBase;
0115: import org.apache.catalina.deploy.ApplicationParameter;
0116: import org.apache.catalina.util.Enumerator;
0117: import org.apache.catalina.util.ResourceSet;
0118: import org.apache.catalina.util.ServerInfo;
0119: import org.apache.catalina.util.StringManager;
0120:
0121: /**
0122: * Standard implementation of <code>ServletContext</code> that represents
0123: * a web application's execution environment. An instance of this class is
0124: * associated with each instance of <code>StandardContext</code>.
0125: *
0126: * @author Craig R. McClanahan
0127: * @author Remy Maucherat
0128: * @version $Revision: 1.39 $ $Date: 2002/06/28 01:35:34 $
0129: */
0130:
0131: public class ApplicationContext implements ServletContext {
0132:
0133: protected class PrivilegedGetRequestDispatcher implements
0134: PrivilegedAction {
0135:
0136: private String contextPath;
0137: private String relativeURI;
0138: private String queryString;
0139:
0140: PrivilegedGetRequestDispatcher(String contextPath,
0141: String relativeURI, String queryString) {
0142: this .contextPath = contextPath;
0143: this .relativeURI = relativeURI;
0144: this .queryString = queryString;
0145: }
0146:
0147: public Object run() {
0148: HttpRequest request = new MappingRequest(context.getPath(),
0149: contextPath + relativeURI, queryString);
0150: /*
0151: HttpRequestBase request = new HttpRequestBase();
0152: request.setContext(context);
0153: request.setContextPath(context.getPath());
0154: request.setRequestURI(contextPath + relativeURI);
0155: request.setQueryString(queryString);
0156: */
0157: Wrapper wrapper = (Wrapper) context.map(request, true);
0158: if (wrapper == null)
0159: return (null);
0160:
0161: // Construct a RequestDispatcher to process this request
0162: HttpServletRequest hrequest = (HttpServletRequest) request
0163: .getRequest();
0164: return (RequestDispatcher) new ApplicationDispatcher(
0165: wrapper, hrequest.getServletPath(), hrequest
0166: .getPathInfo(), hrequest.getQueryString(),
0167: null);
0168: }
0169:
0170: }
0171:
0172: protected class PrivilegedGetResource implements
0173: PrivilegedExceptionAction {
0174:
0175: private String path;
0176: private String host;
0177: private DirContext resources;
0178:
0179: PrivilegedGetResource(String host, String path,
0180: DirContext resources) {
0181: this .host = host;
0182: this .path = path;
0183: this .resources = resources;
0184: }
0185:
0186: public Object run() throws Exception {
0187: return new URL("jndi", null, 0, getJNDIUri(host, path),
0188: new DirContextURLStreamHandler(resources));
0189: }
0190: }
0191:
0192: protected class PrivilegedGetResourcePaths implements
0193: PrivilegedAction {
0194:
0195: private String path;
0196: private DirContext resources;
0197:
0198: PrivilegedGetResourcePaths(DirContext resources, String path) {
0199: this .resources = resources;
0200: this .path = path;
0201: }
0202:
0203: public Object run() {
0204: return (getResourcePathsInternal(resources, path));
0205: }
0206:
0207: }
0208:
0209: protected class PrivilegedLogMessage implements PrivilegedAction {
0210:
0211: private String message;
0212:
0213: PrivilegedLogMessage(String message) {
0214: this .message = message;
0215: }
0216:
0217: public Object run() {
0218: internalLog(message);
0219: return null;
0220: }
0221:
0222: }
0223:
0224: protected class PrivilegedLogException implements PrivilegedAction {
0225:
0226: private String message;
0227: private Exception exception;
0228:
0229: PrivilegedLogException(Exception exception, String message) {
0230: this .message = message;
0231: this .exception = exception;
0232: }
0233:
0234: public Object run() {
0235: internalLog(exception, message);
0236: return null;
0237: }
0238:
0239: }
0240:
0241: protected class PrivilegedLogThrowable implements PrivilegedAction {
0242:
0243: private String message;
0244: private Throwable throwable;
0245:
0246: PrivilegedLogThrowable(String message, Throwable throwable) {
0247: this .message = message;
0248: this .throwable = throwable;
0249: }
0250:
0251: public Object run() {
0252: internalLog(message, throwable);
0253: return null;
0254: }
0255:
0256: }
0257:
0258: // ----------------------------------------------------------- Constructors
0259:
0260: /**
0261: * Construct a new instance of this class, associated with the specified
0262: * Context instance.
0263: *
0264: * @param context The associated Context instance
0265: */
0266: public ApplicationContext(String basePath, StandardContext context) {
0267: super ();
0268: this .context = context;
0269: this .basePath = basePath;
0270: }
0271:
0272: // ----------------------------------------------------- Instance Variables
0273:
0274: /**
0275: * The context attributes for this context.
0276: */
0277: private HashMap attributes = new HashMap();
0278:
0279: /**
0280: * List of read only attributes for this context.
0281: */
0282: private HashMap readOnlyAttributes = new HashMap();
0283:
0284: /**
0285: * The Context instance with which we are associated.
0286: */
0287: private StandardContext context = null;
0288:
0289: /**
0290: * Empty collection to serve as the basis for empty enumerations.
0291: * <strong>DO NOT ADD ANY ELEMENTS TO THIS COLLECTION!</strong>
0292: */
0293: private static final ArrayList empty = new ArrayList();
0294:
0295: /**
0296: * The facade around this object.
0297: */
0298: private ServletContext facade = new ApplicationContextFacade(this );
0299:
0300: /**
0301: * The merged context initialization parameters for this Context.
0302: */
0303: private HashMap parameters = null;
0304:
0305: /**
0306: * The string manager for this package.
0307: */
0308: private static final StringManager sm = StringManager
0309: .getManager(Constants.Package);
0310:
0311: /**
0312: * Base path.
0313: */
0314: private String basePath = null;
0315:
0316: // --------------------------------------------------------- Public Methods
0317:
0318: /**
0319: * Clear all application-created attributes.
0320: */
0321: public void clearAttributes() {
0322:
0323: // Create list of attributes to be removed
0324: ArrayList list = new ArrayList();
0325: synchronized (attributes) {
0326: Iterator iter = attributes.keySet().iterator();
0327: while (iter.hasNext()) {
0328: list.add(iter.next());
0329: }
0330: }
0331:
0332: // Remove application originated attributes
0333: // (read only attributes will be left in place)
0334: Iterator keys = list.iterator();
0335: while (keys.hasNext()) {
0336: String key = (String) keys.next();
0337: removeAttribute(key);
0338: }
0339:
0340: }
0341:
0342: /**
0343: * Return the resources object that is mapped to a specified path.
0344: * The path must begin with a "/" and is interpreted as relative to the
0345: * current context root.
0346: */
0347: public DirContext getResources() {
0348:
0349: return context.getResources();
0350:
0351: }
0352:
0353: /**
0354: * Set an attribute as read only.
0355: */
0356: public void setAttributeReadOnly(String name) {
0357:
0358: synchronized (attributes) {
0359: if (attributes.containsKey(name))
0360: readOnlyAttributes.put(name, name);
0361: }
0362:
0363: }
0364:
0365: // ------------------------------------------------- ServletContext Methods
0366:
0367: /**
0368: * Return the value of the specified context attribute, if any;
0369: * otherwise return <code>null</code>.
0370: *
0371: * @param name Name of the context attribute to return
0372: */
0373: public Object getAttribute(String name) {
0374:
0375: synchronized (attributes) {
0376: return (attributes.get(name));
0377: }
0378:
0379: }
0380:
0381: /**
0382: * Return an enumeration of the names of the context attributes
0383: * associated with this context.
0384: */
0385: public Enumeration getAttributeNames() {
0386:
0387: synchronized (attributes) {
0388: return (new Enumerator(attributes.keySet()));
0389: }
0390:
0391: }
0392:
0393: /**
0394: * Return a <code>ServletContext</code> object that corresponds to a
0395: * specified URI on the server. This method allows servlets to gain
0396: * access to the context for various parts of the server, and as needed
0397: * obtain <code>RequestDispatcher</code> objects or resources from the
0398: * context. The given path must be absolute (beginning with a "/"),
0399: * and is interpreted based on our virtual host's document root.
0400: *
0401: * @param uri Absolute URI of a resource on the server
0402: */
0403: public ServletContext getContext(String uri) {
0404:
0405: // Validate the format of the specified argument
0406: if ((uri == null) || (!uri.startsWith("/")))
0407: return (null);
0408:
0409: // Return the current context if requested
0410: String contextPath = context.getPath();
0411: if (!contextPath.endsWith("/"))
0412: contextPath = contextPath + "/";
0413: if ((contextPath.length() > 0) && (uri.startsWith(contextPath))) {
0414: return (this );
0415: }
0416:
0417: // Return other contexts only if allowed
0418: if (!context.getCrossContext())
0419: return (null);
0420: try {
0421: Host host = (Host) context.getParent();
0422: Context child = host.map(uri);
0423: if (child != null)
0424: return (child.getServletContext());
0425: else
0426: return (null);
0427: } catch (Throwable t) {
0428: return (null);
0429: }
0430:
0431: }
0432:
0433: /**
0434: * Return the value of the specified initialization parameter, or
0435: * <code>null</code> if this parameter does not exist.
0436: *
0437: * @param name Name of the initialization parameter to retrieve
0438: */
0439: public String getInitParameter(String name) {
0440:
0441: mergeParameters();
0442: synchronized (parameters) {
0443: return ((String) parameters.get(name));
0444: }
0445:
0446: }
0447:
0448: /**
0449: * Return the names of the context's initialization parameters, or an
0450: * empty enumeration if the context has no initialization parameters.
0451: */
0452: public Enumeration getInitParameterNames() {
0453:
0454: mergeParameters();
0455: synchronized (parameters) {
0456: return (new Enumerator(parameters.keySet()));
0457: }
0458:
0459: }
0460:
0461: /**
0462: * Return the major version of the Java Servlet API that we implement.
0463: */
0464: public int getMajorVersion() {
0465:
0466: return (Constants.MAJOR_VERSION);
0467:
0468: }
0469:
0470: /**
0471: * Return the minor version of the Java Servlet API that we implement.
0472: */
0473: public int getMinorVersion() {
0474:
0475: return (Constants.MINOR_VERSION);
0476:
0477: }
0478:
0479: /**
0480: * Return the MIME type of the specified file, or <code>null</code> if
0481: * the MIME type cannot be determined.
0482: *
0483: * @param file Filename for which to identify a MIME type
0484: */
0485: public String getMimeType(String file) {
0486:
0487: if (file == null)
0488: return (null);
0489: int period = file.lastIndexOf(".");
0490: if (period < 0)
0491: return (null);
0492: String extension = file.substring(period + 1);
0493: if (extension.length() < 1)
0494: return (null);
0495: return (context.findMimeMapping(extension));
0496:
0497: }
0498:
0499: /**
0500: * Return a <code>RequestDispatcher</code> object that acts as a
0501: * wrapper for the named servlet.
0502: *
0503: * @param name Name of the servlet for which a dispatcher is requested
0504: */
0505: public RequestDispatcher getNamedDispatcher(String name) {
0506:
0507: // Validate the name argument
0508: if (name == null)
0509: return (null);
0510:
0511: // Create and return a corresponding request dispatcher
0512: Wrapper wrapper = (Wrapper) context.findChild(name);
0513: if (wrapper == null)
0514: return (null);
0515: ApplicationDispatcher dispatcher = new ApplicationDispatcher(
0516: wrapper, null, null, null, name);
0517: return ((RequestDispatcher) dispatcher);
0518:
0519: }
0520:
0521: /**
0522: * Return the real path for a given virtual path, if possible; otherwise
0523: * return <code>null</code>.
0524: *
0525: * @param path The path to the desired resource
0526: */
0527: public String getRealPath(String path) {
0528:
0529: if (!context.isFilesystemBased())
0530: return null;
0531:
0532: File file = new File(basePath, path);
0533: return (file.getAbsolutePath());
0534:
0535: }
0536:
0537: /**
0538: * Return a <code>RequestDispatcher</code> instance that acts as a
0539: * wrapper for the resource at the given path. The path must begin
0540: * with a "/" and is interpreted as relative to the current context root.
0541: *
0542: * @param path The path to the desired resource.
0543: */
0544: public RequestDispatcher getRequestDispatcher(String path) {
0545:
0546: // Validate the path argument
0547: if (path == null)
0548: return (null);
0549: if (!path.startsWith("/"))
0550: throw new IllegalArgumentException(sm.getString(
0551: "applicationContext.requestDispatcher.iae", path));
0552: if (normalize(path) == null)
0553: return (null);
0554:
0555: // Construct a "fake" request to be mapped by our Context
0556: String contextPath = context.getPath();
0557: if (contextPath == null)
0558: contextPath = "";
0559: String relativeURI = path;
0560: String queryString = null;
0561: int question = path.indexOf('?');
0562: if (question >= 0) {
0563: relativeURI = path.substring(0, question);
0564: queryString = path.substring(question + 1);
0565: }
0566: if (System.getSecurityManager() != null) {
0567: PrivilegedGetRequestDispatcher dp = new PrivilegedGetRequestDispatcher(
0568: contextPath, relativeURI, queryString);
0569: return (RequestDispatcher) AccessController
0570: .doPrivileged(dp);
0571: }
0572:
0573: // The remaining code is duplicated in PrivilegedGetRequestDispatcher,
0574: // we need to make sure they stay in sync
0575: HttpRequest request = new MappingRequest(context.getPath(),
0576: contextPath + relativeURI, queryString);
0577: /*
0578: request.setContext(context);
0579: request.setContextPath(context.getPath());
0580: request.setRequestURI(contextPath + relativeURI);
0581: request.setQueryString(queryString);
0582: */
0583: Wrapper wrapper = (Wrapper) context.map(request, true);
0584: if (wrapper == null)
0585: return (null);
0586:
0587: // Construct a RequestDispatcher to process this request
0588: HttpServletRequest hrequest = (HttpServletRequest) request
0589: .getRequest();
0590: return (RequestDispatcher) new ApplicationDispatcher(wrapper,
0591: hrequest.getServletPath(), hrequest.getPathInfo(),
0592: hrequest.getQueryString(), null);
0593:
0594: }
0595:
0596: /**
0597: * Return the URL to the resource that is mapped to a specified path.
0598: * The path must begin with a "/" and is interpreted as relative to the
0599: * current context root.
0600: *
0601: * @param path The path to the desired resource
0602: *
0603: * @exception MalformedURLException if the path is not given
0604: * in the correct form
0605: */
0606: public URL getResource(String path) throws MalformedURLException {
0607: DirContext resources = context.getResources();
0608: if (resources != null) {
0609: String fullPath = context.getName() + path;
0610: String hostName = context.getParent().getName();
0611: try {
0612: resources.lookup(path);
0613: if (System.getSecurityManager() != null) {
0614: try {
0615: PrivilegedGetResource dp = new PrivilegedGetResource(
0616: hostName, fullPath, resources);
0617: return (URL) AccessController.doPrivileged(dp);
0618: } catch (PrivilegedActionException pe) {
0619: throw pe.getException();
0620: }
0621: } else {
0622: return new URL("jndi", null, 0, getJNDIUri(
0623: hostName, fullPath),
0624: new DirContextURLStreamHandler(resources));
0625: }
0626: } catch (Exception e) {
0627: //e.printStackTrace();
0628: }
0629: }
0630: return (null);
0631:
0632: }
0633:
0634: /**
0635: * Return the requested resource as an <code>InputStream</code>. The
0636: * path must be specified according to the rules described under
0637: * <code>getResource</code>. If no such resource can be identified,
0638: * return <code>null</code>.
0639: *
0640: * @param path The path to the desired resource.
0641: */
0642: public InputStream getResourceAsStream(String path) {
0643:
0644: DirContext resources = context.getResources();
0645: if (resources != null) {
0646: try {
0647: Object resource = resources.lookup(path);
0648: if (resource instanceof Resource)
0649: return (((Resource) resource).streamContent());
0650: } catch (Exception e) {
0651: }
0652: }
0653: return (null);
0654:
0655: }
0656:
0657: /**
0658: * Return a Set containing the resource paths of resources member of the
0659: * specified collection. Each path will be a String starting with
0660: * a "/" character. The returned set is immutable.
0661: *
0662: * @param path Collection path
0663: */
0664: public Set getResourcePaths(String path) {
0665:
0666: DirContext resources = context.getResources();
0667: if (resources != null) {
0668: if (System.getSecurityManager() != null) {
0669: PrivilegedAction dp = new PrivilegedGetResourcePaths(
0670: resources, path);
0671: return ((Set) AccessController.doPrivileged(dp));
0672: } else {
0673: return (getResourcePathsInternal(resources, path));
0674: }
0675: }
0676: return (null);
0677:
0678: }
0679:
0680: /**
0681: * Internal implementation of getResourcesPath() logic.
0682: *
0683: * @param resources Directory context to search
0684: * @param path Collection path
0685: */
0686: private Set getResourcePathsInternal(DirContext resources,
0687: String path) {
0688:
0689: ResourceSet set = new ResourceSet();
0690: try {
0691: listCollectionPaths(set, resources, path);
0692: } catch (NamingException e) {
0693: return (null);
0694: }
0695: set.setLocked(true);
0696: return (set);
0697:
0698: }
0699:
0700: /**
0701: * Return the name and version of the servlet container.
0702: */
0703: public String getServerInfo() {
0704:
0705: return (ServerInfo.getServerInfo());
0706:
0707: }
0708:
0709: /**
0710: * @deprecated As of Java Servlet API 2.1, with no direct replacement.
0711: */
0712: public Servlet getServlet(String name) {
0713:
0714: return (null);
0715:
0716: }
0717:
0718: /**
0719: * Return the display name of this web application.
0720: */
0721: public String getServletContextName() {
0722:
0723: return (context.getDisplayName());
0724:
0725: }
0726:
0727: /**
0728: * @deprecated As of Java Servlet API 2.1, with no direct replacement.
0729: */
0730: public Enumeration getServletNames() {
0731:
0732: return (new Enumerator(empty));
0733:
0734: }
0735:
0736: /**
0737: * @deprecated As of Java Servlet API 2.1, with no direct replacement.
0738: */
0739: public Enumeration getServlets() {
0740:
0741: return (new Enumerator(empty));
0742:
0743: }
0744:
0745: /**
0746: * Writes the specified message to a servlet log file.
0747: *
0748: * @param message Message to be written
0749: */
0750: public void log(String message) {
0751: if (System.getSecurityManager() != null) {
0752: PrivilegedLogMessage dp = new PrivilegedLogMessage(message);
0753: AccessController.doPrivileged(dp);
0754: } else {
0755: internalLog(message);
0756: }
0757: }
0758:
0759: private void internalLog(String message) {
0760:
0761: Logger logger = context.getLogger();
0762: if (logger != null)
0763: logger.log(message);
0764:
0765: }
0766:
0767: /**
0768: * Writes the specified exception and message to a servlet log file.
0769: *
0770: * @param exception Exception to be reported
0771: * @param message Message to be written
0772: *
0773: * @deprecated As of Java Servlet API 2.1, use
0774: * <code>log(String, Throwable)</code> instead
0775: */
0776: public void log(Exception exception, String message) {
0777: if (System.getSecurityManager() != null) {
0778: PrivilegedLogException dp = new PrivilegedLogException(
0779: exception, message);
0780: AccessController.doPrivileged(dp);
0781: } else {
0782: internalLog(exception, message);
0783: }
0784: }
0785:
0786: private void internalLog(Exception exception, String message) {
0787: Logger logger = context.getLogger();
0788: if (logger != null)
0789: logger.log(exception, message);
0790:
0791: }
0792:
0793: /**
0794: * Writes the specified message and exception to a servlet log file.
0795: *
0796: * @param message Message to be written
0797: * @param throwable Exception to be reported
0798: */
0799: public void log(String message, Throwable throwable) {
0800: if (System.getSecurityManager() != null) {
0801: PrivilegedLogThrowable dp = new PrivilegedLogThrowable(
0802: message, throwable);
0803: AccessController.doPrivileged(dp);
0804: } else {
0805: internalLog(message, throwable);
0806: }
0807: }
0808:
0809: private void internalLog(String message, Throwable throwable) {
0810:
0811: Logger logger = context.getLogger();
0812: if (logger != null)
0813: logger.log(message, throwable);
0814:
0815: }
0816:
0817: /**
0818: * Remove the context attribute with the specified name, if any.
0819: *
0820: * @param name Name of the context attribute to be removed
0821: */
0822: public void removeAttribute(String name) {
0823:
0824: Object value = null;
0825: boolean found = false;
0826:
0827: // Remove the specified attribute
0828: synchronized (attributes) {
0829: // Check for read only attribute
0830: if (readOnlyAttributes.containsKey(name))
0831: return;
0832: found = attributes.containsKey(name);
0833: if (found) {
0834: value = attributes.get(name);
0835: attributes.remove(name);
0836: } else {
0837: return;
0838: }
0839: }
0840:
0841: // Notify interested application event listeners
0842: Object listeners[] = context.getApplicationListeners();
0843: if ((listeners == null) || (listeners.length == 0))
0844: return;
0845: ServletContextAttributeEvent event = new ServletContextAttributeEvent(
0846: context.getServletContext(), name, value);
0847: for (int i = 0; i < listeners.length; i++) {
0848: if (!(listeners[i] instanceof ServletContextAttributeListener))
0849: continue;
0850: ServletContextAttributeListener listener = (ServletContextAttributeListener) listeners[i];
0851: try {
0852: context.fireContainerEvent(
0853: "beforeContextAttributeRemoved", listener);
0854: listener.attributeRemoved(event);
0855: context.fireContainerEvent(
0856: "afterContextAttributeRemoved", listener);
0857: } catch (Throwable t) {
0858: context.fireContainerEvent(
0859: "afterContextAttributeRemoved", listener);
0860: // FIXME - should we do anything besides log these?
0861: log(sm.getString("applicationContext.attributeEvent"),
0862: t);
0863: }
0864: }
0865:
0866: }
0867:
0868: /**
0869: * Bind the specified value with the specified context attribute name,
0870: * replacing any existing value for that name.
0871: *
0872: * @param name Attribute name to be bound
0873: * @param value New attribute value to be bound
0874: */
0875: public void setAttribute(String name, Object value) {
0876:
0877: // Name cannot be null
0878: if (name == null)
0879: throw new IllegalArgumentException(
0880: sm
0881: .getString("applicationContext.setAttribute.namenull"));
0882:
0883: // Null value is the same as removeAttribute()
0884: if (value == null) {
0885: removeAttribute(name);
0886: return;
0887: }
0888:
0889: Object oldValue = null;
0890: boolean replaced = false;
0891:
0892: // Add or replace the specified attribute
0893: synchronized (attributes) {
0894: // Check for read only attribute
0895: if (readOnlyAttributes.containsKey(name))
0896: return;
0897: oldValue = attributes.get(name);
0898: if (oldValue != null)
0899: replaced = true;
0900: attributes.put(name, value);
0901: }
0902:
0903: // Notify interested application event listeners
0904: Object listeners[] = context.getApplicationListeners();
0905: if ((listeners == null) || (listeners.length == 0))
0906: return;
0907: ServletContextAttributeEvent event = null;
0908: if (replaced)
0909: event = new ServletContextAttributeEvent(context
0910: .getServletContext(), name, oldValue);
0911: else
0912: event = new ServletContextAttributeEvent(context
0913: .getServletContext(), name, value);
0914:
0915: for (int i = 0; i < listeners.length; i++) {
0916: if (!(listeners[i] instanceof ServletContextAttributeListener))
0917: continue;
0918: ServletContextAttributeListener listener = (ServletContextAttributeListener) listeners[i];
0919: try {
0920: if (replaced) {
0921: context.fireContainerEvent(
0922: "beforeContextAttributeReplaced", listener);
0923: listener.attributeReplaced(event);
0924: context.fireContainerEvent(
0925: "afterContextAttributeReplaced", listener);
0926: } else {
0927: context.fireContainerEvent(
0928: "beforeContextAttributeAdded", listener);
0929: listener.attributeAdded(event);
0930: context.fireContainerEvent(
0931: "afterContextAttributeAdded", listener);
0932: }
0933: } catch (Throwable t) {
0934: if (replaced)
0935: context.fireContainerEvent(
0936: "afterContextAttributeReplaced", listener);
0937: else
0938: context.fireContainerEvent(
0939: "afterContextAttributeAdded", listener);
0940: // FIXME - should we do anything besides log these?
0941: log(sm.getString("applicationContext.attributeEvent"),
0942: t);
0943: }
0944: }
0945:
0946: }
0947:
0948: // -------------------------------------------------------- Package Methods
0949:
0950: /**
0951: * Return the facade associated with this ApplicationContext.
0952: */
0953: ServletContext getFacade() {
0954:
0955: return (this .facade);
0956:
0957: }
0958:
0959: // -------------------------------------------------------- Private Methods
0960:
0961: /**
0962: * Return a context-relative path, beginning with a "/", that represents
0963: * the canonical version of the specified path after ".." and "." elements
0964: * are resolved out. If the specified path attempts to go outside the
0965: * boundaries of the current context (i.e. too many ".." path elements
0966: * are present), return <code>null</code> instead.
0967: *
0968: * @param path Path to be normalized
0969: */
0970: private String normalize(String path) {
0971:
0972: String normalized = path;
0973:
0974: // Normalize the slashes and add leading slash if necessary
0975: if (normalized.indexOf('\\') >= 0)
0976: normalized = normalized.replace('\\', '/');
0977:
0978: // Resolve occurrences of "/../" in the normalized path
0979: while (true) {
0980: int index = normalized.indexOf("/../");
0981: if (index < 0)
0982: break;
0983: if (index == 0)
0984: return (null); // Trying to go outside our context
0985: int index2 = normalized.lastIndexOf('/', index - 1);
0986: normalized = normalized.substring(0, index2)
0987: + normalized.substring(index + 3);
0988: }
0989:
0990: // Return the normalized path that we have completed
0991: return (normalized);
0992:
0993: }
0994:
0995: /**
0996: * Merge the context initialization parameters specified in the application
0997: * deployment descriptor with the application parameters described in the
0998: * server configuration, respecting the <code>override</code> property of
0999: * the application parameters appropriately.
1000: */
1001: private void mergeParameters() {
1002:
1003: if (parameters != null)
1004: return;
1005: HashMap results = new HashMap();
1006: String names[] = context.findParameters();
1007: for (int i = 0; i < names.length; i++)
1008: results.put(names[i], context.findParameter(names[i]));
1009: ApplicationParameter params[] = context
1010: .findApplicationParameters();
1011: for (int i = 0; i < params.length; i++) {
1012: if (params[i].getOverride()) {
1013: if (results.get(params[i].getName()) == null)
1014: results.put(params[i].getName(), params[i]
1015: .getValue());
1016: } else {
1017: results.put(params[i].getName(), params[i].getValue());
1018: }
1019: }
1020: parameters = results;
1021:
1022: }
1023:
1024: /**
1025: * List resource paths (recursively), and store all of them in the given
1026: * Set.
1027: */
1028: private static void listPaths(Set set, DirContext resources,
1029: String path) throws NamingException {
1030:
1031: Enumeration childPaths = resources.listBindings(path);
1032: while (childPaths.hasMoreElements()) {
1033: Binding binding = (Binding) childPaths.nextElement();
1034: String name = binding.getName();
1035: String childPath = path + "/" + name;
1036: set.add(childPath);
1037: Object object = binding.getObject();
1038: if (object instanceof DirContext) {
1039: listPaths(set, resources, childPath);
1040: }
1041: }
1042:
1043: }
1044:
1045: /**
1046: * List resource paths (recursively), and store all of them in the given
1047: * Set.
1048: */
1049: private static void listCollectionPaths(Set set,
1050: DirContext resources, String path) throws NamingException {
1051:
1052: Enumeration childPaths = resources.listBindings(path);
1053: while (childPaths.hasMoreElements()) {
1054: Binding binding = (Binding) childPaths.nextElement();
1055: String name = binding.getName();
1056: StringBuffer childPath = new StringBuffer(path);
1057: if (!"/".equals(path) && !path.endsWith("/"))
1058: childPath.append("/");
1059: childPath.append(name);
1060: Object object = binding.getObject();
1061: if (object instanceof DirContext) {
1062: childPath.append("/");
1063: }
1064: set.add(childPath.toString());
1065: }
1066:
1067: }
1068:
1069: /**
1070: * Get full path, based on the host name and the context path.
1071: */
1072: public static String getJNDIUri(String hostName, String path) {
1073: if (!path.startsWith("/"))
1074: return "/" + hostName + "/" + path;
1075: else
1076: return "/" + hostName + path;
1077: }
1078:
1079: }
|