>Velocity version?

The latest version ie 2.0.

>When you say you "shut down the container (tomcat)", >can you be more
specific? Do you bounce the >application, or do you >terminate Tomcat and
the JVM, >etc.?

Terminate tomcat shutdown.sh and then restart it.

>Did you write your own WebappResourceLoader (and if >so, why)?

Its a bit application so I do have my own version.

I did read on a list that it was an issue.  Think Nathan
answered the post???

Maybe I have missed something in the code?


public class WebappResourceLoader extends ResourceLoader {

    private static Log log = LogFactory.getLog(WebappResourceLoader.class);

    // The root paths for templates (relative to webapp's root).
    protected String[] paths = null;
    protected HashMap<String, String> 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 configuration
     */
    @Override
    public void init(ExtProperties configuration) {

        if (log.isDebugEnabled())
            log.debug("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] += "/";
                }
                if (log.isDebugEnabled())
                    log.debug("WebappResourceLoader: added template path -
'"
                            + paths[i] + "'");
            }
        }

        // Try out default
        servletContext = EventsContext.getServletContext();

        // get the ServletContext
        if (servletContext == null) {
            Object obj = rsvc
                    .getApplicationAttribute(ServletContext.class.getName()
);
            if (obj instanceof ServletContext) {
                servletContext = (ServletContext) obj;
            } else {
                log.error(
                        "WebappResourceLoader: unable to retrieve
ServletContext");
            }
        }

        if (log.isDebugEnabled()) {
            for (int i = 0; i < paths.length; i++) {
                log.debug("Servlet Context = "
                        + servletContext.getRealPath(paths[i]));
            }
        }

        // init the template paths map
        templatePaths = new HashMap<String, String>();

        if (log.isDebugEnabled())
            log.debug("WebappResourceLoader: initialization complete.");
    }

    /**
     * Get an InputStream so that the Runtime can build a template with it.
     *
     * @param name
     *            name of template to get
     * @param encoding
     *            the encoding
     *
     * @return InputStream containing the template
     *
     * @throws ResourceNotFoundException
     *             if template not found in classpath.
     */
    @Override
    public Reader getResourceReader(String name, String encoding)
            throws ResourceNotFoundException {

        // public synchronized InputStream getResourceStream(String name)
        // throws ResourceNotFoundException {

        InputStream result = null;

        Exception exception = null;

        if (name == null || name.length() == 0) {
            throw new ResourceNotFoundException(
                    "WebappResourceLoader: No template name provided");
        }

        // names are <template>:<deviceType>
        // loading events_macros.vm etc will not have the type so only
check for
        // one.
        String[] split = name.split(":", 2);
        if (split.length < 1) {
            throw new ResourceNotFoundException("Invalid ThemeRL key " +
name);
        }

        String savedPath = (String) templatePaths.get(name);
        if (savedPath != null) {

            result = servletContext.getResourceAsStream(savedPath +
split[0]);

        }

        if (result == null) {

            for (int i = 0; i < paths.length; i++) {

                String path = paths[i] + split[0];

                try {

                    result = servletContext.getResourceAsStream(path);

                    // 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) {
                    // only save the first one for later throwing
                    if (exception == null) {
                        if (log.isDebugEnabled()) {
                            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 on class path.";

            // convert to a general Velocity ResourceNotFoundException
            if (exception == null) {
                throw new ResourceNotFoundException(msg);
            } else {
                msg += "  Due to: " + exception;
                throw new ResourceNotFoundException(msg, exception);
            }
        }

        return new BufferedReader(new InputStreamReader(result));
    }

    /**
     * Gets the cached file.
     *
     * @param rootPath
     *            the root path
     * @param fileName
     *            the file name
     *
     * @return the cached file
     */
    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);

        // names are <template>:<deviceType>
        // loading events_macros.vm etc will not have the type so only
check for
        // one.
        String[] split = fileName.split(":", 2);
        return new File(rootPath + savedPath, split[0]);

    }

    /**
     * Checks to see if a resource has been deleted, moved or modified. When
     * using the resource.loader.cache=true option
     *
     * @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
                // getResourceStream())
                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;
        }

    }

}

On 4 January 2017 at 16:04, Christopher Schultz <
ch...@christopherschultz.net> wrote:

> Greg,
>
> On 1/4/17 8:43 AM, Greg Huber wrote:
> > The was one issue that has been around for ages, and I am not sure if it
> is
> > possible to fix it.
> >
> > If I have added a new macro into a velocity template file loaded via a
> > resource loader, I have to shut down the container (tomcat) and restart
> for
> > it to be picked up.  I will allow the contents of the macro to be changed
> > but not a new macro.  I did try to see if I could fix it but without much
> > success.
> >
> > my velocity.properties :
> > ..
> > webapp.resource.loader.description=Webapp Resource Loader
> > webapp.resource.loader.class=rendering.velocity.WebappResourceLoader
> > webapp.resource.loader.cache=true
> > webapp.resource.loader.path=/WEB-INF/velocity,/WEB-INF/
> velocity/templates,/WEB-INF/velocity/templates/feeds,/WEB-
> INF/velocity/templates/emails
> > ...
> >
> > If you are now familiar with the code you might be in a better position
> to
> > see why I have to shut down for it to be picked up.
>
> Velocity version?
>
> When you say you "shut down the container (tomcat)", can you be more
> specific? Do you bounce the application, or do you terminate Tomcat and
> the JVM, etc.?
>
> Did you write your own WebappResourceLoader (and if so, why)?
>
> -chris
>
>

Reply via email to