1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.jasper.servlet;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URL;
23 import java.net.URLClassLoader;
24 import java.security.CodeSource;
25 import java.security.PermissionCollection;
26
27 import org.apache.jasper.Constants;
28
29 /**
30 * Class loader for loading servlet class files (corresponding to JSP files)
31 * and tag handler class files (corresponding to tag files).
32 *
33 * @author Anil K. Vijendran
34 * @author Harish Prabandham
35 */
36 public class JasperLoader extends URLClassLoader {
37
38 private final PermissionCollection permissionCollection;
39 private final SecurityManager securityManager;
40
41 public JasperLoader(URL[] urls, ClassLoader parent,
42 PermissionCollection permissionCollection) {
43 super(urls, parent);
44 this.permissionCollection = permissionCollection;
45 this.securityManager = System.getSecurityManager();
46 }
47
48 /**
49 * Load the class with the specified name. This method searches for
50 * classes in the same manner as <code>loadClass(String, boolean)</code>
51 * with <code>false</code> as the second argument.
52 *
53 * @param name Name of the class to be loaded
54 *
55 * @exception ClassNotFoundException if the class was not found
56 */
57 @Override
58 public Class<?> loadClass(String name) throws ClassNotFoundException {
59 return loadClass(name, false);
60 }
61
62 /**
63 * Load the class with the specified name, searching using the following
64 * algorithm until it finds and returns the class. If the class cannot
65 * be found, returns <code>ClassNotFoundException</code>.
66 * <ul>
67 * <li>Call <code>findLoadedClass(String)</code> to check if the
68 * class has already been loaded. If it has, the same
69 * <code>Class</code> object is returned.</li>
70 * <li>If the <code>delegate</code> property is set to <code>true</code>,
71 * call the <code>loadClass()</code> method of the parent class
72 * loader, if any.</li>
73 * <li>Call <code>findClass()</code> to find this class in our locally
74 * defined repositories.</li>
75 * <li>Call the <code>loadClass()</code> method of our parent
76 * class loader, if any.</li>
77 * </ul>
78 * If the class was found using the above steps, and the
79 * <code>resolve</code> flag is <code>true</code>, this method will then
80 * call <code>resolveClass(Class)</code> on the resulting Class object.
81 *
82 * @param name Name of the class to be loaded
83 * @param resolve If <code>true</code> then resolve the class
84 *
85 * @exception ClassNotFoundException if the class was not found
86 */
87 @Override
88 public synchronized Class<?> loadClass(final String name, boolean resolve)
89 throws ClassNotFoundException {
90
91 Class<?> clazz = null;
92
93 // (0) Check our previously loaded class cache
94 clazz = findLoadedClass(name);
95 if (clazz != null) {
96 if (resolve)
97 resolveClass(clazz);
98 return clazz;
99 }
100
101 // (.5) Permission to access this class when using a SecurityManager
102 if (securityManager != null) {
103 int dot = name.lastIndexOf('.');
104 if (dot >= 0) {
105 try {
106 // Do not call the security manager since by default, we grant that package.
107 if (!"org.apache.jasper.runtime".equalsIgnoreCase(name.substring(0,dot))){
108 securityManager.checkPackageAccess(name.substring(0,dot));
109 }
110 } catch (SecurityException se) {
111 String error = "Security Violation, attempt to use " +
112 "Restricted Class: " + name;
113 se.printStackTrace();
114 throw new ClassNotFoundException(error);
115 }
116 }
117 }
118
119 if( !name.startsWith(Constants.JSP_PACKAGE_NAME + '.') ) {
120 // Class is not in org.apache.jsp, therefore, have our
121 // parent load it
122 clazz = getParent().loadClass(name);
123 if( resolve )
124 resolveClass(clazz);
125 return clazz;
126 }
127
128 return findClass(name);
129 }
130
131
132 /**
133 * Delegate to parent
134 *
135 * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
136 */
137 @Override
138 public InputStream getResourceAsStream(String name) {
139 InputStream is = getParent().getResourceAsStream(name);
140 if (is == null) {
141 URL url = findResource(name);
142 if (url != null) {
143 try {
144 is = url.openStream();
145 } catch (IOException e) {
146 // Ignore
147 }
148 }
149 }
150 return is;
151 }
152
153
154 /**
155 * Get the Permissions for a CodeSource.
156 *
157 * Since this ClassLoader is only used for a JSP page in
158 * a web application context, we just return our preset
159 * PermissionCollection for the web app context.
160 *
161 * @param codeSource Code source where the code was loaded from
162 * @return PermissionCollection for CodeSource
163 */
164 @Override
165 public final PermissionCollection getPermissions(CodeSource codeSource) {
166 return permissionCollection;
167 }
168 }
169