diff options
Diffstat (limited to 'velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/StringResourceLoader.java')
-rw-r--r-- | velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/StringResourceLoader.java | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/StringResourceLoader.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/StringResourceLoader.java new file mode 100644 index 00000000..fd5d8c4a --- /dev/null +++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/StringResourceLoader.java @@ -0,0 +1,438 @@ +package 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 org.apache.commons.lang3.StringUtils; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.Resource; +import org.apache.velocity.runtime.resource.util.StringResource; +import org.apache.velocity.runtime.resource.util.StringResourceRepository; +import org.apache.velocity.runtime.resource.util.StringResourceRepositoryImpl; +import org.apache.velocity.util.ClassUtils; +import org.apache.velocity.util.ExtProperties; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Resource loader that works with Strings. Users should manually add + * resources to the repository that is used by the resource loader instance. + * + * Below is an example configuration for this loader. + * Note that 'repository.class' is not necessary; + * if not provided, the factory will fall back on using + * {@link StringResourceRepositoryImpl} as the default. + * <pre> + * resource.loaders = string + * resource.loader.string.description = Velocity StringResource loader + * resource.loader.string.class = org.apache.velocity.runtime.resource.loader.StringResourceLoader + * resource.loader.string.repository.name = MyRepositoryName (optional, to avoid using the default repository) + * resource.loader.string.repository.class = org.apache.velocity.runtime.resource.loader.StringResourceRepositoryImpl + * </pre> + * Resources can be added to the repository like this: + * <pre><code> + * StringResourceRepository repo = StringResourceLoader.getRepository(); + * + * String myTemplateName = "/some/imaginary/path/hello.vm"; + * String myTemplate = "Hi, ${username}... this is some template!"; + * repo.putStringResource(myTemplateName, myTemplate); + * </code></pre> + * + * After this, the templates can be retrieved as usual. + * <br> + * <p>If there will be multiple StringResourceLoaders used in an application, + * you should consider specifying a 'resource.loader.string.repository.name = foo' + * property in order to keep you string resources in a non-default repository. + * This can help to avoid conflicts between different frameworks or components + * that are using StringResourceLoader. + * You can then retrieve your named repository like this: + * <pre><code> + * StringResourceRepository repo = StringResourceLoader.getRepository("foo"); + * </code></pre> + * <p>and add string resources to the repo just as in the previous example. + * </p> + * <p>If you have concerns about memory leaks or for whatever reason do not wish + * to have your string repository stored statically as a class member, then you + * should set 'resource.loader.string.repository.static = false' in your properties. + * This will tell the resource loader that the string repository should be stored + * in the Velocity application attributes. To retrieve the repository, do:</p> + * <pre><code> + * StringResourceRepository repo = velocityEngine.getApplicationAttribute("foo"); + * </code></pre> + * <p>If you did not specify a name for the repository, then it will be stored under the + * class name of the repository implementation class (for which the default is + * 'org.apache.velocity.runtime.resource.util.StringResourceRepositoryImpl'). + * Incidentally, this is also true for the default statically stored repository. + * </p> + * <p>Whether your repository is stored statically or in Velocity's application + * attributes, you can also manually create and set it prior to Velocity + * initialization. For a static repository, you can do something like this: + * <pre><code> + * StringResourceRepository repo = new MyStringResourceRepository(); + * repo.magicallyAddSomeStringResources(); + * StringResourceLoader.setRepository("foo", repo); + * </code></pre> + * <p>Or for a non-static repository:</p> + * <pre><code> + * StringResourceRepository repo = new MyStringResourceRepository(); + * repo.magicallyAddSomeStringResources(); + * velocityEngine.setApplicationAttribute("foo", repo); + * </code></pre> + * <p>Then, assuming the 'resource.loader.string.repository.name' property is + * set to 'some.name', the StringResourceLoader will use that already created + * repository, rather than creating a new one. + * </p> + * + * @author <a href="mailto:eelco.hillenius@openedge.nl">Eelco Hillenius</a> + * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a> + * @author Nathan Bubna + * @version $Id$ + * @since 1.5 + */ +public class StringResourceLoader extends ResourceLoader +{ + /** + * Key to determine whether the repository should be set as the static one or not. + * @since 1.6 + */ + public static final String REPOSITORY_STATIC = "repository.static"; + + /** + * By default, repositories are stored statically (shared across the VM). + * @since 1.6 + */ + public static final boolean REPOSITORY_STATIC_DEFAULT = true; + + /** Key to look up the repository implementation class. */ + public static final String REPOSITORY_CLASS = "repository.class"; + + /** The default implementation class. */ + public static final String REPOSITORY_CLASS_DEFAULT = + StringResourceRepositoryImpl.class.getName(); + + /** + * Key to look up the name for the repository to be used. + * @since 1.6 + */ + public static final String REPOSITORY_NAME = "repository.name"; + + /** The default name for string resource repositories + * ('org.apache.velocity.runtime.resource.util.StringResourceRepository'). + * @since 1.6 + */ + public static final String REPOSITORY_NAME_DEFAULT = + StringResourceRepository.class.getName(); + + /** Key to look up the repository char encoding. */ + public static final String REPOSITORY_ENCODING = "repository.encoding"; + + protected static final Map<String, StringResourceRepository> STATIC_REPOSITORIES = + Collections.synchronizedMap(new HashMap<>()); + + /** + * Returns a reference to the default static repository. + * @return default static repository + */ + public static StringResourceRepository getRepository() + { + return getRepository(REPOSITORY_NAME_DEFAULT); + } + + /** + * Returns a reference to the repository stored statically under the + * specified name. + * @param name + * @return named repository + * @since 1.6 + */ + public static StringResourceRepository getRepository(String name) + { + return (StringResourceRepository)STATIC_REPOSITORIES.get(name); + } + + /** + * Sets the specified {@link StringResourceRepository} in static storage + * under the specified name. + * @param name + * @param repo + * @since 1.6 + */ + public static void setRepository(String name, StringResourceRepository repo) + { + STATIC_REPOSITORIES.put(name, repo); + } + + /** + * Removes the {@link StringResourceRepository} stored under the specified + * name. + * @param name + * @return removed repository + * @since 1.6 + */ + public static StringResourceRepository removeRepository(String name) + { + return (StringResourceRepository)STATIC_REPOSITORIES.remove(name); + } + + /** + * Removes all statically stored {@link StringResourceRepository}s. + * @since 1.6 + */ + public static void clearRepositories() + { + STATIC_REPOSITORIES.clear(); + } + + + /** + * the repository used internally by this resource loader + */ + protected StringResourceRepository repository; + + + /** + * @param configuration + * @see ResourceLoader#init(org.apache.velocity.util.ExtProperties) + */ + @Override + public void init(final ExtProperties configuration) + { + log.trace("StringResourceLoader: initialization starting."); + + // get the repository configuration info + String repoClass = configuration.getString(REPOSITORY_CLASS, REPOSITORY_CLASS_DEFAULT); + String repoName = configuration.getString(REPOSITORY_NAME, REPOSITORY_NAME_DEFAULT); + boolean isStatic = configuration.getBoolean(REPOSITORY_STATIC, REPOSITORY_STATIC_DEFAULT); + String encoding = configuration.getString(REPOSITORY_ENCODING); + + // look for an existing repository of that name and isStatic setting + if (isStatic) + { + this.repository = getRepository(repoName); + if (repository != null) + { + log.debug("Loaded repository '{}' from static repo store", repoName); + } + } + else + { + this.repository = (StringResourceRepository)rsvc.getApplicationAttribute(repoName); + if (repository != null) + { + log.debug("Loaded repository '{}' from application attributes", repoName); + } + } + + if (this.repository == null) + { + // since there's no repository under the repo name, create a new one + this.repository = createRepository(repoClass, encoding); + + // and store it according to the isStatic setting + if (isStatic) + { + setRepository(repoName, this.repository); + } + else + { + rsvc.setApplicationAttribute(repoName, this.repository); + } + } + else + { + // ok, we already have a repo + // warn them if they are trying to change the class of the repository + if (!this.repository.getClass().getName().equals(repoClass)) + { + log.debug("Cannot change class of string repository '{}' from {} to {}." + + " The change will be ignored.", + repoName, this.repository.getClass().getName(), repoClass); + } + + // allow them to change the default encoding of the repo + if (encoding != null && + !this.repository.getEncoding().equals(encoding)) + { + log.debug("Changing the default encoding of string repository '{}' from {} to {}", + repoName, this.repository.getEncoding(), encoding); + this.repository.setEncoding(encoding); + } + } + + log.trace("StringResourceLoader: initialization complete."); + } + + /** + * @param className + * @param encoding + * @return created repository + * @since 1.6 + */ + public StringResourceRepository createRepository(final String className, + final String encoding) + { + log.debug("Creating string repository using class {}...", className); + + StringResourceRepository repo; + try + { + repo = (StringResourceRepository) ClassUtils.getNewInstance(className); + } + catch (ClassNotFoundException cnfe) + { + throw new VelocityException("Could not find '" + className + "'", cnfe); + } + catch (IllegalAccessException iae) + { + throw new VelocityException("Could not access '" + className + "'", iae); + } + catch (InstantiationException ie) + { + throw new VelocityException("Could not instantiate '" + className + "'", ie); + } + + if (encoding != null) + { + repo.setEncoding(encoding); + } + else + { + repo.setEncoding(RuntimeConstants.ENCODING_DEFAULT); + } + + log.debug("Default repository encoding is {}", repo.getEncoding()); + return repo; + } + + /** + * Overrides superclass for better performance. + * @param name resource name + * @return whether resource exists + * @since 1.6 + */ + @Override + public boolean resourceExists(final String name) + { + if (name == null) + { + return false; + } + return (this.repository.getStringResource(name) != null); + } + + /** + * Get a reader so that the Runtime can build a + * template with it. + * + * @param name name of template to get. + * @param encoding asked encoding + * @return Reader containing the template. + * @throws ResourceNotFoundException Ff template not found + * in the RepositoryFactory. + * @since 2.0 + */ + @Override + public Reader getResourceReader(String name, String encoding) + throws ResourceNotFoundException + { + if (StringUtils.isEmpty(name)) + { + throw new ResourceNotFoundException("No template name provided"); + } + + StringResource resource = this.repository.getStringResource(name); + + if(resource == null) + { + throw new ResourceNotFoundException("Could not locate resource '" + name + "'"); + } + + byte [] byteArray = null; + InputStream rawStream = null; + + try + { + byteArray = resource.getBody().getBytes(resource.getEncoding()); + rawStream = new ByteArrayInputStream(byteArray); + return new InputStreamReader(rawStream, resource.getEncoding()); + } + catch(UnsupportedEncodingException ue) + { + if (rawStream != null) + { + try + { + rawStream.close(); + } + catch (IOException ioe) {} + } + throw new VelocityException("Could not convert String using encoding " + resource.getEncoding(), ue, rsvc.getLogContext().getStackTrace()); + } + } + + /** + * @param resource + * @return whether resource was modified + * @see ResourceLoader#isSourceModified(org.apache.velocity.runtime.resource.Resource) + */ + @Override + public boolean isSourceModified(final Resource resource) + { + StringResource original = null; + boolean result = true; + + original = this.repository.getStringResource(resource.getName()); + + if (original != null) + { + result = original.getLastModified() != resource.getLastModified(); + } + + return result; + } + + /** + * @param resource + * @return last modified timestamp + * @see ResourceLoader#getLastModified(org.apache.velocity.runtime.resource.Resource) + */ + @Override + public long getLastModified(final Resource resource) + { + StringResource original = null; + + original = this.repository.getStringResource(resource.getName()); + + return (original != null) + ? original.getLastModified() + : 0; + } + +} + |