mirror of
https://gitee.com/nutz/nutzboot.git
synced 2024-12-12 13:25:22 +08:00
tomcat support!
This commit is contained in:
parent
084d2b26e7
commit
bd83fbdcac
@ -0,0 +1,205 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.nutz.lang.Files;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLConnection;
|
||||
import java.security.CodeSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
|
||||
public abstract class AbstractServletContainerFactory {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String[] COMMON_DOC_ROOTS = { "webapp", "public","static" };
|
||||
|
||||
private File documentRoot;
|
||||
|
||||
public AbstractServletContainerFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
public File getDocumentRoot() {
|
||||
return this.documentRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute document root when it points to a valid directory, logging a
|
||||
* warning and returning {@code null} otherwise.
|
||||
* @return the valid document root
|
||||
*/
|
||||
protected final File getValidDocumentRoot(String staticPath) {
|
||||
File file = getDocumentRoot();
|
||||
// If document root not explicitly set see if we are running from a war archive
|
||||
file = file != null ? file : getWarFileDocumentRoot();
|
||||
// If not a war archive maybe it is an exploded war
|
||||
file = file != null ? file : getExplodedWarFileDocumentRoot();
|
||||
// Or maybe there is a document root in a well-known location
|
||||
file = file != null ? file : getCommonDocumentRoot();
|
||||
//static file
|
||||
file = file != null ? file : Files.findFile(staticPath);
|
||||
if (file == null && this.logger.isDebugEnabled()) {
|
||||
this.logger
|
||||
.debug("None of the document roots " + Arrays.asList(COMMON_DOC_ROOTS)
|
||||
+ " point to a directory and will be ignored.");
|
||||
}
|
||||
else if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Document root: " + file);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private File getExplodedWarFileDocumentRoot() {
|
||||
return getExplodedWarFileDocumentRoot(getCodeSourceArchive());
|
||||
}
|
||||
|
||||
protected List<URL> getUrlsOfJarsWithMetaInfResources() {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
List<URL> staticResourceUrls = new ArrayList<URL>();
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
|
||||
try {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
File file = new File(url.getFile());
|
||||
if (file.isDirectory()
|
||||
&& new File(file, "META-INF/resources").isDirectory()) {
|
||||
staticResourceUrls.add(url);
|
||||
}
|
||||
else if (isResourcesJar(file)) {
|
||||
staticResourceUrls.add(url);
|
||||
}
|
||||
}
|
||||
else {
|
||||
URLConnection connection = url.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
if (isResourcesJar((JarURLConnection) connection)) {
|
||||
staticResourceUrls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return staticResourceUrls;
|
||||
}
|
||||
|
||||
private boolean isResourcesJar(JarURLConnection connection) {
|
||||
try {
|
||||
return isResourcesJar(connection.getJarFile());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResourcesJar(File file) {
|
||||
try {
|
||||
return isResourcesJar(new JarFile(file));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResourcesJar(JarFile jar) throws IOException {
|
||||
try {
|
||||
return jar.getName().endsWith(".jar")
|
||||
&& (jar.getJarEntry("META-INF/resources") != null);
|
||||
}
|
||||
finally {
|
||||
jar.close();
|
||||
}
|
||||
}
|
||||
|
||||
File getExplodedWarFileDocumentRoot(File codeSourceFile) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Code archive: " + codeSourceFile);
|
||||
}
|
||||
if (codeSourceFile != null && codeSourceFile.exists()) {
|
||||
String path = codeSourceFile.getAbsolutePath();
|
||||
int webInfPathIndex = path
|
||||
.indexOf(File.separatorChar + "WEB-INF" + File.separatorChar);
|
||||
if (webInfPathIndex >= 0) {
|
||||
path = path.substring(0, webInfPathIndex);
|
||||
return new File(path);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File getWarFileDocumentRoot() {
|
||||
return getArchiveFileDocumentRoot(".war");
|
||||
}
|
||||
|
||||
private File getArchiveFileDocumentRoot(String extension) {
|
||||
File file = getCodeSourceArchive();
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Code archive: " + file);
|
||||
}
|
||||
if (file != null && file.exists() && !file.isDirectory()
|
||||
&& file.getName().toLowerCase().endsWith(extension)) {
|
||||
return file.getAbsoluteFile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File getCommonDocumentRoot() {
|
||||
for (String commonDocRoot : COMMON_DOC_ROOTS) {
|
||||
URL url = Thread.currentThread().getContextClassLoader().getResource(commonDocRoot);
|
||||
if (url!=null) {
|
||||
File root = new File(url.getPath());
|
||||
if (root.exists() && root.isDirectory()) {
|
||||
return root.getAbsoluteFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File getCodeSourceArchive() {
|
||||
return getCodeSourceArchive(getClass().getProtectionDomain().getCodeSource());
|
||||
}
|
||||
|
||||
File getCodeSourceArchive(CodeSource codeSource) {
|
||||
try {
|
||||
URL location = (codeSource == null ? null : codeSource.getLocation());
|
||||
if (location == null) {
|
||||
return null;
|
||||
}
|
||||
String path;
|
||||
URLConnection connection = location.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
path = ((JarURLConnection) connection).getJarFile().getName();
|
||||
}
|
||||
else {
|
||||
path = location.toURI().getPath();
|
||||
}
|
||||
if (path.contains("!/")) {
|
||||
path = path.substring(0, path.indexOf("!/"));
|
||||
}
|
||||
return new File(path);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected final File getValidSessionStoreDir(boolean mkdirs) {
|
||||
return new ApplicationTemp().getDir("servlet-sessions");
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public class ApplicationHome {
|
||||
|
||||
private final File source;
|
||||
|
||||
private final File dir;
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationHome} instance.
|
||||
*/
|
||||
public ApplicationHome() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationHome} instance for the specified source class.
|
||||
* @param sourceClass the source class or {@code null}
|
||||
*/
|
||||
public ApplicationHome(Class<?> sourceClass) {
|
||||
this.source = findSource(sourceClass == null ? getStartClass() : sourceClass);
|
||||
this.dir = findHomeDir(this.source);
|
||||
}
|
||||
|
||||
private Class<?> getStartClass() {
|
||||
try {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
return getStartClass(classLoader.getResources("META-INF/MANIFEST.MF"));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> getStartClass(Enumeration<URL> manifestResources) {
|
||||
while (manifestResources.hasMoreElements()) {
|
||||
try {
|
||||
InputStream inputStream = manifestResources.nextElement().openStream();
|
||||
try {
|
||||
Manifest manifest = new Manifest(inputStream);
|
||||
String startClass = manifest.getMainAttributes()
|
||||
.getValue("Start-Class");
|
||||
if (startClass != null) {
|
||||
return ClassUtils.forName(startClass,
|
||||
getClass().getClassLoader());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File findSource(Class<?> sourceClass) {
|
||||
try {
|
||||
ProtectionDomain domain = (sourceClass == null ? null
|
||||
: sourceClass.getProtectionDomain());
|
||||
CodeSource codeSource = (domain == null ? null : domain.getCodeSource());
|
||||
URL location = (codeSource == null ? null : codeSource.getLocation());
|
||||
File source = (location == null ? null : findSource(location));
|
||||
if (source != null && source.exists() && !isUnitTest()) {
|
||||
return source.getAbsoluteFile();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnitTest() {
|
||||
try {
|
||||
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
|
||||
if (element.getClassName().startsWith("org.junit.")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private File findSource(URL location) throws IOException {
|
||||
URLConnection connection = location.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
return getRootJarFile(((JarURLConnection) connection).getJarFile());
|
||||
}
|
||||
return new File(location.getPath());
|
||||
}
|
||||
|
||||
private File getRootJarFile(JarFile jarFile) {
|
||||
String name = jarFile.getName();
|
||||
int separator = name.indexOf("!/");
|
||||
if (separator > 0) {
|
||||
name = name.substring(0, separator);
|
||||
}
|
||||
return new File(name);
|
||||
}
|
||||
|
||||
private File findHomeDir(File source) {
|
||||
File homeDir = source;
|
||||
homeDir = (homeDir == null ? findDefaultHomeDir() : homeDir);
|
||||
if (homeDir.isFile()) {
|
||||
homeDir = homeDir.getParentFile();
|
||||
}
|
||||
homeDir = (homeDir.exists() ? homeDir : new File("."));
|
||||
return homeDir.getAbsoluteFile();
|
||||
}
|
||||
|
||||
private File findDefaultHomeDir() {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
return new File(StringUtils.hasLength(userDir) ? userDir : ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying source used to find the home directory. This is usually the
|
||||
* jar file or a directory. Can return {@code null} if the source cannot be
|
||||
* determined.
|
||||
* @return the underlying source or {@code null}
|
||||
*/
|
||||
public File getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the application home directory.
|
||||
* @return the home directory (never {@code null})
|
||||
*/
|
||||
public File getDir() {
|
||||
return this.dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDir().toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class ApplicationTemp {
|
||||
|
||||
private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
private final Class<?> sourceClass;
|
||||
|
||||
private volatile File dir;
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationTemp} instance.
|
||||
*/
|
||||
public ApplicationTemp() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationTemp} instance for the specified source class.
|
||||
* @param sourceClass the source class or {@code null}
|
||||
*/
|
||||
public ApplicationTemp(Class<?> sourceClass) {
|
||||
this.sourceClass = sourceClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDir().getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a sub-directory of the application temp.
|
||||
* @param subDir the sub-directory name
|
||||
* @return a sub-directory
|
||||
*/
|
||||
public File getDir(String subDir) {
|
||||
File dir = new File(getDir(), subDir);
|
||||
dir.mkdirs();
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the directory to be used for application specific temp files.
|
||||
* @return the application temp directory
|
||||
*/
|
||||
public File getDir() {
|
||||
if (this.dir == null) {
|
||||
synchronized (this) {
|
||||
byte[] hash = generateHash(this.sourceClass);
|
||||
this.dir = new File(getTempDirectory(), toHexString(hash));
|
||||
this.dir.mkdirs();
|
||||
Assert.state(this.dir.exists(),
|
||||
"Unable to create temp directory " + this.dir);
|
||||
}
|
||||
}
|
||||
return this.dir;
|
||||
}
|
||||
|
||||
private File getTempDirectory() {
|
||||
String property = System.getProperty("java.io.tmpdir");
|
||||
Assert.state(StringUtils.hasLength(property), "No 'java.io.tmpdir' property set");
|
||||
File file = new File(property);
|
||||
Assert.state(file.exists(), "Temp directory" + file + " does not exist");
|
||||
Assert.state(file.isDirectory(), "Temp location " + file + " is not a directory");
|
||||
return file;
|
||||
}
|
||||
|
||||
private byte[] generateHash(Class<?> sourceClass) {
|
||||
ApplicationHome home = new ApplicationHome(sourceClass);
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-1");
|
||||
update(digest, home.getSource());
|
||||
update(digest, home.getDir());
|
||||
update(digest, System.getProperty("user.dir"));
|
||||
update(digest, System.getProperty("java.home"));
|
||||
update(digest, System.getProperty("java.class.path"));
|
||||
update(digest, System.getProperty("sun.java.command"));
|
||||
update(digest, System.getProperty("sun.boot.class.path"));
|
||||
return digest.digest();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void update(MessageDigest digest, Object source) {
|
||||
if (source != null) {
|
||||
digest.update(getUpdateSourceBytes(source));
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getUpdateSourceBytes(Object source) {
|
||||
if (source instanceof File) {
|
||||
return getUpdateSourceBytes(((File) source).getAbsolutePath());
|
||||
}
|
||||
return source.toString().getBytes();
|
||||
}
|
||||
|
||||
private String toHexString(byte[] bytes) {
|
||||
char[] hex = new char[bytes.length * 2];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int b = bytes[i] & 0xFF;
|
||||
hex[i * 2] = HEX_CHARS[b >>> 4];
|
||||
hex[i * 2 + 1] = HEX_CHARS[b & 0x0F];
|
||||
}
|
||||
return new String(hex);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.catalina.util.StandardSessionIdGenerator;
|
||||
|
||||
|
||||
class LazySessionIdGenerator extends StandardSessionIdGenerator {
|
||||
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
setState(LifecycleState.STARTING);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.session.ManagerBase;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
public class TomcatContext extends StandardContext {
|
||||
|
||||
private TomcatStarter starter;
|
||||
|
||||
private final boolean overrideLoadOnStart;
|
||||
|
||||
TomcatContext() {
|
||||
this.overrideLoadOnStart = ReflectionUtils
|
||||
.findMethod(StandardContext.class, "loadOnStartup", Container[].class)
|
||||
.getReturnType() == boolean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadOnStartup(Container[] children) {
|
||||
if (this.overrideLoadOnStart) {
|
||||
return true;
|
||||
}
|
||||
return super.loadOnStartup(children);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setManager(Manager manager) {
|
||||
if (manager instanceof ManagerBase) {
|
||||
manager.setSessionIdGenerator(new LazySessionIdGenerator());
|
||||
}
|
||||
super.setManager(manager);
|
||||
}
|
||||
|
||||
public void deferredLoadOnStartup() {
|
||||
// Some older Servlet frameworks (e.g. Struts, BIRT) use the Thread context class
|
||||
// loader to create servlet instances in this phase. If they do that and then try
|
||||
// to initialize them later the class loader may have changed, so wrap the call to
|
||||
// loadOnStartup in what we think its going to be the main webapp classloader at
|
||||
// runtime.
|
||||
ClassLoader classLoader = getLoader().getClassLoader();
|
||||
ClassLoader existingLoader = null;
|
||||
if (classLoader != null) {
|
||||
existingLoader = ClassUtils.overrideThreadContextClassLoader(classLoader);
|
||||
}
|
||||
|
||||
if (this.overrideLoadOnStart) {
|
||||
// Earlier versions of Tomcat used a version that returned void. If that
|
||||
// version is used our overridden loadOnStart method won't have been called
|
||||
// and the original will have already run.
|
||||
super.loadOnStartup(findChildren());
|
||||
}
|
||||
if (existingLoader != null) {
|
||||
ClassUtils.overrideThreadContextClassLoader(existingLoader);
|
||||
}
|
||||
}
|
||||
|
||||
public void setStarter(TomcatStarter starter) {
|
||||
this.starter = starter;
|
||||
}
|
||||
|
||||
public TomcatStarter getStarter() {
|
||||
return this.starter;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.WebResourceRoot.ResourceSetType;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class TomcatResources {
|
||||
|
||||
private final Context context;
|
||||
|
||||
TomcatResources(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
void addResourceJars(List<URL> resourceJarUrls) {
|
||||
for (URL url : resourceJarUrls) {
|
||||
String file = url.getFile();
|
||||
if (file.endsWith(".jar") || file.endsWith(".jar!/")) {
|
||||
String jar = url.toString();
|
||||
if (!jar.startsWith("jar:")) {
|
||||
// A jar file in the file system. Convert to Jar URL.
|
||||
jar = "jar:" + jar + "!/";
|
||||
}
|
||||
addJar(jar);
|
||||
}
|
||||
else {
|
||||
addDir(file, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final Context getContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to add a JAR to the resources.
|
||||
* @param jar the URL spec for the jar
|
||||
*/
|
||||
protected abstract void addJar(String jar);
|
||||
|
||||
/**
|
||||
* Called to add a dir to the resource.
|
||||
* @param dir the dir
|
||||
* @param url the URL
|
||||
*/
|
||||
protected abstract void addDir(String dir, URL url);
|
||||
|
||||
/**
|
||||
* Return a {@link TomcatResources} instance for the currently running Tomcat version.
|
||||
* @param context the tomcat context
|
||||
* @return a {@link TomcatResources} instance.
|
||||
*/
|
||||
public static TomcatResources get(Context context) {
|
||||
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
|
||||
return new Tomcat7Resources(context);
|
||||
}
|
||||
return new Tomcat8Resources(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TomcatResources} for Tomcat 7.
|
||||
*/
|
||||
private static class Tomcat7Resources extends TomcatResources {
|
||||
|
||||
private final Method addResourceJarUrlMethod;
|
||||
|
||||
Tomcat7Resources(Context context) {
|
||||
super(context);
|
||||
this.addResourceJarUrlMethod = ReflectionUtils.findMethod(context.getClass(),
|
||||
"addResourceJarUrl", URL.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addJar(String jar) {
|
||||
URL url = getJarUrl(jar);
|
||||
if (url != null) {
|
||||
try {
|
||||
this.addResourceJarUrlMethod.invoke(getContext(), url);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private URL getJarUrl(String jar) {
|
||||
try {
|
||||
return new URL(jar);
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
// Ignore
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDir(String dir, URL url) {
|
||||
if (getContext() instanceof StandardContext) {
|
||||
try {
|
||||
Class<?> fileDirContextClass = Class
|
||||
.forName("org.apache.naming.resources.FileDirContext");
|
||||
Method setDocBaseMethod = ReflectionUtils
|
||||
.findMethod(fileDirContextClass, "setDocBase", String.class);
|
||||
Object fileDirContext = fileDirContextClass.newInstance();
|
||||
setDocBaseMethod.invoke(fileDirContext, dir);
|
||||
Method addResourcesDirContextMethod = ReflectionUtils.findMethod(
|
||||
StandardContext.class, "addResourcesDirContext",
|
||||
DirContext.class);
|
||||
addResourcesDirContextMethod.invoke(getContext(), fileDirContext);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Tomcat 7 reflection failed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TomcatResources} for Tomcat 8.
|
||||
*/
|
||||
static class Tomcat8Resources extends TomcatResources {
|
||||
|
||||
Tomcat8Resources(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addJar(String jar) {
|
||||
addResourceSet(jar);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDir(String dir, URL url) {
|
||||
addResourceSet(url.toString());
|
||||
}
|
||||
|
||||
private void addResourceSet(String resource) {
|
||||
try {
|
||||
if (isInsideNestedJar(resource)) {
|
||||
// It's a nested jar but we now don't want the suffix because Tomcat
|
||||
// is going to try and locate it as a root URL (not the resource
|
||||
// inside it)
|
||||
resource = resource.substring(0, resource.length() - 2);
|
||||
}
|
||||
URL url = new URL(resource);
|
||||
String path = "/META-INF/resources";
|
||||
getContext().getResources().createWebResourceSet(
|
||||
ResourceSetType.RESOURCE_JAR, "/", url, path);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Ignore (probably not a directory)
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInsideNestedJar(String dir) {
|
||||
return dir.indexOf("!/") < dir.lastIndexOf("!/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package org.nutz.boot.starter.tomcat;
|
||||
|
||||
import org.apache.catalina.loader.WebappClassLoader;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public class TomcatWebappClassLoader extends WebappClassLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TomcatWebappClassLoader.class);
|
||||
|
||||
public TomcatWebappClassLoader() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TomcatWebappClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Class<?> loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
Class<?> result = findExistingLoadedClass(name);
|
||||
result = (result == null ? doLoadClass(name) : result);
|
||||
if (result == null) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return resolveIfNecessary(result, resolve);
|
||||
}
|
||||
|
||||
private Class<?> findExistingLoadedClass(String name) {
|
||||
Class<?> resultClass = findLoadedClass0(name);
|
||||
resultClass = (resultClass == null ? findLoadedClass(name) : resultClass);
|
||||
return resultClass;
|
||||
}
|
||||
|
||||
private Class<?> doLoadClass(String name) throws ClassNotFoundException {
|
||||
checkPackageAccess(name);
|
||||
if ((this.delegate || filter(name, true))) {
|
||||
Class<?> result = loadFromParent(name);
|
||||
return (result == null ? findClassIgnoringNotFound(name) : result);
|
||||
}
|
||||
Class<?> result = findClassIgnoringNotFound(name);
|
||||
return (result == null ? loadFromParent(name) : result);
|
||||
}
|
||||
|
||||
private Class<?> resolveIfNecessary(Class<?> resultClass, boolean resolve) {
|
||||
if (resolve) {
|
||||
resolveClass(resultClass);
|
||||
}
|
||||
return (resultClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addURL(URL url) {
|
||||
// Ignore URLs added by the Tomcat 8 implementation (see gh-919)
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Ignoring request to add " + url + " to the tomcat classloader");
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> loadFromParent(String name) {
|
||||
if (this.parent == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Class.forName(name, false, this.parent);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> findClassIgnoringNotFound(String name) {
|
||||
try {
|
||||
return findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPackageAccess(String name) throws ClassNotFoundException {
|
||||
if (this.securityManager != null && name.lastIndexOf('.') >= 0) {
|
||||
try {
|
||||
this.securityManager
|
||||
.checkPackageAccess(name.substring(0, name.lastIndexOf('.')));
|
||||
}
|
||||
catch (SecurityException ex) {
|
||||
throw new ClassNotFoundException("Security Violation, attempt to use "
|
||||
+ "Restricted Class: " + name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user