/**
- * Return the parent class loader (if any) for web applications.
+ * Return the parent class loader for this component. If not set, return
+ * {@link Container#getParent()#getParentClassLoader()}. If no parent has
+ * been set, return the system class loader.
*/
public ClassLoader getParentClassLoader();
/**
- * Set the parent class loader (if any) for web applications.
- * This call is meaningful only <strong>before</strong> a Loader has
+ * Set the parent class loader for this component. For {@link Context}s
+ * this call is meaningful only <strong>before</strong> a Loader has
* been configured, and the specified value (if non-null) should be
* passed as an argument to the class loader constructor.
*
/**
- * Return the parent class loader.
+ * Return the parent class loader for this component. If not set, return
+ * {@link Server#getCatalina()#getParentClassLoader(). If no catalina has
+ * been set, return the system class loader.
*/
public ClassLoader getParentClassLoader();
+
+ /**
+ * Set the parent class loader for this server.
+ *
+ * @param parent The new parent class loader
+ */
+ public void setParentClassLoader(ClassLoader parent);
+
/**
* Return the outer Catalina startup/shutdown component if present.
public void setServer(Server server);
/**
- * Return the parent class loader.
+ * Return the parent class loader for this component. If not set, return
+ * {@link Service#getServer()#getParentClassLoader(). If no server has
+ * been set, return the system class loader.
*/
public ClassLoader getParentClassLoader();
-
+
+ /**
+ * Set the parent class loader for this service.
+ *
+ * @param parent The new parent class loader
+ */
+ public void setParentClassLoader(ClassLoader parent);
+
// --------------------------------------------------------- Public Methods
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
package org.apache.catalina.core;
-
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
* @author Craig R. McClanahan
* @version $Id$
*/
-public final class StandardServer extends LifecycleMBeanBase
- implements Server {
+public final class StandardServer extends LifecycleMBeanBase implements Server {
private static final Log log = LogFactory.getLog(StandardServer.class);
private Catalina catalina = null;
+ private ClassLoader parentClassLoader = null;
+
// ------------------------------------------------------------- Properties
*/
@Override
public ClassLoader getParentClassLoader() {
+ if (parentClassLoader != null)
+ return (parentClassLoader);
if (catalina != null) {
return (catalina.getParentClassLoader());
}
return (ClassLoader.getSystemClassLoader());
}
+ /**
+ * Set the parent class loader for this server.
+ *
+ * @param parent The new parent class loader
+ */
+ @Override
+ public void setParentClassLoader(ClassLoader parent) {
+ ClassLoader oldParentClassLoader = this.parentClassLoader;
+ this.parentClassLoader = parent;
+ support.firePropertyChange("parentClassLoader", oldParentClassLoader,
+ this.parentClassLoader);
+ }
+
+
private ObjectName onameStringCache;
private ObjectName onameMBeanFactory;
private ObjectName onameNamingResoucres;
*/
protected Container container = null;
+ private ClassLoader parentClassLoader = null;
// ------------------------------------------------------------- Properties
*/
@Override
public ClassLoader getParentClassLoader() {
+ if (parentClassLoader != null)
+ return (parentClassLoader);
if (server != null) {
return (server.getParentClassLoader());
}
return (ClassLoader.getSystemClassLoader());
}
+ /**
+ * Set the parent class loader for this server.
+ *
+ * @param parent The new parent class loader
+ */
+ @Override
+ public void setParentClassLoader(ClassLoader parent) {
+ ClassLoader oldParentClassLoader = this.parentClassLoader;
+ this.parentClassLoader = parent;
+ support.firePropertyChange("parentClassLoader", oldParentClassLoader,
+ this.parentClassLoader);
+ }
@Override
protected String getDomainInternal() {
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.catalina.startup;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.loader.WebappClassLoader;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestTomcatClassLoader extends TomcatBaseTest {
+
+ public void testDefaultClassLoader() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ // Must have a real docBase - just use temp
+ Context ctx =
+ tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+
+ Tomcat.addServlet(ctx, "ClassLoaderReport", new ClassLoaderReport(null));
+ ctx.addServletMapping("/", "ClassLoaderReport");
+
+ tomcat.start();
+
+ ByteChunk res = getUrl("http://localhost:" + getPort() + "/");
+ assertEquals("WEBAPP,SYSTEM,OTHER,", res.toString());
+ }
+
+ public void testNonDefaultClassLoader() throws Exception {
+
+ ClassLoader cl = new URLClassLoader(new URL[0],
+ Thread.currentThread().getContextClassLoader());
+
+ Thread.currentThread().setContextClassLoader(cl);
+
+ Tomcat tomcat = getTomcatInstance();
+ tomcat.getServer().setParentClassLoader(cl);
+
+ // Must have a real docBase - just use temp
+ Context ctx =
+ tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+
+ Tomcat.addServlet(ctx, "ClassLoaderReport", new ClassLoaderReport(cl));
+ ctx.addServletMapping("/", "ClassLoaderReport");
+
+ tomcat.start();
+
+ ByteChunk res = getUrl("http://localhost:" + getPort() + "/");
+ assertEquals("WEBAPP,CUSTOM,SYSTEM,OTHER,", res.toString());
+ }
+
+ private static final class ClassLoaderReport extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ ClassLoader custom;
+
+ public ClassLoaderReport(ClassLoader custom) {
+ this.custom = custom;
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ resp.setContentType("text/plain");
+ PrintWriter out = resp.getWriter();
+
+ ClassLoader system = ClassLoader.getSystemClassLoader();
+
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ while (cl != null) {
+ if (system == cl) {
+ out.print("SYSTEM,");
+ } else if (custom == cl) {
+ out.print("CUSTOM,");
+ } else if (cl instanceof WebappClassLoader) {
+ out.print("WEBAPP,");
+ } else {
+ out.print("OTHER,");
+ }
+ cl = cl.getParent();
+ }
+ }
+ }
+}
Improve fix for <bug>50205</bug> to trigger an error earlier if invalid
configuration is used. (markt)
</update>
+ <add>
+ Provide additional control over component class loaders, primarily for
+ use when embedding. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">