package org.juxtasoftware.util.ftl;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import freemarker.core.Environment;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
/**
* Custom FTL directive to stream a file into the body. That file
* must be set as the src param of the directive call. Optionally, it will
* look for <code>srcRangeStart</code> and <code>srcRangeEnd</code>.
* If both are set, the data read from the source will be constrained
* to this range.
*
* @author loufoster
*
*/
public class FileDirective implements TemplateDirectiveModel {
private FileDirectiveListener listener;
public void setListener( FileDirectiveListener listener ) {
this.listener = listener;
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] model, TemplateDirectiveBody body)
throws TemplateException, IOException {
// Error check and collect necessary data:
if (params.containsKey("src") == false ) {
throw new TemplateModelException(
"This directive requires a src paramater");
}
// OPTIONAL startRange
TemplateModel startVal = env.getVariable("srcRangeStart");
Integer start = null;
if (startVal != null ) {
start = Integer.parseInt(startVal.toString());
}
// OPTIONAL endRange
TemplateModel endVal = env.getVariable("srcRangeEnd");
Integer end = null;
if (endVal != null ) {
end = Integer.parseInt(endVal.toString());
}
if ((start == null && end != null) ||
(start != null && end == null) ) {
throw new TemplateModelException(
"Incomplete range: Only one of srcRangeStart/srcRangeEnd pair specified");
}
// Stream in the data
InputStreamReader isr = null;
final SimpleScalar scalarValue = (SimpleScalar)params.get("src");
final String srcFile = scalarValue.getAsString();
File src = new File( srcFile );
try {
Writer out = env.getOut();
FileInputStream fis = new FileInputStream(src);
isr = new InputStreamReader(fis, "UTF-8");
int pos = 0;
while (true) {
int data = isr.read();
if (data == -1 ) {
break;
} else {
// is a range defined?
if ( start != null && end != null ) {
// only write out data in range
if ( pos >= start && pos <= end ) {
out.write( data );
}
} else {
// write evertything
out.write( data );
}
pos++;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(isr);
}
// notify others that we are done with the file
if ( this.listener != null ) {
this.listener.fileReadComplete(src);
}
}
}