All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.velocity.tools.view.WebappResourceLoader Maven / Gradle / Ivy

The newest version!
package org.apache.velocity.tools.view;

/*
 * 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.File;
import java.io.InputStream;
import java.io.Reader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import javax.servlet.ServletContext;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.resource.Resource;
import org.apache.velocity.runtime.resource.loader.ResourceLoader;
import org.apache.velocity.util.ExtProperties;

/**
 * Resource loader that uses the ServletContext of a webapp to
 * load Velocity templates.  (it's much easier to use with servlets than
 * the standard FileResourceLoader, in particular the use of war files
 * is transparent).
 *
 * The default search path is '/' (relative to the webapp root), but
 * you can change this behaviour by specifying one or more paths
 * by mean of as many webapp.resource.loader.path properties as needed
 * in the velocity.properties file.
 *
 * All paths must be relative to the root of the webapp.
 *
 * To enable caching and cache refreshing the webapp.resource.loader.cache and
 * webapp.resource.loader.modificationCheckInterval properties need to be
 * set in the velocity.properties file ... auto-reloading of global macros
 * requires the webapp.resource.loader.cache property to be set to 'false'.
 *
 * @author Geir Magnusson Jr.
 * @author Nathan Bubna
 * @author Claude Brisson
 * @version $Id$  */

public class WebappResourceLoader extends ResourceLoader
{
    /** The root paths for templates (relative to webapp's root). */
    protected String[] paths = null;
    protected HashMap templatePaths = null;
    protected ServletContext servletContext = null;


    /**
     *  This is abstract in the base class, so we need it.
     *  
* NOTE: this expects that the ServletContext has already * been placed in the runtime's application attributes * under its full class name (i.e. "javax.servlet.ServletContext"). * * @param configuration the {@link ExtProperties} associated with * this resource loader. */ public void init(ExtProperties configuration) { log.trace("WebappResourceLoader: initialization starting."); /* get configured paths */ paths = configuration.getStringArray("path"); if (paths == null || paths.length == 0) { paths = new String[1]; paths[0] = "/"; } else { /* make sure the paths end with a '/' */ for (int i=0; i < paths.length; i++) { if (!paths[i].endsWith("/")) { paths[i] += '/'; } log.info("WebappResourceLoader: added template path - '{}'", paths[i]); } } /* get the ServletContext */ Object obj = rsvc.getApplicationAttribute(ServletContext.class.getName()); if (obj instanceof ServletContext) { servletContext = (ServletContext)obj; } else { log.error("WebappResourceLoader: unable to retrieve ServletContext"); } /* init the template paths map */ templatePaths = new HashMap(); log.trace("WebappResourceLoader: initialization complete."); } /** * Get Reader so that the Runtime can build a * template with it. * * @param name name of template to get * @param encoding asked encoding * @return InputStream containing the template * @throws ResourceNotFoundException if template not found * in classpath. * @since 2.0 */ public synchronized Reader getResourceReader(String name, String encoding) throws ResourceNotFoundException { Reader result = null; if (name == null || name.length() == 0) { throw new ResourceNotFoundException("WebappResourceLoader: No template name provided"); } /* since the paths always ends in '/', * make sure the name never starts with one */ while (name.startsWith("/")) { name = name.substring(1); } Exception exception = null; for (int i = 0; i < paths.length; i++) { final String path = paths[i] + name; InputStream rawStream = null; try { if (System.getSecurityManager() != null) { rawStream = AccessController.doPrivileged( new PrivilegedAction() { @Override public InputStream run() { return servletContext.getResourceAsStream(path); } }); } else { rawStream = servletContext.getResourceAsStream(path); } if (rawStream != null) { result = buildReader(rawStream, encoding); } /* save the path and exit the loop if we found the template */ if (result != null) { templatePaths.put(name, paths[i]); break; } } catch (NullPointerException npe) { /* no servletContext was set, whine about it! */ throw npe; } catch (Exception e) { if (rawStream != null) { try { rawStream.close(); } catch(Exception ee) {} } /* only save the first one for later throwing */ if (exception == null) { log.debug("WebappResourceLoader: Could not load {}", path, e); exception = e; } } } /* if we never found the template */ if (result == null) { String msg = "WebappResourceLoader: Resource '" + name + "' not found."; /* convert to a general Velocity ResourceNotFoundException */ if (exception == null) { throw new ResourceNotFoundException(msg); } else { msg += " Due to: " + exception; throw new ResourceNotFoundException(msg, exception); } } return result; } private File getCachedFile(String rootPath, String fileName) { // we do this when we cache a resource, // so do it again to ensure a match while (fileName.startsWith("/")) { fileName = fileName.substring(1); } String savedPath = (String)templatePaths.get(fileName); return new File(rootPath + savedPath, fileName); } /** * Checks to see if a resource has been deleted, moved or modified. * * @param resource Resource The resource to check for modification * @return boolean True if the resource has been modified */ public boolean isSourceModified(Resource resource) { String rootPath = servletContext.getRealPath("/"); if (rootPath == null) { // rootPath is null if the servlet container cannot translate the // virtual path to a real path for any reason (such as when the // content is being made available from a .war archive) return false; } // first, try getting the previously found file String fileName = resource.getName(); File cachedFile = getCachedFile(rootPath, fileName); if (!cachedFile.exists()) { /* then the source has been moved and/or deleted */ return true; } /* check to see if the file can now be found elsewhere * before it is found in the previously saved path */ File currentFile = null; for (int i = 0; i < paths.length; i++) { currentFile = new File(rootPath + paths[i], fileName); if (currentFile.canRead()) { /* stop at the first resource found * (just like in getResourceReader()) */ break; } } /* if the current is the cached and it is readable */ if (cachedFile.equals(currentFile) && cachedFile.canRead()) { /* then (and only then) do we compare the last modified values */ return (cachedFile.lastModified() != resource.getLastModified()); } else { /* we found a new file for the resource * or the resource is no longer readable. */ return true; } } /** * Checks to see when a resource was last modified * * @param resource Resource the resource to check * @return long The time when the resource was last modified or 0 if the file can't be read */ public long getLastModified(Resource resource) { String rootPath = servletContext.getRealPath("/"); if (rootPath == null) { // rootPath is null if the servlet container cannot translate the // virtual path to a real path for any reason (such as when the // content is being made available from a .war archive) return 0; } File cachedFile = getCachedFile(rootPath, resource.getName()); if (cachedFile.canRead()) { return cachedFile.lastModified(); } else { return 0; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy