/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
*
* [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
package hk.hku.cecid.piazza.commons.pagelet;
import hk.hku.cecid.piazza.commons.io.IOHandler;
import hk.hku.cecid.piazza.commons.servlet.RequestListenerException;
import hk.hku.cecid.piazza.commons.servlet.http.HttpRequestAdaptor;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* HttpPageletAdaptor is an HTTP request adaptor which generates a page from a
* template pagelet. A template pagelet may contain the content, or part of the
* content, of the page to be generated. It also describes the layout of other
* pagelets in the page.
* <p>
* The tag in the template which declares a pagelet should follow the convention
* stated below:
* <pre>
* <!-- template-[pagelet-id] -->
* </pre>
* <p>
* By default, there are two generation modes of the page.
* <ol>
* <li> full - Generate the page according to the template pre-defined
* by this adaptor. This is the default generation mode.
* <li> raw - Generate the page according to the dynamically specified pagelet.
* </ol>
* <p>
* Note: All the pagelets, including the template, must be saved in UTF-8 encoding.
*
* @see Pagelet
* @see PageletStore
* @see Template
*
* @author Hugo Y. K. Lam
*
*/
public abstract class HttpPageletAdaptor extends HttpRequestAdaptor {
/**
* The name of the request parameter which specifies a pagelet ID.
* This parameter is named 'pagelet'.
*/
protected static final String REQ_PARAM_PAGELET = "pagelet";
/**
* The name of the request parameter which specifies the generation mode.
* This parameter is named 'mode'.
*/
protected static final String REQ_PARAM_PAGEMODE = "mode";
/**
* The name of the request parameter which specifies an action.
* This parameter is named 'action'.
*/
protected static final String REQ_PARAM_ACTION = "action";
/**
* Processes the page request.
* This method determines if the generation mode is "raw". If not, it invokes
* processTemplate() to complete the rest of the generation.
*
* @see #processTemplate(HttpServletRequest,HttpServletResponse)
* @see hk.hku.cecid.piazza.commons.servlet.http.HttpRequestListener#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public String processRequest(HttpServletRequest request,
HttpServletResponse response) throws RequestListenerException {
try {
String pageMode = request.getParameter(REQ_PARAM_PAGEMODE);
String pageletId =request.getParameter(REQ_PARAM_PAGELET);
if ("raw".equalsIgnoreCase(pageMode) || pageletId!=null && pageMode==null) {
Pagelet rawPage = getPagelet(pageletId);
if (rawPage != null) {
response.setContentType(null);
IOHandler.pipe(rawPage.openStream(), response.getOutputStream());
}
}
else {
processTemplate(request, response);
}
}
catch (Exception e) {
throw new RequestListenerException("Error occurred in generating page", e);
}
return null;
}
/**
* Processes the template of the generating page.
* This method invokes getTemplate() to retrieve the template pagelet. It
* then generates the page according to the pagelet. The content of the
* template pagelet will be parsed according to the following alogirthm:
* <ul>
* <li>When it encounters any text other than a template tag, it invokes
* processText() to generate the content.
* <li>When it encounters a template tag in the template, it invokes
* processPagelet() to generate the content.
* <li>When it encounters any errors while invoking processPagelet(), it will
* invokes processError() to generate the content.
* </ul>
* <p>
*
* @param request the servlet request.
* @param response the servlet response.
* @throws RequestListenerException if unable to process the template.
*
* @see #getTemplate(HttpServletRequest)
* @see #processText(TemplateElement, String, HttpServletRequest, HttpServletResponse)
* @see #processPagelet(TemplateElement, Pagelet, HttpServletRequest, HttpServletResponse)
* @see #processError(TemplateElement, Throwable, HttpServletRequest, HttpServletResponse)
*/
protected void processTemplate(HttpServletRequest request,
HttpServletResponse response) throws RequestListenerException {
try {
Pagelet tempPage = getTemplate(request);
String s = IOHandler.readString(tempPage.openStream(),
Charset.forName("UTF-8"));
Template template = new Template(s);
template.parse();
while (template.hasMoreElements()) {
TemplateElement element = template.nextElement();
if (element.isText()) {
processText(element, element.getText(), request, response);
}
else {
Pagelet pagelet = getPagelet(element.getName());
try {
processPagelet(element, pagelet, request, response);
}
catch (Throwable error) {
processError(element, error, request, response);
}
}
}
}
catch (Exception e) {
throw new RequestListenerException("Error in processing template", e);
}
}
/**
* Processes the text part of the generating page by simply generating the
* text to the output.
*
* @param element the template element which represents the text.
* @param text the text to be processed.
* @param request the servlet request.
* @param response the servlet response.
* @throws RequestListenerException if unable to process the text.
*
* @see #processTemplate(HttpServletRequest, HttpServletResponse)
*/
protected void processText(TemplateElement element, String text, HttpServletRequest request,
HttpServletResponse response) throws RequestListenerException {
try {
IOHandler.writeString(text, response.getWriter());
}
catch (IOException e) {
throw new RequestListenerException("Error in processing text", e);
}
}
/**
* Processes the pagelet of the generating page by reading the content from
* the pagelet and generates it to the output.
*
* @param element the template element which represents the pagelet.
* @param pagelet the pagelet to be processed.
* @param request the servlet request.
* @param response the servlet response.
* @throws RequestListenerException if unable to process the pagelet.
*
* @see #processTemplate(HttpServletRequest, HttpServletResponse)
*/
protected void processPagelet(TemplateElement element, Pagelet pagelet, HttpServletRequest request,
HttpServletResponse response) throws RequestListenerException {
try {
if (pagelet != null) {
InputStreamReader reader = new InputStreamReader(
pagelet.openStream(), Charset.forName("UTF-8"));
IOHandler.pipe(reader, response.getWriter());
reader.close();
reader = null;
}
}
catch (Exception e) {
throw new RequestListenerException("Error in processing pagelet", e);
}
}
/**
* Processes the error generated when processing a pagelet.
*
* @param element the template element which represents the pagelet.
* @param error the error generated by the pagelet process.
* @param request the servlet request.
* @param response the servlet response.
* @throws RequestListenerException if unable to process the pagelet error.
*
* @see #processTemplate(HttpServletRequest, HttpServletResponse)
*/
protected void processError(TemplateElement element, Throwable error, HttpServletRequest request,
HttpServletResponse response) throws RequestListenerException {
try {
processPagelet(element, getErrorPagelet(request), request, response);
}
catch (Exception e) {
throw new RequestListenerException("Error in processing pagelet error: "+e, error);
}
}
/**
* Gets the template pagelet.
* This method invokes getPagelet() with a parameter "&pagelet-template".
*
* @param request the servlet request.
* @return the template pagelet.
*/
protected Pagelet getTemplate(HttpServletRequest request) {
return getPagelet("&pagelet-template");
}
/**
* Gets the error pagelet.
* This method invokes getPagelet() with a parameter "&pagelet-error".
*
* @param request the servlet request.
* @return the template pagelet.
*/
protected Pagelet getErrorPagelet(HttpServletRequest request) {
return getPagelet("&pagelet-error");
}
/**
* Gets the pagelet from the underlying pagelet store.
* If the specified ID is preceded by an ampersand, it indicates the pagelet
* id should be firstly treated as a listener parameter name which has a
* value of the target pagelet ID. In this case, if there is a corresponding
* listener parameter, its value will be used as the target pagelet ID.
* Otherwise, the specified id will be matched against the underlying pagelet
* store as if there is no ampersand indicator.
*
* @param id the pagelet ID.
* @return the corresponding pagelet or null if not found.
*/
protected Pagelet getPagelet(String id) {
if (id != null && id.startsWith("&")) {
id = id.substring(1);
String refId = getParameters().getProperty(id);
if (refId != null) {
id = refId;
}
}
return getPageletStore().getPagelet(id);
}
/**
* Gets the pagelet store which holds all the registered pagelets of this
* adaptor.
*
* @return a pagelet store.
*/
protected abstract PageletStore getPageletStore();
}