/**
* The MIT License (MIT)
*
* Copyright (c) 2015 <mickael.jeanroy@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.github.mjeanroy.springmvc.view.mustache.configuration;
import static com.github.mjeanroy.springmvc.view.mustache.commons.PreConditions.hasText;
import static com.github.mjeanroy.springmvc.view.mustache.commons.PreConditions.notNull;
import com.github.mjeanroy.springmvc.view.mustache.MustacheTemplateLoader;
import com.github.mjeanroy.springmvc.view.mustache.core.CompositeResourceLoader;
import com.github.mjeanroy.springmvc.view.mustache.core.DefaultTemplateLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ClassUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
/**
* Factory bean for {@link com.github.mjeanroy.springmvc.view.mustache.MustacheTemplateLoader} instance.
*/
public class MustacheTemplateLoaderFactoryBean extends AbstractFactoryBean<MustacheTemplateLoader> implements FactoryBean<MustacheTemplateLoader>, ApplicationContextAware, ResourceLoaderAware {
/**
* Class logger.
*/
private static final Logger log = LoggerFactory.getLogger(MustacheTemplateLoaderFactoryBean.class);
/**
* Classpath resource loader, implemented as a singleton.
*/
private static final ClasspathResourceLoader CLASSPATH_RESOURCE_LOADER = new ClasspathResourceLoader();
/**
* Current application context.
*/
private ApplicationContext applicationContext;
/**
* Current resource loader.
*/
private ResourceLoader resourceLoader;
/**
* @see {@link com.github.mjeanroy.springmvc.view.mustache.MustacheTemplateLoader#getPrefix()}
*/
private String prefix;
/**
* @see {@link com.github.mjeanroy.springmvc.view.mustache.MustacheTemplateLoader#getSuffix()}
*/
private String suffix;
/**
* @see {@link com.github.mjeanroy.springmvc.view.mustache.MustacheTemplateLoader#addPartialAliases(java.util.Map)}
*/
private final Map<String, String> partialAliases;
/**
* Default constructor.
*/
public MustacheTemplateLoaderFactoryBean() {
super();
this.partialAliases = new HashMap<String, String>();
}
@Override
public Class<?> getObjectType() {
return MustacheTemplateLoader.class;
}
@Override
protected MustacheTemplateLoader createInstance() throws Exception {
log.debug("Create instance of {}", DefaultTemplateLoader.class);
DefaultTemplateLoader templateLoader = new DefaultTemplateLoader(computeResourceLoader());
templateLoader.setPrefix(prefix);
templateLoader.setSuffix(suffix);
templateLoader.addPartialAliases(partialAliases);
return templateLoader;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
protected ResourceLoader computeResourceLoader() {
log.debug("Build composite resource loader");
Collection<ResourceLoader> resourceLoaders = new LinkedHashSet<ResourceLoader>();
if (resourceLoader != null) {
log.trace(" => Add custom resource loader: {}", resourceLoader);
resourceLoaders.add(resourceLoader);
}
if (applicationContext != null) {
log.trace(" => Add application context as resource loader: {}", applicationContext);
resourceLoaders.add(applicationContext);
}
if (resourceLoaders.isEmpty()) {
log.trace(" => Add instance of ClassPathXmlApplicationContext as resource loader");
resourceLoaders.add(new ClassPathXmlApplicationContext());
log.trace(" => Add instance of FileSystemXmlApplicationContext as resource loader");
resourceLoaders.add(new FileSystemXmlApplicationContext());
}
log.debug("Add instance of classpath resource loader");
resourceLoaders.add(CLASSPATH_RESOURCE_LOADER);
log.debug("Create composite resource loader using: {}", resourceLoaders);
log.trace(" => Number of loaders: {}", resourceLoaders.size());
return new CompositeResourceLoader(resourceLoaders);
}
/**
* Set {@link #prefix}
*
* @param prefix New {@link #prefix}
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Set {@link #suffix}
*
* @param suffix New {@link #suffix}
*/
public void setSuffix(String suffix) {
this.suffix = suffix;
}
/**
* Set {@link #partialAliases}
*
* @param partialAliases New {@link #partialAliases}
*/
public void setPartialAliases(Map<String, String> partialAliases) {
this.partialAliases.putAll(partialAliases);
}
/**
* Implementation of spring {@link org.springframework.core.io.ResourceLoader}
* that will always check for resources in the classpath (not the root of the application
* context).
*
* This class does not guarantee that resource patterns such as "file:/" or "http:" will
* work, that's why this class should remain private and should not be used outside.
*/
private static final class ClasspathResourceLoader implements ResourceLoader {
/**
* Classpath prefix.
*/
private static final String CLASSPATH_PREFIX = "classpath:";
/**
* Create new resource loader.
*/
private ClasspathResourceLoader() {
}
@Override
public Resource getResource(String location) {
notNull(location, "Resource location must not be null");
hasText(location, "Resource location must be defined");
// Remove the classpath if specified.
// This should never happen since a previous resource loader will probably be used
// before.
String classpathLocation = location;
if (location.startsWith(CLASSPATH_PREFIX)) {
classpathLocation = location.substring(CLASSPATH_PREFIX.length());
}
return new ClassPathResource(classpathLocation);
}
@Override
public ClassLoader getClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
}
}