demo.tomcat.TomcatResources.java Source code

Java tutorial

Introduction

Here is the source code for demo.tomcat.TomcatResources.java

Source

package demo.tomcat;

/*
 * Copyright 2012-2014 the original author or authors.
 *
 * Licensed 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.
 */

import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import javax.naming.directory.DirContext;
import javax.servlet.ServletContext;

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;

/**
 * Abstraction to add resources that works with both Tomcat 8 and 7.
 *
 * @author Dave Syer
 * @author Phillip Webb
 */
public abstract class TomcatResources {

    private final Context context;

    public TomcatResources(Context context) {
        this.context = context;
    }

    /**
     * Add resources from the classpath
     */
    public void addClasspathResources() {
        ClassLoader loader = getClass().getClassLoader();
        if (loader instanceof URLClassLoader) {
            for (URL url : ((URLClassLoader) loader).getURLs()) {
                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 if (url.toString().startsWith("file:")) {
                    String dir = url.toString().substring("file:".length());
                    if (new File(dir).isDirectory()) {
                        addDir(dir, 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;

        public Tomcat7Resources(Context context) {
            super(context);
            this.addResourceJarUrlMethod = ReflectionUtils.findMethod(context.getClass(), "addResourceJarUrl",
                    URL.class);
        }

        @Override
        protected void addJar(String jar) {
            URL url = getJarUlr(jar);
            if (url != null) {
                try {
                    this.addResourceJarUrlMethod.invoke(getContext(), url);
                } catch (Exception ex) {
                    throw new IllegalStateException(ex);
                }
            }
        }

        private URL getJarUlr(String jar) {
            try {
                return new URL(jar);
            } catch (MalformedURLException ex) {
                // Ignore
                return null;
            }
        }

        @Override
        protected void addDir(String dir, URL url) {
            if (getContext() instanceof ServletContext) {
                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 {

        public 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("!/");
        }

    }

}