| // ======================================================================== |
| // $Id: ContextLoader.java,v 1.37 2006/01/09 07:26:12 gregwilkins Exp $ |
| // Copyright 1999-2004 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ======================================================================== |
| |
| package org.openqa.jetty.http; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.security.CodeSource; |
| import java.security.PermissionCollection; |
| import java.util.Arrays; |
| import java.util.StringTokenizer; |
| |
| import org.apache.commons.logging.Log; |
| import org.openqa.jetty.log.LogFactory; |
| import org.openqa.jetty.util.IO; |
| import org.openqa.jetty.util.Resource; |
| |
| /* ------------------------------------------------------------ */ |
| /** ClassLoader for HttpContext. |
| * Specializes URLClassLoader with some utility and file mapping |
| * methods. |
| * |
| * This loader defaults to the 2.3 servlet spec behaviour where non |
| * system classes are loaded from the classpath in preference to the |
| * parent loader. Java2 compliant loading, where the parent loader |
| * always has priority, can be selected with the setJava2Complient method. |
| * |
| * @version $Id: ContextLoader.java,v 1.37 2006/01/09 07:26:12 gregwilkins Exp $ |
| * @author Greg Wilkins (gregw) |
| */ |
| public class ContextLoader extends URLClassLoader |
| { |
| private static Log log= LogFactory.getLog(ContextLoader.class); |
| |
| private boolean _java2compliant= false; |
| private ClassLoader _parent; |
| private PermissionCollection _permissions; |
| private String _urlClassPath; |
| private HttpContext _context; |
| |
| /* ------------------------------------------------------------ */ |
| /** Constructor. |
| * @param classPath Comma separated path of filenames or URLs |
| * pointing to directories or jar files. Directories should end |
| * with '/'. |
| * @exception IOException |
| */ |
| public ContextLoader(HttpContext context, String classPath, ClassLoader parent, PermissionCollection permisions) |
| throws MalformedURLException, IOException |
| { |
| super(new URL[0], parent); |
| _context=context; |
| _permissions= permisions; |
| _parent= parent; |
| |
| if (_parent == null) |
| _parent= getSystemClassLoader(); |
| |
| if (classPath == null) |
| { |
| _urlClassPath= ""; |
| } |
| else |
| { |
| StringTokenizer tokenizer= new StringTokenizer(classPath, ",;"); |
| |
| while (tokenizer.hasMoreTokens()) |
| { |
| Resource resource= Resource.newResource(tokenizer.nextToken()); |
| if (log.isDebugEnabled()) |
| log.debug("Path resource=" + resource); |
| |
| // Resolve file path if possible |
| File file= resource.getFile(); |
| |
| if (file != null) |
| { |
| URL url= resource.getURL(); |
| addURL(url); |
| _urlClassPath= (_urlClassPath == null) ? url.toString() : (_urlClassPath + "," + url.toString()); |
| } |
| else |
| { |
| // Add resource or expand jar/ |
| if (!resource.isDirectory() && file == null) |
| { |
| InputStream in= resource.getInputStream(); |
| File lib= new File(context.getTempDirectory(), "lib"); |
| if (!lib.exists()) |
| { |
| lib.mkdir(); |
| lib.deleteOnExit(); |
| } |
| File jar= File.createTempFile("Jetty-", ".jar", lib); |
| |
| jar.deleteOnExit(); |
| if (log.isDebugEnabled()) |
| log.debug("Extract " + resource + " to " + jar); |
| FileOutputStream out = null; |
| try |
| { |
| out= new FileOutputStream(jar); |
| IO.copy(in, out); |
| } |
| finally |
| { |
| IO.close(out); |
| } |
| |
| URL url= jar.toURL(); |
| addURL(url); |
| _urlClassPath= |
| (_urlClassPath == null) ? url.toString() : (_urlClassPath + "," + url.toString()); |
| } |
| else |
| { |
| URL url= resource.getURL(); |
| addURL(url); |
| _urlClassPath= |
| (_urlClassPath == null) ? url.toString() : (_urlClassPath + "," + url.toString()); |
| } |
| } |
| } |
| } |
| |
| if (log.isDebugEnabled()) |
| { |
| if (log.isDebugEnabled()) |
| log.debug("ClassPath=" + _urlClassPath); |
| if (log.isDebugEnabled()) |
| log.debug("Permissions=" + _permissions); |
| if (log.isDebugEnabled()) |
| log.debug("URL=" + Arrays.asList(getURLs())); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** Set Java2 compliant status. |
| * @param compliant |
| */ |
| public void setJava2Compliant(boolean compliant) |
| { |
| _java2compliant= compliant; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean isJava2Compliant() |
| { |
| return _java2compliant; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String toString() |
| { |
| return "ContextLoader@" + hashCode() + "(" + _urlClassPath + ")\n --parent--> " + _parent.toString(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public PermissionCollection getPermissions(CodeSource cs) |
| { |
| PermissionCollection pc= (_permissions == null) ? super.getPermissions(cs) : _permissions; |
| if (log.isDebugEnabled()) |
| log.debug("loader.getPermissions(" + cs + ")=" + pc); |
| return pc; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public Class loadClass(String name) throws ClassNotFoundException |
| { |
| return loadClass(name, false); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException |
| { |
| Class c= findLoadedClass(name); |
| ClassNotFoundException ex= null; |
| boolean tried_parent= false; |
| if (c == null && (_java2compliant || isSystemPath(name)) && !isServerPath(name) && _parent!=null) |
| { |
| if (log.isTraceEnabled()) |
| log.trace("try loadClass " + name + " from " + _parent); |
| tried_parent= true; |
| try |
| { |
| c= _parent.loadClass(name); |
| if (log.isTraceEnabled()) |
| log.trace("p0 loaded " + c); |
| } |
| catch (ClassNotFoundException e) |
| { |
| ex= e; |
| } |
| } |
| |
| if (c == null) |
| { |
| if (log.isTraceEnabled()) |
| log.trace("try findClass " + name + " from " + _urlClassPath); |
| try |
| { |
| c= this.findClass(name); |
| if (log.isTraceEnabled()) |
| log.trace("cx loaded " + c); |
| } |
| catch (ClassNotFoundException e) |
| { |
| ex= e; |
| } |
| } |
| |
| if (c == null && !tried_parent && !isServerPath(name) && _parent!=null) |
| { |
| if (log.isTraceEnabled()) |
| log.trace("try loadClass " + name + " from " + _parent); |
| c= _parent.loadClass(name); |
| if (log.isTraceEnabled()) |
| log.trace("p1 loaded " + c); |
| } |
| |
| if (c == null) |
| throw ex; |
| |
| if (resolve) |
| resolveClass(c); |
| |
| return c; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public URL getResource(String name) |
| { |
| URL url= null; |
| boolean tried_parent= false; |
| if (_parent!=null &&(_java2compliant || isSystemPath(name))) |
| { |
| if (log.isTraceEnabled()) |
| log.trace("try getResource " + name + " from " + _parent); |
| tried_parent= true; |
| url= _parent.getResource(name); |
| } |
| |
| if (url == null) |
| { |
| if (log.isTraceEnabled()) |
| log.trace("try findResource " + name + " from " + _urlClassPath); |
| url= this.findResource(name); |
| |
| if (url == null && name.startsWith("/")) |
| { |
| if (log.isDebugEnabled()) |
| log.debug("HACK leading / off " + name); |
| url= this.findResource(name.substring(1)); |
| } |
| } |
| |
| if (_parent!=null && url == null && !tried_parent) |
| { |
| if (log.isTraceEnabled()) |
| log.trace("try getResource " + name + " from " + _parent); |
| url= _parent.getResource(name); |
| } |
| |
| if (url != null) |
| if (log.isTraceEnabled()) |
| log.trace("found " + url); |
| |
| return url; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean isServerPath(String name) |
| { |
| name=name.replace('/','.'); |
| while(name.startsWith(".")) |
| name=name.substring(1); |
| |
| String[] server_classes=_context.getServerClasses(); |
| |
| if (server_classes!=null) |
| { |
| for (int i=0;i<server_classes.length;i++) |
| { |
| boolean result=true; |
| String c=server_classes[i]; |
| if (c.startsWith("-")) |
| { |
| c=c.substring(1); |
| result=false; |
| } |
| |
| if (c.endsWith(".")) |
| { |
| if (name.startsWith(c)) |
| return result; |
| } |
| else if (name.equals(c)) |
| { |
| return result; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean isSystemPath(String name) |
| { |
| name=name.replace('/','.'); |
| while(name.startsWith(".")) |
| name=name.substring(1); |
| |
| String[] system_classes=_context.getSystemClasses(); |
| if (system_classes!=null) |
| { |
| for (int i=0;i<system_classes.length;i++) |
| { |
| boolean result=true; |
| String c=system_classes[i]; |
| if (c.startsWith("-")) |
| { |
| c=c.substring(1); |
| result=false; |
| } |
| |
| if (c.endsWith(".")) |
| { |
| if (name.startsWith(c)) |
| return result; |
| } |
| else if (name.equals(c)) |
| return result; |
| } |
| } |
| |
| return false; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void destroy() |
| { |
| this._parent=null; |
| this._permissions=null; |
| this._urlClassPath=null; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return Returns the serverClasses. |
| */ |
| String[] getServerClasses() |
| { |
| return _context.getServerClasses(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param serverClasses The serverClasses to set. |
| */ |
| void setServerClasses(String[] serverClasses) |
| { |
| _context.setServerClasses(serverClasses); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return Returns the systemClasses. |
| */ |
| String[] getSystemClasses() |
| { |
| return _context.getSystemClasses(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param systemClasses The systemClasses to set. |
| */ |
| void setSystemClasses(String[] systemClasses) |
| { |
| _context.setSystemClasses(systemClasses); |
| } |
| } |