package net.sourceforge.rtf.web.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationContext;
import net.sourceforge.rtf.RTFTemplate;
import net.sourceforge.rtf.document.RTFDocument;
import net.sourceforge.rtf.document.transformer.config.DigesterTransformerConfig;
import net.sourceforge.rtf.document.transformer.config.TransformerConfig;
import net.sourceforge.rtf.helper.RTFTemplateBuilder;
import net.sourceforge.rtf.template.IContext;
import net.sourceforge.rtf.web.RTFTemplateException;
/**
*
* Abstract class RTFTemplate servlet to manage RTFTEmplate with Web Application.
* Method to implement are :
* <ul>
* <li><b>getRTFReader</b> : must return Reader of the RTF model source to use.</li>
* <li><b>putContext</b> : must return Reader of the RTF model source to use.</li>
* <li><b>getXMLFieldsAvailable</b> : must return XML fileds available
* for the RTF model or null if there is not XML Fileds available.</li>
* </ul>
* @version 1.0.0
* @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
*
*/
public abstract class AbstractRTFTemplateServlet extends HttpServlet {
public static final String RTF_CONTENT_TYPE = "application/rtf";
/**
* Map which contains transformed document cached.
*/
private Map cachedTransformedDocumentMap = new HashMap();
private ApplicationContext globalApplicationContext;
public void init() {
globalApplicationContext = getGlobalApplicationContext();
}
/**
* Handles HTTP <code>GET</code> requests by calling {@link
* #doRequest()}.
*/
public void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
doRequest(request, response);
}
/**
* Handles HTTP <code>POST</code> requests by calling {@link
* #doRequest()}.
*/
public void doPost( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
doRequest(request, response);
}
/**
* Handles all requests (by default).
*
* @param request HttpServletRequest object containing client request
* @param response HttpServletResponse object for the response
*/
protected void doRequest(HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
try {
// Get spring configuration for the model.
ApplicationContext applicationContext = getApplicationContext(request);
if (applicationContext == null) {
// Get global Spring configuration
applicationContext = globalApplicationContext;
}
// Test if RTFDocument must be un cached
String cacheWitkKey = cacheWithKey(request);
// Test if RTFDocument must be un cached
String unCackeWitkKey = unCacheWithKey(request);
if (unCackeWitkKey != null) {
// the transformed document must be un cached.
cachedTransformedDocumentMap.remove(unCackeWitkKey);
}
/**
* 2. Get RTFtemplate builder
*/
RTFTemplateBuilder builder = null;
if (applicationContext == null)
builder = RTFTemplateBuilder.newRTFTemplateBuilder();
else
builder = RTFTemplateBuilder.newRTFTemplateBuilder(applicationContext);
/**
* 3. Get RTFtemplate with Implementation
*/
String rtfTemplateImpl = getRTFTemplateImpl(request);
RTFTemplate rtfTemplate = (rtfTemplateImpl != null ? builder.
newRTFTemplate(rtfTemplateImpl) : builder.newRTFTemplate());
rtfTemplate.setGroupByPerPageBreak(getGroupByPerPageBreak(request));
/**
* 4. Put default format
*/
putDefaultFormat(request, rtfTemplate);
/**
* 5. Create a common inner context - not required but showing how common context values can be re-used
*/
IContext ctx = rtfTemplate.getTemplateEngine().newContext();
putGlobalContext(request, ctx);
/**
* 6. Set the template
*/
boolean isAlreadyCached = this.setTemplate(request, rtfTemplate, cacheWitkKey);
/**
* 8. Put Context
*/
putContext(request, rtfTemplate.getContext());
/*
* set the content type
*/
setContentType( request, response );
String fileName = getFileNameOfContentDisposition(request);
if (fileName != null) {
/*
* set the filename of content disposition
*/
setContentDisposition(response, fileName);
}
/**
* 10. Write to servlet Output
* result of Merge data with RTF model
*/
Writer writer = response.getWriter();
rtfTemplate.merge( writer);
if (cacheWitkKey != null && !isAlreadyCached) {
cachedTransformedDocumentMap.put(cacheWitkKey, rtfTemplate.getTransformedDocument());
}
}
catch (Exception e)
{
/*
* call the error handler to let the derived class
* do something useful with this failure.
*/
error( request, response, e);
}
}
/**
* Invoked when there is an error thrown in any part of doRequest() processing.
* <br><br>
* Default will send a simple HTML response indicating there was a problem.
*
* @param request original HttpServletRequest from servlet container.
* @param response HttpServletResponse object from servlet container.
* @param cause Exception that was thrown by some other part of process.
*/
protected void error( HttpServletRequest request, HttpServletResponse response, Exception cause )
throws ServletException, IOException
{
StringBuffer html = new StringBuffer();
html.append("<html>");
html.append("<title>Error</title>");
html.append("<body bgcolor=\"#ffffff\">");
html.append("<h2>RTFTemplateServlet: Error processing RTF edition</h2>");
html.append("<pre>");
String why = cause.getMessage();
if (why != null && why.trim().length() > 0)
{
html.append(why);
html.append("<br>");
}
StringWriter sw = new StringWriter();
cause.printStackTrace( new PrintWriter( sw ) );
html.append( sw.toString() );
html.append("</pre>");
html.append("</body>");
html.append("</html>");
response.getOutputStream().print( html.toString() );
}
/**
* Set content type to RTF.
* @param request
* @param response
*/
protected void setContentType(HttpServletRequest request,
HttpServletResponse response) {
response.setContentType(RTF_CONTENT_TYPE);
}
/**
* Set FileName of Content Disposition
* @param response
* @param fileName
*/
protected void setContentDisposition(HttpServletResponse response, String fileName) {
response.setHeader("Content-Disposition", "attachment; filename=\""+fileName+"\"");
}
/**
* This method to implement must return Reader of the RTF model source to use.
* @param request
* @return
* @throws Exception
*/
protected Reader getRTFReader( HttpServletRequest request ) throws Exception {
return null;
}
/**
* This method to implement must return InputStream of the RTF model source to use.
* @param request
* @return
* @throws Exception
*/
protected InputStream getRTFInputStream( HttpServletRequest request ) throws Exception {
return null;
}
/**
* This method to implement must put context for the RTF model source to use.
* @param request
* @param response
* @param ctx
* @throws Exception
*/
protected abstract void putContext(HttpServletRequest request, IContext ctx ) throws Exception;
/**
* This method to implement must return XML fileds available for the RTF model or null if there is not XML Fileds available.
* @param request
* @param response
* @return
* @throws Exception
*/
protected abstract InputStream getXMLFieldsAvailable( HttpServletRequest request ) throws Exception;
/**
* If this method is implemented, RTFTemplate use this TransformerConfig,
* oterwise, RTFTemplate use default TransformerConfig.
* @return
*/
protected InputStream getTransformerConfig(HttpServletRequest request) {
return null;
}
/**
* Return the real path of RTF Model.
* @param request
* @param rtfModelFile
* @return
*/
protected String getRealPathOfRTFModel(HttpServletRequest request , String rtfModelFile) {
return request.getRealPath("") + rtfModelFile;
}
protected String getFileNameOfContentDisposition(HttpServletRequest request) {
return null;
}
protected String getRTFTemplateImpl(HttpServletRequest request) {
return null;
}
protected void putDefaultFormat(HttpServletRequest request, RTFTemplate rtfTemplate) {
}
protected void putGlobalContext(HttpServletRequest request, IContext newContext) {
}
protected int getGroupByPerPageBreak(HttpServletRequest request) {
return -1;
}
protected String cacheWithKey(HttpServletRequest request) {
return null;
}
protected String unCacheWithKey(HttpServletRequest request) {
return null;
}
/**
* Return global Spring configuration for RTFTemplate
* @return
*/
protected ApplicationContext getGlobalApplicationContext() {
return null;
}
/**
* Return Spring configuration for RTFTemplate
* @return
*/
protected ApplicationContext getApplicationContext(HttpServletRequest request) {
return null;
}
private boolean setTemplate(HttpServletRequest request, RTFTemplate rtfTemplate, String cackeWitkKey) throws Exception {
// test if RTF model is cached
if (cackeWitkKey != null) {
RTFDocument cachedTransformedDocument = (RTFDocument)cachedTransformedDocumentMap.get(cackeWitkKey);
if (cachedTransformedDocument != null) {
// Use cached Transformed Document
rtfTemplate.setTransformedDocument(cachedTransformedDocument);
return true;
}
}
// there is no cache, or the template is not cached,
// load it
/**
* 1. Get RTF Reader or InputStream
*/
InputStream rtfInputStream = null;
Reader rtfReader = getRTFReader(request);
if (rtfReader == null) {
rtfInputStream = getRTFInputStream(request);
if (rtfInputStream == null)
throw new RTFTemplateException("Impossible to launch RTF edition. Method RTFTemplateServlet.getRTFReader or RTFTemplateServlet.getRTFInputStream must not return null.");
}
if(rtfReader != null)
rtfTemplate.setTemplate(rtfReader);
else
rtfTemplate.setTemplate(rtfInputStream);
/**
* 9. Set XML fields available
*/
InputStream xmlFieldsStream = getXMLFieldsAvailable(request);
rtfTemplate.setXmlFields(xmlFieldsStream);
/**
* 7. Set Transformer Config
*/
InputStream transformerConfigStream = getTransformerConfig(request);
if (transformerConfigStream != null) {
TransformerConfig transformConfig = DigesterTransformerConfig.
getTransformerConfig(transformerConfigStream);
rtfTemplate.setTransformerConfig(transformConfig);
}
return false;
}
}