Package org.apache.catalina.webresources

Source Code of org.apache.catalina.webresources.StandardRoot$BaseLocation

/*
* 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.webresources;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.WebResource;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.WebResourceSet;
import org.apache.catalina.util.LifecycleMBeanBase;
import org.apache.tomcat.util.res.StringManager;

/**
* <p>
* Provides the resources implementation for a web application. The
* {@link org.apache.catalina.Lifecycle} of this class should be aligned with
* that of the associated {@link Context}.
* </p><p>
* This implementation assumes that the base attribute supplied to {@link
* StandardRoot#createWebResourceSet(
* org.apache.catalina.WebResourceRoot.ResourceSetType, String, String, String,
* String)} represents the absolute path to a file.
* </p>
*/
public class StandardRoot extends LifecycleMBeanBase
        implements WebResourceRoot {

    protected static final StringManager sm =
            StringManager.getManager(Constants.Package);

    private Context context;
    private boolean allowLinking = false;
    private ArrayList<WebResourceSet> preResources = new ArrayList<>();
    private WebResourceSet main;
    private ArrayList<WebResourceSet> jarResources = new ArrayList<>();
    private ArrayList<WebResourceSet> postResources = new ArrayList<>();

    private Cache cache = new Cache(this);
    private boolean cachingAllowed = true;

    // Constructs to make iteration over all WebResourceSets simpler
    private ArrayList<WebResourceSet> mainResources = new ArrayList<>();
    private ArrayList<ArrayList<WebResourceSet>> allResources =
            new ArrayList<>();
    {
        allResources.add(preResources);
        allResources.add(mainResources);
        allResources.add(jarResources);
        allResources.add(postResources);
    }


    /**
     * Creates a new standard implementation of {@link WebResourceRoot}. A no
     * argument constructor is required for this to work with the digester.
     * {@link #setContext(Context)} must be called before this component is
     * initialized.
     */
    public StandardRoot() {
        // NO-OP
    }

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

    @Override
    public String[] list(String path) {
        checkState();

        // Set because we don't want duplicates
        HashSet<String> result = new HashSet<>();
        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                String[] entries = webResourceSet.list(path);
                for (String entry : entries) {
                    result.add(entry);
                }
            }
        }
        return result.toArray(new String[result.size()]);
    }


    @Override
    public Set<String> listWebAppPaths(String path) {
        checkState();

        // Set because we don't want duplicates
        HashSet<String> result = new HashSet<>();
        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                result.addAll(webResourceSet.listWebAppPaths(path));
            }
        }
        if (result.size() == 0) {
            return null;
        }
        return result;
    }

    @Override
    public boolean mkdir(String path) {
        checkState();

        if (preResourceExists(path)) {
            return false;
        }

        return main.mkdir(path);
    }

    @Override
    public boolean write(String path, InputStream is, boolean overwrite) {
        checkState();

        if (!overwrite && preResourceExists(path)) {
            return false;
        }

        return main.write(path, is, overwrite);
    }

    private boolean preResourceExists(String path) {
        for (WebResourceSet webResourceSet : preResources) {
            WebResource webResource = webResourceSet.getResource(path);
            if (webResource.exists()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public WebResource getResource(String path) {
        if (isCachingAllowed()) {
            return cache.getResource(path);
        } else {
            return getResourceInternal(path);
        }
    }

    protected WebResource getResourceInternal(String path) {
        checkState();

        WebResource result = null;
        WebResource virtual = null;
        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                result = webResourceSet.getResource(path);
                if (result.exists()) {
                    return result;
                }
                if (virtual == null && result.isVirtual()) {
                    virtual = result;
                }
            }
        }

        // Use the first virtual result if no real result was found
        if (virtual != null) {
            return virtual;
        }

        // Default is empty resource in main resources
        return new EmptyResource(this, path);
    }

    @Override
    public WebResource[] getResources(String path) {
        checkState();

        ArrayList<WebResource> result = new ArrayList<>();
        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                WebResource webResource = webResourceSet.getResource(path);
                if (webResource.exists()) {
                    result.add(webResource);
                }
            }
        }

        if (result.size() == 0) {
            result.add(main.getResource(path));
        }

        return result.toArray(new WebResource[result.size()]);
    }

    @Override
    public WebResource[] listResources(String path) {
        checkState();

        String[] resources = list(path);
        WebResource[] result = new WebResource[resources.length];
        for (int i = 0; i < resources.length; i++) {
            if (path.charAt(path.length() - 1) == '/') {
                result[i] = getResource(path + resources[i]);
            } else {
                result[i] = getResource(path + '/' + resources[i]);
            }
        }
        return result;
    }


    @Override
    public void createWebResourceSet(ResourceSetType type, String webAppMount,
            URL url, String internalPath) {
        BaseLocation baseLocation = new BaseLocation(url);
        createWebResourceSet(type, webAppMount, baseLocation.getBasePath(),
                baseLocation.getArchivePath(), internalPath);
    }

    @Override
    public void createWebResourceSet(ResourceSetType type, String webAppMount,
            String base, String archivePath, String internalPath) {
        ArrayList<WebResourceSet> resourceList;
        WebResourceSet resourceSet;

        switch (type) {
            case PRE:
                resourceList = preResources;
                break;
            case RESOURCE_JAR:
                resourceList = jarResources;
                break;
            case POST:
                resourceList = postResources;
                break;
            default:
                throw new IllegalArgumentException(
                        sm.getString("standardRoot.createUnknownType", type));
        }

        // This implementation assumes that the base for all resources will be a
        // file.
        File file = new File(base);

        if (file.isFile()) {
            if (archivePath != null) {
                // Must be a JAR nested inside a WAR if archivePath is non-null
                resourceSet = new JarWarResourceSet(this, webAppMount, base,
                        archivePath, internalPath);
            } else if (file.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar")) {
                resourceSet = new JarResourceSet(this, webAppMount, base,
                        internalPath);
            } else {
                resourceSet = new FileResourceSet(this, webAppMount, base,
                        internalPath);
            }
        } else if (file.isDirectory()) {
            resourceSet =
                    new DirResourceSet(this, webAppMount, base, internalPath);
        } else {
            throw new IllegalArgumentException(
                    sm.getString("standardRoot.createInvalidFile", file));
        }

        resourceList.add(resourceSet);
    }

    @Override
    public void addPreResources(WebResourceSet webResourceSet) {
        webResourceSet.setRoot(this);
        preResources.add(webResourceSet);
    }

    @Override
    public WebResourceSet[] getPreResources() {
        return preResources.toArray(new WebResourceSet[0]);
    }

    @Override
    public void addJarResources(WebResourceSet webResourceSet) {
        webResourceSet.setRoot(this);
        jarResources.add(webResourceSet);
    }

    @Override
    public WebResourceSet[] getJarResources() {
        return jarResources.toArray(new WebResourceSet[0]);
    }

    @Override
    public void addPostResources(WebResourceSet webResourceSet) {
        webResourceSet.setRoot(this);
        postResources.add(webResourceSet);
    }

    @Override
    public WebResourceSet[] getPostResources() {
        return postResources.toArray(new WebResourceSet[0]);
    }

    @Override
    public void setAllowLinking(boolean allowLinking) {
        this.allowLinking = allowLinking;
    }

    @Override
    public boolean getAllowLinking() {
        return allowLinking;
    }

    @Override
    public void setCachingAllowed(boolean cachingAllowed) {
        this.cachingAllowed = cachingAllowed;
    }

    @Override
    public boolean isCachingAllowed() {
        return cachingAllowed;
    }

    @Override
    public long getCacheTtl() {
        return cache.getTtl();
    }

    @Override
    public void setCacheTtl(long cacheTtl) {
        cache.setTtl(cacheTtl);
    }

    @Override
    public long getCacheMaxSize() {
        return cache.getMaxSize();
    }

    @Override
    public void setCacheMaxSize(long cacheMaxSize) {
        cache.setMaxSize(cacheMaxSize);
    }

    @Override
    public void setCacheMaxObjectSize(long cacheMaxObjectSize) {
        cache.setMaxObjectSize(cacheMaxObjectSize);
    }

    @Override
    public long getCacheMaxObjectSize() {
        return cache.getMaxObjectSize();
    }

    @Override
    public Context getContext() {
        return context;
    }

    @Override
    public void setContext(Context context) {
        this.context = context;
    }

    private void checkState() {
        if (!getState().isAvailable()) {
            throw new IllegalStateException(
                    sm.getString("standardRoot.checkStateNotStarted"));
        }
    }

    /**
     * For unit testing
     */
    protected void setMainResources(WebResourceSet main) {
        this.main = main;
        mainResources.clear();
        mainResources.add(main);
    }

    @Override
    public void backgroundProcess() {
        cache.backgroundProcess();
    }

    // ----------------------------------------------------------- JMX Lifecycle
    @Override
    protected String getDomainInternal() {
        return context.getDomain();
    }

    @Override
    protected String getObjectNameKeyProperties() {
        StringBuilder keyProperties = new StringBuilder("type=WebResourceRoot");
        keyProperties.append(context.getMBeanKeyProperties());

        return keyProperties.toString();
    }

    // --------------------------------------------------------------- Lifecycle

    @Override
    protected void initInternal() throws LifecycleException {
        super.initInternal();

        // Ensure support for jar:war:file:/ URLs will be available (required
        // for resource JARs in packed WAR files).
        TomcatURLStreamHandlerFactory.register();

        if (context == null) {
            throw new IllegalStateException(
                    sm.getString("standardRoot.noContext"));
        }

        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                webResourceSet.init();
            }
        }
    }

    @Override
    protected void startInternal() throws LifecycleException {
        String docBase = context.getDocBase();

        File f = new File(docBase);
        if (!f.isAbsolute()) {
            f = new File(((Host)context.getParent()).getAppBaseFile(), f.getName());
        }
        if (f.isDirectory()) {
            main = new DirResourceSet(this, "/", f.getAbsolutePath(), "/");
        } else if(f.isFile() && docBase.endsWith(".war")) {
            main = new JarResourceSet(this, "/", f.getAbsolutePath(), "/");
        } else {
            throw new IllegalArgumentException(
                    sm.getString("standardRoot.startInvalidMain",
                            f.getAbsolutePath()));
        }

        mainResources.clear();
        mainResources.add(main);

        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                webResourceSet.start();
            }
        }

        setState(LifecycleState.STARTING);
    }

    @Override
    protected void stopInternal() throws LifecycleException {
        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                webResourceSet.stop();
            }
        }

        if (main != null) {
            main.destroy();
        }
        mainResources.clear();

        for (WebResourceSet webResourceSet : jarResources) {
            webResourceSet.destroy();
        }
        jarResources.clear();

        cache.clear();

        setState(LifecycleState.STOPPING);
    }

    @Override
    protected void destroyInternal() throws LifecycleException {
        for (ArrayList<WebResourceSet> list : allResources) {
            for (WebResourceSet webResourceSet : list) {
                webResourceSet.destroy();
            }
        }

        super.destroyInternal();
    }


    // Unit tests need to access this class
    static class BaseLocation {

        private final String basePath;
        private final String archivePath;

        BaseLocation(URL url) {
            File f = null;

            if ("jar".equals(url.getProtocol())) {
                String jarUrl = url.toString();
                int endOfFileUrl = jarUrl.indexOf("!/");
                String fileUrl = jarUrl.substring(4, endOfFileUrl);
                try {
                    f = new File(new URL(fileUrl).toURI());
                } catch (MalformedURLException | URISyntaxException e) {
                    throw new IllegalArgumentException(e);
                }
                int startOfArchivePath = endOfFileUrl + 2;
                if (jarUrl.length() >  startOfArchivePath) {
                    archivePath = jarUrl.substring(startOfArchivePath);
                } else {
                    archivePath = null;
                }
            } else if ("file".equals(url.getProtocol())){
                try {
                    f = new File(url.toURI());
                } catch (URISyntaxException e) {
                    throw new IllegalArgumentException(e);
                }
                archivePath = null;
            } else {
                throw new IllegalArgumentException(sm.getString(
                        "standardRoot.unsupportedProtocol", url.getProtocol()));
            }

            basePath = f.getAbsolutePath();
        }


        public String getBasePath() {
            return basePath;
        }


        public String getArchivePath() {
            return archivePath;
        }
    }
}
TOP

Related Classes of org.apache.catalina.webresources.StandardRoot$BaseLocation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.