bboss.org.apache.velocity.runtime.resource.loader.JarResourceLoader.java Source code

Java tutorial

Introduction

Here is the source code for bboss.org.apache.velocity.runtime.resource.loader.JarResourceLoader.java

Source

package bboss.org.apache.velocity.runtime.resource.loader;

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

import java.io.InputStream;

import java.util.Hashtable;
import java.util.Vector;
import java.util.Map;
import java.util.HashMap;

import bboss.org.apache.velocity.util.StringUtils;
import bboss.org.apache.velocity.runtime.resource.Resource;
import bboss.org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.commons.collections.ExtendedProperties;

/**
 * <p>
 * ResourceLoader to load templates from multiple Jar files.
 * </p>
 * <p>
 * The configuration of the JarResourceLoader is straightforward -
 * You simply add the JarResourceLoader to the configuration via
 * </p>
 * <p><pre>
 *    resource.loader = jar
 *    jar.resource.loader.class = bboss.org.apache.velocity.runtime.resource.loader.JarResourceLoader
 *    jar.resource.loader.path = list of JAR &lt;URL&gt;s
 * </pre></p>
 *
 * <p> So for example, if you had a jar file on your local filesystem, you could simply do
 *    <pre>
 *    jar.resource.loader.path = jar:file:/opt/myfiles/jar1.jar
 *    </pre>
 * </p>
 * <p> Note that jar specification for the <code>.path</code> configuration property
 * conforms to the same rules for the java.net.JarUrlConnection class.
 * </p>
 *
 * <p> For a working example, see the unit test case,
 *  bboss.org.apache.velocity.test.MultiLoaderTestCase class
 * </p>
 *
 * @author <a href="mailto:mailmur@yahoo.com">Aki Nieminen</a>
 * @author <a href="mailto:daveb@miceda-data.com">Dave Bryson</a>
 * @version $Id: JarResourceLoader.java 691884 2008-09-04 06:46:51Z nbubna $
 */
public class JarResourceLoader extends ResourceLoader {
    /**
     * Maps entries to the parent JAR File
     * Key = the entry *excluding* plain directories
     * Value = the JAR URL
     */
    private Map entryDirectory = new HashMap(559);

    /**
     * Maps JAR URLs to the actual JAR
     * Key = the JAR URL
     * Value = the JAR
     */
    private Map jarfiles = new HashMap(89);

    /**
     * Called by Velocity to initialize the loader
     * @param configuration
     */
    public void init(ExtendedProperties configuration) {
        log.trace("JarResourceLoader : initialization starting.");

        // rest of Velocity engine still use legacy Vector
        // and Hashtable classes. Classes are implicitly
        // synchronized even if we don't need it.
        Vector paths = configuration.getVector("path");
        StringUtils.trimStrings(paths);

        /*
         *  support the old version but deprecate with a log message
         */

        if (paths == null || paths.size() == 0) {
            paths = configuration.getVector("resource.path");
            StringUtils.trimStrings(paths);

            if (paths != null && paths.size() > 0) {
                log.debug("JarResourceLoader : you are using a deprecated configuration"
                        + " property for the JarResourceLoader -> '<name>.resource.loader.resource.path'."
                        + " Please change to the conventional '<name>.resource.loader.path'.");
            }
        }

        if (paths != null) {
            log.debug("JarResourceLoader # of paths : " + paths.size());

            for (int i = 0; i < paths.size(); i++) {
                loadJar((String) paths.get(i));
            }
        }

        log.trace("JarResourceLoader : initialization complete.");
    }

    private void loadJar(String path) {
        if (log.isDebugEnabled()) {
            log.debug("JarResourceLoader : trying to load \"" + path + "\"");
        }

        // Check path information
        if (path == null) {
            String msg = "JarResourceLoader : can not load JAR - JAR path is null";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        if (!path.startsWith("jar:")) {
            String msg = "JarResourceLoader : JAR path must start with jar: -> see java.net.JarURLConnection for information";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        if (path.indexOf("!/") < 0) {
            path += "!/";
        }

        // Close the jar if it's already open
        // this is useful for a reload
        closeJar(path);

        // Create a new JarHolder
        JarHolder temp = new JarHolder(rsvc, path);
        // Add it's entries to the entryCollection
        addEntries(temp.getEntries());
        // Add it to the Jar table
        jarfiles.put(temp.getUrlPath(), temp);
    }

    /**
     * Closes a Jar file and set its URLConnection
     * to null.
     */
    private void closeJar(String path) {
        if (jarfiles.containsKey(path)) {
            JarHolder theJar = (JarHolder) jarfiles.get(path);
            theJar.close();
        }
    }

    /**
     * Copy all the entries into the entryDirectory
     * It will overwrite any duplicate keys.
     */
    private void addEntries(Hashtable entries) {
        entryDirectory.putAll(entries);
    }

    /**
     * Get an InputStream so that the Runtime can build a
     * template with it.
     *
     * @param source name of template to get
     * @return InputStream containing the template
     * @throws ResourceNotFoundException if template not found
     *         in the file template path.
     */
    public InputStream getResourceStream(String source) throws ResourceNotFoundException {
        InputStream results = null;

        if (org.apache.commons.lang.StringUtils.isEmpty(source)) {
            throw new ResourceNotFoundException("Need to have a resource!");
        }

        String normalizedPath = StringUtils.normalizePath(source);

        if (normalizedPath == null || normalizedPath.length() == 0) {
            String msg = "JAR resource error : argument " + normalizedPath
                    + " contains .. and may be trying to access " + "content outside of template root.  Rejected.";

            log.error("JarResourceLoader : " + msg);

            throw new ResourceNotFoundException(msg);
        }

        /*
         *  if a / leads off, then just nip that :)
         */
        if (normalizedPath.startsWith("/")) {
            normalizedPath = normalizedPath.substring(1);
        }

        if (entryDirectory.containsKey(normalizedPath)) {
            String jarurl = (String) entryDirectory.get(normalizedPath);

            if (jarfiles.containsKey(jarurl)) {
                JarHolder holder = (JarHolder) jarfiles.get(jarurl);
                results = holder.getResource(normalizedPath);
                return results;
            }
        }

        throw new ResourceNotFoundException("JarResourceLoader Error: cannot find resource " + source);

    }

    // TODO: SHOULD BE DELEGATED TO THE JARHOLDER

    /**
     * @see bboss.org.apache.velocity.runtime.resource.loader.ResourceLoader#isSourceModified(bboss.org.apache.velocity.runtime.resource.Resource)
     */
    public boolean isSourceModified(Resource resource) {
        return true;
    }

    /**
     * @see bboss.org.apache.velocity.runtime.resource.loader.ResourceLoader#getLastModified(bboss.org.apache.velocity.runtime.resource.Resource)
     */
    public long getLastModified(Resource resource) {
        return 0;
    }
}