zweb/src/main/java/org/zkoss/web/util/resource/ResourceCaches.java

Summary

Maintainability
D
1 day
Test Coverage
/* ResourceCaches.java

    Purpose:
        
    Description:
        
    History:
        Tue Aug 30 18:31:05     2005, Created by tomyeh

Copyright (C) 2005 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
    This program is distributed under LGPL Version 2.1 in the hope that
    it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.web.util.resource;

import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.servlet.ServletContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.lang.SystemException;
import org.zkoss.web.servlet.Servlets;

/**
 * Utilities to load (and parse) the Servlet resource.
 * Notice that {@link ResourceCache} and {@link ResourceLoader}
 * must be used rather than
 * {@link org.zkoss.util.resource.ResourceCache}
 * and {@link org.zkoss.util.resource.Loader}.
 *
 * <p>Usage:
 * <ol>
 * <li>Implements a loader by extending from {@link ResourceLoader}.</li>
 * <li>Creates a resource cache ({@link ResourceCache})
 * by use of the loader in the previous step.</li>
 * <li>Invoke {@link #get} to load the resource.</li>
 * </ol>
 *
 * @author tomyeh
 */
public class ResourceCaches {
    private static final Logger log = LoggerFactory.getLogger(ResourceCaches.class);

    /** Loads, parses and returns the resource of the specified URI,
     * or null if not found. The parser is defined by the loader defined
     * in {@link ResourceCache}.
     *
     * @param cache the resource cache.
     * Note: its loader must extend from {@link ResourceLoader}.
     * @param path the URI path
     * @param extra the extra parameter that will be passed to
     * {@link ResourceLoader#parse(String,File,Object)} and
     * {@link ResourceLoader#parse(String,URL,Object)}
     */
    public static final <V> V get(ResourceCache<V> cache, ServletContext ctx, String path, Object extra) {
        //20050905: Tom Yeh
        //We don't need to handle the default name if user specifies only a dir
        //because it is handled by the container directly
        //And, web  developer has to specify <welcome-file> in web.xml
        URL url = null;
        if (path == null || path.length() == 0)
            path = "/";
        else if (path.charAt(0) != '/') {
            if (path.indexOf("://") > 0) {
                try {
                    url = new URL(path);
                } catch (java.net.MalformedURLException ex) {
                    throw new SystemException(ex);
                }
            } else
                path = '/' + path;
        }

        if (url == null) {
            if (path.startsWith("/~")) {
                final ServletContext ctx0 = ctx;
                final String path0 = path;
                final int j = path.indexOf('/', 2);
                final String ctxpath;
                if (j >= 0) {
                    ctxpath = "/" + path.substring(2, j);
                    path = path.substring(j);
                } else {
                    ctxpath = "/" + path.substring(2);
                    path = "/";
                }

                final ExtendletContext extctx = Servlets.getExtendletContext(ctx, ctxpath.substring(1));
                if (extctx != null) {
                    url = extctx.getResource(path);
                    //                    if (log.isDebugEnabled()) log.debug("Resolving "+path0+" to "+url);
                    if (url == null)
                        return null;
                    try {
                        return cache.get(new ResourceInfo(path, url, extra));
                    } catch (Throwable ex) {
                        final IOException ioex = getIOException(ex);
                        if (ioex == null)
                            throw SystemException.Aide.wrap(ex);
                        log.warn("Unable to load " + url, ioex);
                    }
                    return null;
                }

                ctx = ctx.getContext(ctxpath);
                if (ctx == null) { //failed
                    //                    if (log.isDebugEnabled()) log.debug("Context not found: "+ctxpath);
                    ctx = ctx0;
                    path = path0; //restore
                }
            }

            final String flnm = ctx.getRealPath(path);
            if (flnm != null) {
                try {
                    return cache.get(new ResourceInfo(path, new File(flnm), extra));
                    //it is loader's job to check the existence
                } catch (Throwable ex) {
                    final IOException ioex = getIOException(ex);
                    if (ioex == null)
                        throw SystemException.Aide.wrap(ex);
                    log.warn("Unable to load " + flnm, ioex);
                }
                return null;
            }
        }

        //try url because some server uses JAR format
        try {
            if (url == null)
                url = ctx.getResource(path);
            if (url != null)
                return cache.get(new ResourceInfo(path, url, extra));
        } catch (Throwable ex) {
            final IOException ioex = getIOException(ex);
            if (ioex == null)
                throw SystemException.Aide.wrap(ex);
            log.warn("Unable to load " + path, ioex);
        }
        return null;
    }

    //don't eat exceptions other than IOException
    private static IOException getIOException(Throwable ex) {
        for (; ex != null; ex = ex.getCause())
            if (ex instanceof IOException)
                return (IOException) ex;
        return null;
    }
}