All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rs.mail.templates.resolver.AbstractFileResolver Maven / Gradle / Ivy

package rs.mail.templates.resolver;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import rs.mail.templates.ResolverException;
import rs.mail.templates.TemplateContext;
import rs.mail.templates.cache.Cache;
import rs.mail.templates.cache.CacheFactory;
import rs.mail.templates.cache.CacheFactory.CacheBuilder;
import rs.mail.templates.cache.CacheStrategy;
import rs.mail.templates.impl.ResolverId;

/**
 * The default resolver searches a specific directory (non-recursive)
 * versions of a file name. The order of lookups will be provided through 
 * method ...
 * 
 * @param  the type of object to be resolved
 * 
 * @author ralph
 *
 */
public abstract class AbstractFileResolver extends AbstractResolver {

	private File directory;
	private Charset charset;
	
	/**
	 * Constructor (which uses a LRU cache).
	 * 
	 * @param directory - the directory to search templates (non-recursive)
	 * @param objectClass - the type of object to be resolved
	 * @throws IOException - when the directory is not accessible
	 */
	public AbstractFileResolver(File directory, Class objectClass) throws IOException {
		this(directory, true, objectClass);
	}
	
	/**
	 * Constructor to enable or disable the default LRU cache.
	 * 
	 * @param directory - the directory to search templates (non-recursive)
	 * @param enableCache whether to enable the Cache
	 * @param objectClass - the type of object to be resolved
	 * @throws IOException - when the directory is not accessible
	 */
	public AbstractFileResolver(File directory, boolean enableCache, Class objectClass) throws IOException {
		this(directory, enableCache? CacheFactory.newBuilder(ResolverId.class, objectClass).with(CacheStrategy.LRU).build() : null);
	}
	
	/**
	 * Constructor to use a specific cache strategy.
	 * 
	 * @param directory - the directory to search templates (non-recursive)
	 * @param cacheStrategy the cahce strategy to be used
	 * @param objectClass - the type of object to be resolved
	 * @throws IOException - when the directory is not accessible
	 */
	public AbstractFileResolver(File directory, CacheStrategy cacheStrategy, Class objectClass) throws IOException {
		this(directory, CacheFactory.newBuilder(ResolverId.class, objectClass).with(cacheStrategy));
	}
	
	/**
	 * Constructor to use a custom {@link CacheBuilder}.
	 * 
	 * @param directory - the directory to search templates (non-recursive)
	 * @param cacheBuilder the cache builder
	 * @throws IOException - when the directory is not accessible
	 */
	public AbstractFileResolver(File directory, CacheBuilder cacheBuilder) throws IOException {
		this(directory, cacheBuilder.build());
	}
	
	/**
	 * Constructor to use a custom cache.
	 * 
	 * @param directory - the directory to search templates (non-recursive)
	 * @param cache the cache to be used (can be null)
	 * @throws IOException - when the directory is not accessible
	 */
	public AbstractFileResolver(File directory, Cache cache) throws IOException {
		super(cache);
		this.directory = directory;
		this.charset   = StandardCharsets.UTF_8;
		if (!directory.exists())      throw new FileNotFoundException("Not found: "+directory.getCanonicalPath());
		if (!directory.isDirectory()) throw new IOException("Not a directory: "+directory.getCanonicalPath());
		if (!directory.canRead())     throw new IOException("Cannot read: "+directory.getCanonicalPath());
	}

	/**
	 * Returns the directory.
	 * @return the directory
	 */
	public File getDirectory() {
		return directory;
	}

	/**
	 * Returns the charset to be used.
	 * @return charset to be used
	 */
	public Charset getCharset() {
		return getCharset(false);
	}
	
	/**
	 * Sets the charset.
	 * @param charset the charset to set
	 */
	public void setCharset(Charset charset) {
		this.charset = charset;
	}

	/**
	 * Returns the charset to be used or - if required - a default one
	 * @param resolveWithDefault whether a default charset shall be returned when no charset was set before
	 * @return a charset
	 */
	protected Charset getCharset(boolean resolveWithDefault) {
		if (charset == null) {
			if (resolveWithDefault) return Charset.defaultCharset();
		}
		return charset;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected X resolve(ResolverId id, String name, TemplateContext context) throws ResolverException {
		X rc = null;
		
		// Find in cache
		boolean cacheHit = false;
		Cache cache = getCache();
		if (cache != null) {
			rc = cache.get(id);
		}
		if (rc == null) {
			rc = create(id, name, context);
		} else {
			cacheHit = true;
		}
		
		if ((cache != null) && (rc != null) && !cacheHit) {
			cache.put(id, rc);
		}
		return rc;
	}

	/**
	 * Creates the resolved object based on the resolver id, the name and the context.
	 * 

It is up to descendants to resolve files and how to incorporate in the resolved * object. This class provides some useful methods for that purpose.

* * @param id - ID of resolved object * @param name - base name of resolved object * @param context - the template context for further information * @return the created object * @throws ResolverException when resolving fails * @see #getPriorityPaths(String, TemplateContext, String) * @see #getFileVariants(TemplateContext) * @see #findFile(List) */ protected abstract X create(ResolverId id, String name, TemplateContext context) throws ResolverException; /** * Returns the files to be checked in order of priority. *

This implementation uses {@link #getFileVariants(TemplateContext)}, but subclasses my decide * to overrride this method for additional files to be returned.

* * @param name - the base name of the file * @param context - the context * @param suffix - the suffix of the file * @return the files to be checked * @see #getFileVariants(TemplateContext) */ protected List getPriorityPaths(String name, TemplateContext context, String suffix) { String variants[] = getFileVariants(context); List files = new ArrayList<>(); for (int i=0; iDefault implementation uses the locale in the context and e.g. returns ["de-DE", "de" ]

* @param context - the context holding information about the message to be built * @return the list of variants to be checked for files */ protected String[] getFileVariants(TemplateContext context) { Locale locale = context.getLocale(); return new String[] { locale.toLanguageTag(), locale.getLanguage() }; } /** * Check files in order of priorities to find the first readable. * @param priorities - list of files in order of priority * @return - the file that can be used or {@code null} if none is available */ protected File findFile(List priorities) { for (File file : priorities) { if (file.exists() && file.isFile() && file.canRead()) { return file; } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy