ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/catalina/loader/WebappLoader.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/catalina/loader/WebappLoader.java
Status
scanned
Type
file
Name
WebappLoader.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
18810 (18.4 KB)
MD5
94a355b24307cdb49b5c3c330f4e81f8
SHA1
1b88330891ab797853d32e1ecade11d6b1fce7d5
SHA256
4181d9a32dd0a7f98e3365626750d4817e740fdd4fa3010d38773ce315f12345
SHA512

      
    
SHA1_git
576ca14236d49a52692c69592d1515c0768679b0
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
WebappLoader.java | 18.4 KB |

/* * 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; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.lang.reflect.Constructor; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import javax.management.ObjectName; import jakarta.servlet.ServletContext; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Loader; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.catalina.util.ToStringUtil; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jakartaee.ClassConverter; import org.apache.tomcat.jakartaee.EESpecProfile; import org.apache.tomcat.jakartaee.EESpecProfiles; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** * 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. */ public class WebappLoader extends LifecycleMBeanBase implements Loader { private static final Log log = LogFactory.getLog(WebappLoader.class); // ----------------------------------------------------- Instance Variables /** * 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. */ private boolean 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. */ protected static final StringManager sm = StringManager.getManager(WebappLoader.class); /** * The property change support for this component. */ protected final PropertyChangeSupport support = new PropertyChangeSupport(this); /** * Classpath set in the loader. */ private String classpath = null; // ------------------------------------------------------------- Properties @Override public ClassLoader getClassLoader() { return classLoader; } @Override public Context getContext() { return context; } @Override public void setContext(Context context) { if (this.context == context) { return; } if (getState().isAvailable()) { throw new IllegalStateException(sm.getString("webappLoader.setContext.ise")); } // Process this property change Context oldContext = this.context; this.context = context; support.firePropertyChange("context", oldContext, this.context); } @Override public boolean getDelegate() { return this.delegate; } @Override public void 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. */ public void setJakartaConverter(String jakartaConverter) { String oldJakartaConverter = this.jakartaConverter; this.jakartaConverter = jakartaConverter; support.firePropertyChange("jakartaConverter", oldJakartaConverter, this.jakartaConverter); } /** * @return the ClassLoader class name. */ public String getLoaderClass() { return this.loaderClass; } /** * Set the ClassLoader class name. * * @param loaderClass The new ClassLoader class name */ public void 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 */ public void setLoaderInstance(WebappClassLoaderBase loaderInstance) { this.classLoader = loaderInstance; setLoaderClass(loaderInstance.getClass().getName()); } // --------------------------------------------------------- Public Methods @Override public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } @Override public void 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) { return new 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; } @Override public boolean modified() { return classLoader != null && classLoader.modified(); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } @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 protected void 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 { classLoader = createClassLoader(); classLoader.setResources(context.getResources()); classLoader.setDelegate(this.delegate); // Set Jakarta class converter if (getJakartaConverter() != null) { MigrationUtil.addJakartaEETransformer(classLoader, getJakartaConverter()); } classLoader.start(); // Configure our repositories setClassPath(); String contextName = context.getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } ObjectName cloname = new ObjectName(context.getDomain() + ":type=" + classLoader.getClass().getSimpleName() + ",host=" + context.getParent().getName() + ",context=" + contextName); Registry.getRegistry(null).registerComponent(classLoader, cloname, null); } catch (Throwable t) { Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(throwable); throw new LifecycleException(sm.getString("webappLoader.startError"), throwable); } setState(LifecycleState.STARTING); } /** * 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 protected void stopInternal() throws LifecycleException { if (log.isDebugEnabled()) { log.debug(sm.getString("webappLoader.stopping")); } setState(LifecycleState.STOPPING); // Remove context attributes as appropriate ServletContext servletContext = context.getServletContext(); servletContext.removeAttribute(Globals.CLASS_PATH_ATTR); // Throw away our current class loader if any if (classLoader != null) { try { classLoader.stop(); } finally { classLoader.destroy(); } // classLoader must be non-null to have been registered try { String contextName = context.getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } ObjectName cloname = new ObjectName(context.getDomain() + ":type=" + classLoader.getClass().getSimpleName() + ",host=" + context.getParent().getName() + ",context=" + contextName); Registry.getRegistry(null).unregisterComponent(cloname); } catch (Exception e) { log.warn(sm.getString("webappLoader.stopError"), e); } } classLoader = null; } // ------------------------------------------------------- Private Methods /** * Create associated classLoader. */ private WebappClassLoaderBase createClassLoader() throws Exception { if (classLoader != null) { return classLoader; } if (ParallelWebappClassLoader.class.getName().equals(loaderClass)) { return new ParallelWebappClassLoader(context.getParentClassLoader()); } Class<?> clazz = Class.forName(loaderClass); ClassLoader parentClassLoader = context.getParentClassLoader(); Class<?>[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor<?> constr = clazz.getConstructor(argTypes); return (WebappClassLoaderBase) constr.newInstance(args); } /** * Set the appropriate context attribute for our class path. This is required only because Jasper depends on it. */ private void 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); } private boolean buildClassPath(StringBuilder classpath, ClassLoader loader) { if (loader instanceof URLClassLoader) { URL[] repositories = ((URLClassLoader) loader).getURLs(); for (URL url : repositories) { String repository = url.toString(); if (repository == null) { continue; } if (repository.startsWith("file:")) { // Let the JRE handle all the edge cases for URL to path conversion. try { File f = new File(url.toURI()); repository = f.getAbsolutePath(); } catch (URISyntaxException | IllegalArgumentException e) { // Can't convert from URL to URI. Treat as non-file URL and skip. continue; } } else { continue; } if (!classpath.isEmpty()) { classpath.append(File.pathSeparator); } classpath.append(repository); } } else if (loader == ClassLoader.getSystemClassLoader()) { // From Java 9 the internal class loaders no longer extend URLCLassLoader String cp = System.getProperty("java.class.path"); if (cp != null && !cp.isEmpty()) { if (!classpath.isEmpty()) { classpath.append(File.pathSeparator); } classpath.append(cp); } return false; } else { // Ignore Graal "unknown" classloader if (!JreCompat.isGraalAvailable()) { log.info(sm.getString("webappLoader.unknownClassLoader", loader, loader.getClass())); } return false; } return true; } @Override protected String getDomainInternal() { return context.getDomain(); } @Override protected String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Loader"); name.append(",host="); name.append(context.getParent().getName()); name.append(",context="); String contextName = context.getName(); if (!contextName.startsWith("/")) { name.append('/'); } name.append(contextName); return name.toString(); } /** * Implemented in a subclass 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. */ private static class MigrationUtil { public static void 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()); } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
7.48
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9