org.codebuilder.template.TemplateReader.java Source code

Java tutorial

Introduction

Here is the source code for org.codebuilder.template.TemplateReader.java

Source

package org.codebuilder.template;

/*
 * Copyright 2001,2004 The Apache Software Foundation.
 *
 * 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.
 */

import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;

import java.util.Hashtable;
import java.util.Vector;

import org.apache.velocity.util.StringUtils;

import org.apache.velocity.runtime.resource.Resource;

import org.apache.velocity.exception.ResourceNotFoundException;

import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.runtime.resource.loader.ResourceLoader;

/**
 * A loader for templates stored on the file system either by
 * relative or absolute path.
 *
 * @author <a href="mailto:jvanzyl@apache.org"></a>
*  @author <a href="mailto:dskolovos@hotmail.com">Dimitrios Kolovos</a> based on
*  code of Jason van Zyl
 * @version $Id: AbsoluteFileResourceLoader.java,v 1.0 2004/03/03 23:23:02
 */
public class TemplateReader extends ResourceLoader {
    /**
     * The paths to search for templates.
     */
    private Vector paths = null;

    /**
     * Used to map the path that a template was found on
     * so that we can properly check the modification
     * times of the files.
     */
    private Hashtable templatePaths = new Hashtable();

    public void init(ExtendedProperties configuration) {
        rsvc.info("FileResourceLoader : initialization starting.");

        paths = configuration.getVector("path");

        /*
         *  lets tell people what paths we will be using
         */

        int sz = paths.size();

        for (int i = 0; i < sz; i++) {
            rsvc.info("FileResourceLoader : adding path '" + (String) paths.get(i) + "'");
        }

        rsvc.info("FileResourceLoader : initialization complete.");
    }

    /**
     * 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 the file template path.
     */
    public synchronized InputStream getResourceStream(String templateName) throws ResourceNotFoundException {
        /*
         * Make sure we have a valid templateName.
         */
        if (templateName == null || templateName.length() == 0) {
            /*
             * If we don't get a properly formed templateName then
             * there's not much we can do. So we'll forget about
             * trying to search any more paths for the template.
             */
            throw new ResourceNotFoundException("Need to specify a file name or file path!");
        }

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

            rsvc.error("FileResourceLoader : " + msg);

            throw new ResourceNotFoundException(msg);
        }

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

        int size = paths.size();
        for (int i = 0; i < size; i++) {
            String path = (String) paths.get(i);
            InputStream inputStream = findTemplate(path, template);

            if (inputStream != null) {
                /*
                 * Store the path that this template came
                 * from so that we can check its modification
                 * time.
                 */

                templatePaths.put(templateName, path);
                return inputStream;
            }
        }

        /*
         * We have now searched all the paths for
         * templates and we didn't find anything so
         * throw an exception.
         */
        String msg = "FileResourceLoader Error: cannot find resource " + template;

        throw new ResourceNotFoundException(msg);
    }

    /**
     * Try to find a template given a normalized path.
     *
     * @param String a normalized path
     * @return InputStream input stream that will be parsed
     *
     */
    private InputStream findTemplate(String path, String template) {
        try {
            File file = new File(path, template);

            // ---------------------
            // Based on the original FileResourceLoader
            // Modified in order to accept absolute file
            // names as well. If the file is not found
            // using the relative paths mechanism, try to
            // find it by using its full name
            // ---------------------

            if (!file.canRead()) {
                file = new File(template);
            }

            // ---------------------
            // End of modification
            // ---------------------

            if (file.canRead()) {
                return new BufferedInputStream(new FileInputStream(file.getAbsolutePath()));
            } else {
                return null;
            }
        } catch (FileNotFoundException fnfe) {
            /*
             *  log and convert to a general Velocity ResourceNotFoundException
             */
            return null;
        }
    }

    /**
     * How to keep track of all the modified times
     * across the paths.  Note that a file might have
     * appeared in a directory which is earlier in the
     * path; so we should search the path and see if
     * the file we find that way is the same as the one
     * that we have cached.
     */
    public boolean isSourceModified(Resource resource) {
        /*
         * we assume that the file needs to be reloaded;
         * if we find the original file and it's unchanged,
         * then we'll flip this.
         */
        boolean modified = true;

        String fileName = resource.getName();
        String path = (String) templatePaths.get(fileName);
        File currentFile = null;

        for (int i = 0; currentFile == null && i < paths.size(); i++) {
            String testPath = (String) paths.get(i);
            File testFile = new File(testPath, fileName);
            if (testFile.canRead()) {
                currentFile = testFile;
            }
        }
        File file = new File(path, fileName);
        if (currentFile == null || !file.exists()) {
            /*
             * noop: if the file is missing now (either the cached
             * file is gone, or the file can no longer be found)
             * then we leave modified alone (it's set to true); a
             * reload attempt will be done, which will either use
             * a new template or fail with an appropriate message
             * about how the file couldn't be found.
             */
        } else if (currentFile.equals(file) && file.canRead()) {
            /*
             * if only if currentFile is the same as file and
             * file.lastModified() is the same as
             * resource.getLastModified(), then we should use the
             * cached version.
             */
            modified = (file.lastModified() != resource.getLastModified());
        }

        /*
         * rsvc.debug("isSourceModified for " + fileName + ": " + modified);
         */
        return modified;
    }

    public long getLastModified(Resource resource) {
        String path = (String) templatePaths.get(resource.getName());
        File file = new File(path, resource.getName());

        if (file.canRead()) {
            return file.lastModified();
        } else {
            return 0;
        }
    }
}