001: /*
002: * argun 1.0
003: * Web 2.0 delivery framework
004: * Copyright (C) 2007 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.web;
024:
025: import java.io.IOException;
026: import java.util.HashMap;
027: import java.util.Map;
028:
029: import javax.servlet.ServletConfig;
030: import javax.servlet.ServletException;
031: import javax.servlet.http.HttpServlet;
032: import javax.servlet.http.HttpServletRequest;
033: import javax.servlet.http.HttpServletResponse;
034: import javax.xml.parsers.DocumentBuilder;
035: import javax.xml.parsers.DocumentBuilderFactory;
036: import javax.xml.parsers.FactoryConfigurationError;
037: import javax.xml.parsers.ParserConfigurationException;
038: import javax.xml.transform.Result;
039: import javax.xml.transform.TransformerException;
040: import javax.xml.transform.dom.DOMSource;
041: import javax.xml.transform.stream.StreamResult;
042:
043: import org.apache.log4j.Logger;
044: import org.w3c.dom.Document;
045: import org.w3c.dom.Element;
046: import org.w3c.dom.Node;
047:
048: import biz.hammurapi.config.Context;
049: import biz.hammurapi.metrics.MeasurementCategoryFactory;
050: import biz.hammurapi.metrics.TimeIntervalCategory;
051: import biz.hammurapi.web.xslt.AbstractXsltTransformer;
052: import biz.hammurapi.web.xslt.XsltTransformerBase;
053: import biz.hammurapi.web.xslt.AbstractXsltTransformer.SetParametersCallback;
054: import biz.hammurapi.xml.dom.CompositeDomSerializer;
055:
056: /**
057: * Converts to DOM and styles request or session attribute. Also a base class
058: * for other servlets that apply XST style as part of processing
059: * @web:servlet name="ActionServlet" display-name="ActionServlet" load-on-startup="1"
060: * @web:servlet-init-param name="style-prefix" value="/WEB-INF/style/"
061: * @web:servlet-init-param name="style-suffix" value=".xsl"
062: */
063: public class StylingServlet extends HttpServlet {
064: private Map transformers = new HashMap();
065: private String stylePrefix = "/";
066: private String styleSuffix = ".xsl";
067: protected String parameterizer;
068:
069: private static final Logger logger = Logger
070: .getLogger(StylingServlet.class);
071: private static final TimeIntervalCategory ttic = MeasurementCategoryFactory
072: .getTimeIntervalCategory(StylingServlet.class.getName()
073: + ".transform");
074:
075: /**
076: * @return new document builder
077: * @throws ParserConfigurationException
078: * @throws FactoryConfigurationError
079: */
080: protected static DocumentBuilder newDocumentBuilder()
081: throws ParserConfigurationException,
082: FactoryConfigurationError {
083: return DocumentBuilderFactory.newInstance()
084: .newDocumentBuilder();
085: }
086:
087: /**
088: * Override this method to return custom serializer if needed.
089: * @return DomSerializer
090: */
091: protected CompositeDomSerializer getDomSerializer() {
092: return CompositeDomSerializer.getThreadInstance();
093: }
094:
095: public void init(ServletConfig config) throws ServletException {
096: super .init(config);
097: config.getServletContext().log(
098: "[" + getClass().getName() + "] Initialization");
099:
100: String initParameter = config.getInitParameter("style-prefix");
101: if (initParameter != null) {
102: stylePrefix = initParameter;
103: config.getServletContext().log(
104: "style-prefix=" + stylePrefix);
105: }
106:
107: initParameter = config.getInitParameter("style-suffix");
108: if (initParameter != null) {
109: styleSuffix = initParameter;
110: config.getServletContext().log(
111: "style-suffix=" + styleSuffix);
112: }
113:
114: initParameter = config.getInitParameter("parameterizer");
115: if (initParameter != null) {
116: parameterizer = initParameter;
117: config.getServletContext().log(
118: "parameterizer=" + parameterizer);
119: }
120: }
121:
122: /** Handles the HTTP <code>GET</code> method.
123: * @param request servlet request
124: * @param response servlet response
125: */
126: protected void doGet(HttpServletRequest request,
127: HttpServletResponse response) throws ServletException,
128: java.io.IOException {
129: processRequest(request, response);
130: }
131:
132: /** Handles the HTTP <code>POST</code> method.
133: * @param request servlet request
134: * @param response servlet response
135: */
136: protected void doPost(HttpServletRequest request,
137: HttpServletResponse response) throws ServletException,
138: java.io.IOException {
139: processRequest(request, response);
140: }
141:
142: protected void processRequest(HttpServletRequest request,
143: HttpServletResponse response) throws ServletException,
144: IOException {
145: String pathInfo = request.getPathInfo();
146: logger.debug("Serving " + pathInfo);
147: try {
148: if (pathInfo == null) {
149: response.sendError(404, "Invalid style path: "
150: + pathInfo);
151: return;
152: }
153:
154: String[] path = pathInfo.split("/", 4);
155:
156: if (path.length != 4) {
157: response.sendError(404, "Invalid style path: "
158: + pathInfo);
159: return;
160: }
161:
162: Object o = null;
163: if ("session".equals(path[1])) {
164: o = request.getSession().getAttribute(path[2]);
165: if (o == null) {
166: throw new ServletException("Session attribute '"
167: + path[2] + "' not found");
168: }
169: } else if ("request".equals(path[1])) {
170: o = request.getAttribute(path[2]);
171: if (o == null) {
172: throw new ServletException("Request attribute '"
173: + path[2] + "' not found");
174: }
175: } else {
176: response.sendError(404, "Invalid path: " + pathInfo);
177: return;
178: }
179:
180: Document doc = newDocumentBuilder().newDocument();
181: Element re = doc.createElement("response");
182: doc.appendChild(re);
183: getDomSerializer().toDomSerializable(o).toDom(re);
184:
185: getTransformer(path[3]).transform(doc,
186: getSetParametersCallback(request, path[3]),
187: response);
188: } catch (ParserConfigurationException e) {
189: throw new ServletException(e);
190: }
191: }
192:
193: protected SetParametersCallback getSetParametersCallback(
194: final HttpServletRequest request, String styleName) {
195: SetParametersCallback spc = null;
196: if (parameterizer != null) {
197: Object p = new RequestContext(request).get(parameterizer);
198: if (p instanceof SetParametersCallback) {
199: spc = (SetParametersCallback) p;
200: } else if (styleName != null && p instanceof Context) {
201: Object pp = ((Context) p).get(styleName);
202: if (pp instanceof SetParametersCallback) {
203: spc = (SetParametersCallback) pp;
204: } else {
205: logger.warn("Cannot parameterize stylesheet '"
206: + styleName + "': "
207: + pp.getClass().getName()
208: + " does not implement "
209: + SetParametersCallback.class.getName());
210: }
211: } else if (p != null) {
212: logger.warn("Cannot parameterize stylesheet '"
213: + styleName + "': " + p.getClass().getName()
214: + " does not implement "
215: + SetParametersCallback.class.getName());
216: }
217: }
218: return spc;
219: }
220:
221: protected class TransformCommand {
222:
223: private String style;
224:
225: TransformCommand(String path) {
226: style = path == null ? null : stylePrefix + path
227: + styleSuffix;
228: logger.debug("New transformer: " + style);
229:
230: transformer = new XsltTransformerBase();
231: transformer.setServletContext(getServletContext());
232: if (style != null) {
233: transformer.setUri(style);
234: }
235: }
236:
237: AbstractXsltTransformer transformer;
238:
239: public void transform(Node node, SetParametersCallback spc,
240: final HttpServletResponse response)
241: throws ServletException {
242: long start = ttic.getTime();
243: try {
244: transformer
245: .transform(
246: new DOMSource(node),
247: new StreamResult(response.getWriter()),
248: new AbstractXsltTransformer.SetContentTypeCallBack() {
249: public void setContentType(
250: String contentType) {
251: response
252: .setContentType(contentType);
253: }
254: }, spc);
255: } catch (FactoryConfigurationError e) {
256: throw new ServletException(e);
257: } catch (HammurapiWebException e) {
258: throw new ServletException(e);
259: } catch (TransformerException e) {
260: throw new ServletException(e);
261: } catch (IOException e) {
262: throw new ServletException(e);
263: } finally {
264: ttic.addInterval(style, start);
265: }
266: }
267:
268: public void transform(Document doc, final Result result)
269: throws HammurapiWebException {
270: long start = ttic.getTime();
271: try {
272: transformer.transform(new DOMSource(doc), result, null,
273: null);
274: } catch (FactoryConfigurationError e) {
275: throw new HammurapiWebException(e);
276: } catch (TransformerException e) {
277: throw new HammurapiWebException(e);
278: } finally {
279: ttic.addInterval(style, start);
280: }
281: }
282:
283: }
284:
285: /**
286: * @param path - Style path.
287: */
288: protected synchronized TransformCommand getTransformer(String path) {
289: TransformCommand command = (TransformCommand) transformers
290: .get(path);
291: if (command == null) {
292: command = new TransformCommand(path);
293: transformers.put(path, command);
294: }
295: return command;
296: }
297: }
|