package net.sourceforge.rtf.template;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.text.Format;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.rtf.ITemplateEngine;
import net.sourceforge.rtf.format.DefaultInputStreamFormat;
import net.sourceforge.rtf.format.DefaultRTFCodeStringFormat;
import net.sourceforge.rtf.format.rtfcode.IRTFCode;
import net.sourceforge.rtf.format.rtfcode.RTFCodeString;
public abstract class AbstractTemplateEngine implements ITemplateEngine {
private IContext context;
/**
* Formats to use for formatting of values.
*/
protected Map formats = null;
/**
* Reader that contains the template.
*/
protected Reader template;
public AbstractTemplateEngine() {
formats = new HashMap();
/**
* Manage image with Inputstream
*/
formats.put(FileInputStream.class, new DefaultInputStreamFormat());
formats.put(InputStream.class, new DefaultInputStreamFormat());
// Manage RTF code
formats.put(RTFCodeString.class, new DefaultRTFCodeStringFormat());
}
/**
* Put a value for the given key.
*
* @param key
* @param value
*/
public void put(String key, Object value) {
if (this.context == null) {
this.context = newContext();
}
this.context.put(key, value);
}
/**
* Merge.
*
* @param file name of file to merge into
*/
public void merge(String file) throws Exception
{
merge(new File(file));
}
/**
* Merge.
*
* @param file file to merge into
*/
public void merge(File file) throws Exception
{
Writer writer = null;
try
{
writer = new FileWriter(file);
merge(writer);
}
finally
{
if (writer != null)
{
writer.close();
}
}
}
public void merge(Writer writer) throws Exception {
if (template == null)
throw new IOException("Template must be defined. Use setTemplate method to set it.");
mergeWithTemplateEngine(writer);
}
/**
* Use a pre-populated formats map as the map for this template
*
* @param commonFormats a pre-built map of formats
*/
public void setFormatMap( Map commonFormats)
{
formats = commonFormats;
}
/**
* Set the default format for a given class.
*
* @param clazz class to set format for
* @param format format to use for instances of the given class
*/
public void setDefaultFormat(Class clazz, Format format)
{
formats.put(clazz, format);
}
/**
* Get the default format for a given class.
*
* @param clazz class to get default format for
* @return format
*/
public Format getDefaultFormat(Class clazz)
{
return (Format)formats.get(clazz);
}
protected void setContext(IContext context) {
this.context = context;
}
public IContext getContext() {
if (context == null) {
initializeContext();
}
return context;
}
public void setTemplate(Reader template) {
this.template = template;
}
/**
* Return true if value must be escaped and false otherwise
* @param value
* @return
*/
public boolean mustBeEscaped(Object value) {
if (value instanceof InputStream)
return false;
if (value != null && value instanceof IRTFCode) {
return ((IRTFCode)value).isEscaped();
}
return true;
}
/**
* Escape special chracters { and } with \{ and \}
* otherwise, RTF document generated is not valid.
* @param value
* @return
*/
protected Object escapeSpecialCharacters(Object value) {
if(value != null && value instanceof String ) {
String stringValue = (String)value;
if (stringValue.indexOf("{") != -1) {
stringValue = stringValue.replaceAll("\\{", "\\\\{");
}
if (stringValue.indexOf("}") != -1) {
stringValue = stringValue.replaceAll("\\}", "\\\\}");
}
return stringValue;
}
return value;
}
public IContext initializeContext() {
this.context = newContext();
return this.context;
}
/**
* Use a pre-populated Context.
* This method treats any previously populated keys in the context kindly,
* so it won't act unpredictably if this is called late
*
* @param innerContext a pre-populated Context object
*/
public void setGlobalContext( IContext globalContext)
{
IContext newcontext = newContext( globalContext );
if (context != null) {
Object[] keys = context.getKeys();
for( int kk = 0; kk < keys.length; kk++ ) {
newcontext.put( (String)keys[kk], context.get( (String)keys[kk] ) );
}
}
context = newcontext;
}
/**
*
* @return
*/
private IContext newContext(IContext context) {
IContext newcontext = newContext();
if (context != null) {
Object[] keys = context.getKeys();
for( int kk = 0; kk < keys.length; kk++ ) {
newcontext.put( (String)keys[kk], context.get( (String)keys[kk] ) );
}
}
return newcontext;
}
protected abstract void mergeWithTemplateEngine(Writer writer) throws Exception;
}