com.threewks.thundr.view.velocity.ServletContextResourceLoader.java Source code

Java tutorial

Introduction

Here is the source code for com.threewks.thundr.view.velocity.ServletContextResourceLoader.java

Source

/*
 * This file is a component of thundr, a software library from 3wks.
 * Read more: http://3wks.github.io/thundr/
 * Copyright (C) 2014 3wks, <thundr@3wks.com.au>
 *
 * 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.
 */
package com.threewks.thundr.view.velocity;

import java.io.File;
import java.io.InputStream;

import javax.servlet.ServletContext;

import org.apache.commons.collections.ExtendedProperties;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.resource.Resource;
import org.apache.velocity.runtime.resource.loader.ResourceLoader;

import com.atomicleopard.expressive.Cast;
import com.threewks.thundr.exception.BaseException;

/**
 * Resource loader that uses the ServletContext of a webapp to
 * load Velocity templates.
 * 
 * 
 * This is adapted from the WebappResourceLoader found in velocity tools.
 */
public class ServletContextResourceLoader extends ResourceLoader {
    protected ServletContext servletContext = null;

    /**
     * This is abstract in the base class, so we need it. <br>
     * 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 ExtendedProperties} associated with
     *            this resource loader.
     */
    @Override
    public void init(ExtendedProperties configuration) {
        /* get the ServletContext */
        Object obj = rsvc.getApplicationAttribute(ServletContext.class.getName());
        servletContext = Cast.as(obj, ServletContext.class);
        if (servletContext == null) {
            throw new BaseException(
                    "Unable to use the %s, the %s must be in the velocity extended properties under the key '%s'",
                    this.getClass().getSimpleName(), ServletContext.class.getSimpleName(),
                    ServletContext.class.getName());
        }

    }

    /**
     * Get an InputStream so that the Runtime can build a
     * template with it.
     * 
     * @param name name of template to get
     * @return InputStream containing the template
     * @throws ResourceNotFoundException if template not found
     *             in classpath.
     */
    @Override
    public synchronized InputStream getResourceStream(String name) throws ResourceNotFoundException {
        if (StringUtils.isBlank(name)) {
            throw new ResourceNotFoundException("No template name provided");
        }
        InputStream result = null;
        try {
            result = servletContext.getResourceAsStream(name);
        } catch (Exception e) {
            throw new ResourceNotFoundException("Resource '" + name + "' not found: " + e.getMessage(), e);
        }
        if (result == null) {
            throw new ResourceNotFoundException("Resource '" + name + "' not found");
        }
        return result;
    }

    private File getCachedFile(String rootPath, String fileName) {
        return new File(rootPath, 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
     */
    @Override
    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 = new File(rootPath, fileName);

        /* 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
     */
    @Override
    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;
        }
    }
}