/* * 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.loader;
/** * Classloader implementation which is specialized for handling web applications in the most efficient way, while being * Catalina aware (all accesses to resources are made through {@link org.apache.catalina.WebResourceRoot}). This class * loader supports detection of modified Java classes, which can be used to implement auto-reload support. * <p> * This class loader is configured via the Resources children of its Context prior to calling <code>start()</code>. When * a new class is required, these Resources will be consulted first to locate the class. If it is not present, the * system class loader will be used instead. * * @author Craig R. McClanahan * @author Remy Maucherat
*/ publicclass WebappLoader extends LifecycleMBeanBase implements Loader {
/** * The class loader being managed by this Loader component.
*/ private WebappClassLoaderBase classLoader = null;
/** * The Context with which this Loader has been associated.
*/ private Context context = null;
/** * The "follow standard delegation model" flag that will be used to configure our ClassLoader.
*/ privateboolean delegate = false;
/** * The profile name which will be used by the converter, or null if not used. Any invalid profile value will default * to the TOMCAT profile, which converts all packages used by Tomcat.
*/ private String jakartaConverter = null;
/** * The Java class name of the ClassLoader implementation to be used. This class should extend WebappClassLoaderBase, * otherwise, a different loader implementation must be used.
*/ private String loaderClass = ParallelWebappClassLoader.class.getName();
/** * The string manager for this package.
*/ protectedstaticfinal StringManager sm = StringManager.getManager(WebappLoader.class);
/** * The property change support for this component.
*/ protectedfinal PropertyChangeSupport support = new PropertyChangeSupport(this);
/** * Classpath set in the loader.
*/ private String classpath = null;
if (getState().isAvailable()) { thrownew IllegalStateException(sm.getString("webappLoader.setContext.ise"));
}
// Process this property change
Context oldContext = this.context; this.context = context;
support.firePropertyChange("context", oldContext, this.context);
}
/** * Return the "follow standard delegation model" flag used to configure our ClassLoader.
*/
@Override publicboolean getDelegate() { returnthis.delegate;
}
/** * Set the "follow standard delegation model" flag used to configure our ClassLoader. * * @param delegate The new flag
*/
@Override publicvoid setDelegate(boolean delegate) { boolean oldDelegate = this.delegate; this.delegate = delegate;
support.firePropertyChange("delegate", Boolean.valueOf(oldDelegate), Boolean.valueOf(this.delegate));
}
/** * @return a non null String if the loader will attempt to use the Jakarta converter. The String is the name of the * profile used for conversion.
*/ public String getJakartaConverter() { return jakartaConverter;
}
/** * Set the Jakarta converter. * * @param jakartaConverter The profile name which will be used by the converter Any invalid profile value will * default to the TOMCAT profile, which converts all packages used by Tomcat.
*/ publicvoid setJakartaConverter(String jakartaConverter) {
String oldJakartaConverter = this.jakartaConverter; this.jakartaConverter = jakartaConverter;
support.firePropertyChange("jakartaConverter", oldJakartaConverter, this.jakartaConverter);
}
/** * @return the ClassLoader class name.
*/ public String getLoaderClass() { returnthis.loaderClass;
}
/** * Set the ClassLoader class name. * * @param loaderClass The new ClassLoader class name
*/ publicvoid setLoaderClass(String loaderClass) { this.loaderClass = loaderClass;
}
/** * Set the ClassLoader instance, without relying on reflection This method will also invoke * {@link #setLoaderClass(String)} with {@code loaderInstance.getClass().getName()} as an argument * * @param loaderInstance The new ClassLoader instance to use
*/ publicvoid setLoaderInstance(WebappClassLoaderBase loaderInstance) { this.classLoader = loaderInstance;
setLoaderClass(loaderInstance.getClass().getName());
}
// --------------------------------------------------------- Public Methods
/** * Add a property change listener to this component. * * @param listener The listener to add
*/
@Override publicvoid addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
/** * Execute a periodic task, such as reloading, etc. This method will be invoked inside the classloading context of * this container. Unexpected throwables will be caught and logged.
*/
@Override publicvoid backgroundProcess() {
Context context = getContext(); if (context != null) { if (context.getReloadable() && modified()) { Thread currentThread = Thread.currentThread();
ClassLoader originalTccl = currentThread.getContextClassLoader(); try {
currentThread.setContextClassLoader(WebappLoader.class.getClassLoader());
context.reload();
} finally {
currentThread.setContextClassLoader(originalTccl);
}
}
}
}
public String[] getLoaderRepositories() { if (classLoader == null) { returnnew String[0];
}
URL[] urls = classLoader.getURLs();
String[] result = new String[urls.length]; for (int i = 0; i < urls.length; i++) {
result[i] = urls[i].toExternalForm();
} return result;
}
public String getLoaderRepositoriesString() {
String repositories[] = getLoaderRepositories();
StringBuilder sb = new StringBuilder(); for (String repository : repositories) {
sb.append(repository).append(':');
} return sb.toString();
}
/** * Classpath, as set in org.apache.catalina.jsp_classpath context property * * @return The classpath
*/ public String getClasspath() { return classpath;
}
/** * Has the internal repository associated with this Loader been modified, such that the loaded classes should be * reloaded?
*/
@Override publicboolean modified() { return classLoader != null ? classLoader.modified() : false;
}
/** * Remove a property change listener from this component. * * @param listener The listener to remove
*/
@Override publicvoid removePropertyChangeListener(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}
/** * Return a String representation of this component.
*/
@Override public String toString() { return ToStringUtil.toString(this, context);
}
/** * Start associated {@link ClassLoader} and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error that prevents this component from being * used
*/
@Override protectedvoid startInternal() throws LifecycleException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("webappLoader.starting"));
}
if (context.getResources() == null) {
log.info(sm.getString("webappLoader.noResources", context));
setState(LifecycleState.STARTING); return;
}
// Construct a class loader based on our current repositories list try {
/** * Stop associated {@link ClassLoader} and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error that prevents this component from being * used
*/
@Override protectedvoid stopInternal() throws LifecycleException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("webappLoader.stopping"));
}
for (URL url : context.getResources().getBaseUrls()) {
classLoader.addPermission(url);
}
}
/** * Set the appropriate context attribute for our class path. This is required only because Jasper depends on it.
*/ privatevoid setClassPath() {
// Validate our current state information if (context == null) { return;
}
ServletContext servletContext = context.getServletContext(); if (servletContext == null) { return;
}
StringBuilder classpath = new StringBuilder();
// Assemble the class path information from our class loader chain
ClassLoader loader = getClassLoader();
if (delegate && loader != null) { // Skip the webapp loader for now as delegation is enabled
loader = loader.getParent();
}
while (loader != null) { if (!buildClassPath(classpath, loader)) { break;
}
loader = loader.getParent();
}
if (delegate) { // Delegation was enabled, go back and add the webapp paths
loader = getClassLoader(); if (loader != null) {
buildClassPath(classpath, loader);
}
}
this.classpath = classpath.toString();
// Store the assembled class path as a servlet context attribute
servletContext.setAttribute(Globals.CLASS_PATH_ATTR, this.classpath);
}
String contextName = context.getName(); if (!contextName.startsWith("/")) {
name.append('/');
}
name.append(contextName);
return name.toString();
}
/* * Implemented in a sub-class so EESpecProfile and EESpecProfiles are not loaded unless a profile is configured. * Otherwise, tomcat-embed-core.jar has a runtime dependency on the migration tool whether it is used or not.
*/ privatestaticclass MigrationUtil {
publicstaticvoid addJakartaEETransformer(WebappClassLoaderBase webappClassLoader, String profileName) {
EESpecProfile profile = null; try {
profile = EESpecProfiles.valueOf(profileName);
} catch (IllegalArgumentException ignored) { // Use default value
log.warn(sm.getString("webappLoader.unknownProfile", profileName));
}
webappClassLoader.addTransformer(profile != null ? new ClassConverter(profile) : new ClassConverter());
}
}
}
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.