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:
024: package biz.hammurapi.web.menu;
025:
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.PrintWriter;
029: import java.io.StringReader;
030: import java.io.StringWriter;
031: import java.sql.SQLException;
032: import java.util.ArrayList;
033: import java.util.Collection;
034: import java.util.Collections;
035: import java.util.Enumeration;
036: import java.util.HashMap;
037: import java.util.Iterator;
038: import java.util.List;
039: import java.util.Map;
040:
041: import javax.servlet.Filter;
042: import javax.servlet.FilterChain;
043: import javax.servlet.FilterConfig;
044: import javax.servlet.ServletException;
045: import javax.servlet.ServletRequest;
046: import javax.servlet.ServletResponse;
047: import javax.servlet.http.HttpServletRequest;
048: import javax.servlet.http.HttpServletResponse;
049: import javax.servlet.http.HttpSession;
050: import javax.xml.parsers.DocumentBuilder;
051: import javax.xml.parsers.DocumentBuilderFactory;
052: import javax.xml.parsers.ParserConfigurationException;
053: import javax.xml.transform.Source;
054: import javax.xml.transform.Templates;
055: import javax.xml.transform.Transformer;
056: import javax.xml.transform.TransformerConfigurationException;
057: import javax.xml.transform.TransformerException;
058: import javax.xml.transform.TransformerFactory;
059: import javax.xml.transform.dom.DOMSource;
060: import javax.xml.transform.stream.StreamResult;
061: import javax.xml.transform.stream.StreamSource;
062:
063: import org.apache.log4j.Logger;
064: import org.w3c.dom.Document;
065: import org.w3c.dom.Element;
066:
067: import antlr.Token;
068: import antlr.TokenStreamException;
069: import biz.hammurapi.authorization.AuthorizationProvider;
070: import biz.hammurapi.config.Context;
071: import biz.hammurapi.web.ActionsBase;
072: import biz.hammurapi.web.HammurapiWebException;
073: import biz.hammurapi.web.RequestContext;
074: import biz.hammurapi.web.RequestParametersContext;
075: import biz.hammurapi.web.eval.EvaluationResult;
076: import biz.hammurapi.web.eval.EvaluatorFactory;
077: import biz.hammurapi.web.interaction.InteractionFactory;
078: import biz.hammurapi.web.interaction.InteractionInstance;
079: import biz.hammurapi.web.menu.matchers.MatchResult;
080: import biz.hammurapi.web.menu.matchers.MatchResultComparator;
081: import biz.hammurapi.web.menu.sql.MenuEngine;
082: import biz.hammurapi.web.security.AuthFilter;
083: import biz.hammurapi.web.security.User;
084: import biz.hammurapi.web.util.Escaper;
085: import biz.hammurapi.web.util.HTMLLexer;
086: import biz.hammurapi.web.util.HTMLTokenTypes;
087: import biz.hammurapi.xml.dom.AbstractDomObject;
088:
089: /**
090: * @author Pavel Vlasov
091: * @version $Revision: 1.2 $
092: */
093:
094: public class MenuFilter implements Filter {
095: public static final String CE_GLOBAL = "glbl";
096: private static final String STYLE_NONE = "none";
097: private static final String STYLE_TOOLTIP = "tooltip";
098: public static final String CT_FILTER = "Filter";
099: public static final String CT_HTML = "HTML";
100: public static final String CT_TOC = "Table Of Content";
101: private static final String UNMATCHED_REDIRECT = "unmatched-redirect";
102: private static final String UNMATCHED_MESSAGE = "unmatched-message";
103: private static final String UB_REDIRECT = "redirect";
104: private static final String UB_REDIRECT_TO_ROOT = "redirect-to-root";
105: private static final String UB_MESSAGE = "message";
106: private static final String UB_ERROR = "error";
107: private static final String UB_PASS_THROUGH = "pass-through";
108: private static final String UNMATCHED_BEHAVIOR = "unmatched-behavior";
109: private static final String STYLE_PARAMETER = "style-parameter";
110: private static final String DEFAULT_STYLE = "default-style";
111: private static final String TOC_STYLE = "toc-style";
112: private static final String STYLE_DIR = "style-dir";
113: public static final String MENU_ATTRIBUTE = Menu.class.getName();
114: public static final String MENU_MATCHED_ATTRIBUTE = Menu.class
115: .getName()
116: + ":MATCHED";
117: public static final String MENU_REDIRECT = Menu.class.getName()
118: + ":REDIRECT";
119:
120: private static Logger logger = Logger.getLogger(MenuFilter.class);
121:
122: private String styleDir; // directory where skin styles are stored.
123: private String defaultStyle; // style which is applied to response if style parameter is not set
124: private String tocStyle; // style which used to create table of content.
125: private String styleParameter; // parameter to get style name from. Style name doesn't contain .xsl suffix.
126: private String unmatchedBehavior; //- what to do if no menu items were matched. Possible values:
127: private String unmatchedMessage; // Error message to display in message mode.
128: private String unmatchedRedirect; // Redirect URL for <code>redirect</code> unmatched behavior.
129: private String rootMenuParameter;
130: private FilterConfig filterConfig;
131: private DocumentBuilder documentBuilder;
132: private TransformerFactory transformerFactory;
133: private String contentType;
134:
135: /**
136: * Init method for this filter
137: *
138: */
139: public void init(final FilterConfig filterConfig)
140: throws ServletException {
141: logger.info("Initializing menu filter "
142: + filterConfig.getFilterName());
143: this .filterConfig = filterConfig;
144:
145: styleDir = filterConfig.getInitParameter(STYLE_DIR); //- directory where skin styles are stored.
146: if (styleDir == null) {
147: throw new ServletException("Style directory is not set");
148: }
149:
150: defaultStyle = filterConfig.getInitParameter(DEFAULT_STYLE); //- style which is applied to response if style parameter is not set
151: if (defaultStyle == null) {
152: defaultStyle = "default";
153: }
154:
155: tocStyle = filterConfig.getInitParameter(TOC_STYLE); //- style which is applied to response if style parameter is not set
156: if (tocStyle == null) {
157: tocStyle = "toc";
158: }
159:
160: contentType = filterConfig.getInitParameter("content-type");
161: if (contentType == null) {
162: contentType = "text/html";
163: }
164:
165: rootMenuParameter = filterConfig
166: .getInitParameter("root-menu-parameter");
167:
168: styleParameter = filterConfig.getInitParameter(STYLE_PARAMETER); //- parameter to get style name from. Style name doesn't contain .xsl suffix.
169:
170: unmatchedBehavior = filterConfig
171: .getInitParameter(UNMATCHED_BEHAVIOR); //- what to do if no menu items were matched. Possible values:
172: if (unmatchedBehavior == null) {
173: unmatchedBehavior = UB_ERROR;
174: }
175:
176: if (UB_MESSAGE.equals(unmatchedBehavior)
177: || UB_ERROR.equals(unmatchedBehavior)) {
178: unmatchedMessage = filterConfig
179: .getInitParameter(UNMATCHED_MESSAGE);
180: if (unmatchedMessage == null) {
181: throw new ServletException(
182: "Unmatched message is not set");
183: }
184: } else if (UB_REDIRECT.equals(unmatchedBehavior)) {
185: unmatchedRedirect = filterConfig
186: .getInitParameter(UNMATCHED_REDIRECT);
187: if (unmatchedRedirect == null) {
188: throw new ServletException(
189: "Unmatched redirect is not set");
190: }
191: } else if (!UB_PASS_THROUGH.equals(unmatchedBehavior)
192: && !UB_REDIRECT_TO_ROOT.equals(unmatchedBehavior)) {
193: throw new ServletException("Invalid unmatched behavior: "
194: + unmatchedBehavior);
195: }
196:
197: try {
198: documentBuilder = DocumentBuilderFactory.newInstance()
199: .newDocumentBuilder();
200: } catch (ParserConfigurationException e) {
201: throw new ServletException("Could not start servlet: " + e,
202: e);
203: }
204:
205: transformerFactory = TransformerFactory.newInstance();
206:
207: filterConfig.getServletContext().setAttribute(
208: "filter/" + filterConfig.getFilterName(), this );
209: }
210:
211: /**
212: * @param request The servlet request we are processing
213: * @param result The servlet response we are creating
214: * @param chain The filter chain we are processing
215: *
216: * @exception IOException if an input/output error occurs
217: * @exception ServletException if a servlet error occurs
218: */
219: public void doFilter(ServletRequest request,
220: ServletResponse response, FilterChain chain)
221: throws IOException, ServletException {
222: logger.debug("MenuFilter:doFilter()");
223: if (request instanceof HttpServletRequest
224: && response instanceof HttpServletResponse) {
225: final HttpServletRequest httpRequest = (HttpServletRequest) request;
226: Menu menu = (Menu) request.getAttribute(MENU_ATTRIBUTE);
227: if (menu == null) {
228: menu = (Menu) httpRequest.getSession().getAttribute(
229: MENU_ATTRIBUTE);
230: }
231:
232: if (menu == null) {
233: chain.doFilter(request, response);
234: } else {
235: HttpServletResponse httpResponse = (HttpServletResponse) response;
236: logRequest(httpRequest);
237: List matches = menu.match(httpRequest);
238: if (matches.isEmpty()) {
239: String factualUnmatchedBehavior = unmatchedBehavior;
240: User user = (User) httpRequest.getSession()
241: .getAttribute(AuthFilter.USER);
242: if (user != null
243: && !ActionsBase.isBlank(user
244: .getUnmatchedBehavior())) {
245: factualUnmatchedBehavior = user
246: .getUnmatchedBehavior();
247: }
248: if (UB_REDIRECT.equals(factualUnmatchedBehavior)) {
249: setMenuRedirect(httpRequest);
250: httpResponse.sendRedirect(unmatchedRedirect);
251: } else if (UB_REDIRECT_TO_ROOT
252: .equals(factualUnmatchedBehavior)) {
253: setMenuRedirect(httpRequest);
254: httpResponse.sendRedirect(httpRequest
255: .getContextPath());
256: } else if (UB_ERROR
257: .equals(factualUnmatchedBehavior)) {
258: httpResponse.sendError(
259: HttpServletResponse.SC_FORBIDDEN,
260: unmatchedMessage);
261: } else if (STYLE_NONE.equals(httpRequest
262: .getParameter(styleParameter))) {
263: chain.doFilter(request, response);
264: } else {
265: render(menu, null, null, httpRequest,
266: httpResponse, chain);
267: }
268: } else {
269: Collections.sort(matches,
270: new MatchResultComparator());
271: MatchResult matchResult = (MatchResult) matches
272: .get(0);
273: Menu matched = (Menu) matchResult.getMatcher();
274: httpRequest.setAttribute(MENU_MATCHED_ATTRIBUTE,
275: matched);
276: httpRequest.getSession().setAttribute(
277: MENU_MATCHED_ATTRIBUTE, matched);
278: if (STYLE_NONE.equals(httpRequest
279: .getParameter(styleParameter))
280: && CT_FILTER.equals(matched
281: .getContentType())) {
282: chain.doFilter(request, response);
283: } else {
284: render(menu, matched, (String) matchResult
285: .getAttribute("type"), httpRequest,
286: httpResponse, chain);
287: }
288: }
289: }
290: } else {
291: chain.doFilter(request, response);
292: }
293: }
294:
295: private void setMenuRedirect(final HttpServletRequest httpRequest) {
296: StringBuffer requestURL = httpRequest.getRequestURL();
297: String queryString = httpRequest.getQueryString();
298: if (queryString != null) {
299: requestURL
300: .append(requestURL.indexOf("?") == -1 ? "?" : "&");
301: requestURL.append(queryString);
302: }
303: httpRequest.getSession().setAttribute(MENU_REDIRECT,
304: requestURL.toString());
305: }
306:
307: private void render(Menu root, final Menu matched,
308: String matchType, HttpServletRequest httpRequest,
309: HttpServletResponse httpResponse, FilterChain chain)
310: throws ServletException, IOException {
311: final RequestContext requestContext = new RequestContext(
312: httpRequest);
313: Context menuContext = new Context() {
314:
315: public Object get(String key) {
316: return matched == null ? requestContext.get(key)
317: : matched.get(key, requestContext);
318: }
319:
320: };
321:
322: Map evalContext = new HashMap();
323: httpRequest.setAttribute("evalContext", evalContext);
324:
325: Object runtimeEngine = matched == null ? null : matched
326: .getRuntimeEngine(httpRequest, httpResponse);
327: ClassLoader evalClassLoader = runtimeEngine == null ? this
328: .getClass().getClassLoader() : runtimeEngine.getClass()
329: .getClassLoader();
330: evalContext.put("requestContext", requestContext);
331: evalContext.put("parametersContext",
332: new RequestParametersContext(httpRequest));
333: if (matched != null) {
334: evalContext.put("menuContext", menuContext);
335: evalContext.put("menu", matched);
336: }
337:
338: if (runtimeEngine != null) {
339: evalContext.put("engine", runtimeEngine);
340: }
341: evalContext.put("request", httpRequest);
342: evalContext.put("response", httpResponse);
343: evalContext.put("converter", ActionsBase.converter);
344: Context global = (Context) httpRequest.getAttribute("global");
345: evalContext.put(CE_GLOBAL, global);
346: HttpSession session = httpRequest.getSession();
347: Object user = session.getAttribute(AuthFilter.USER);
348: if (user != null) {
349: evalContext.put("user", user);
350: }
351: Object authProvider = session
352: .getAttribute(AuthFilter.AUTHORIZATION_PROVIDER);
353: if (authProvider != null) {
354: evalContext.put("authorizationProvider", authProvider);
355: }
356:
357: evalContext.put("escaper", new Escaper());
358:
359: if (matched != null && "Interaction".equals(matched.getScope())) {
360: evalContext.put("interaction", null);
361: evalContext.put("interactionStep", null);
362: String idStr = httpRequest.getParameter("interaction");
363: if (idStr != null) {
364: InteractionFactory factory = (InteractionFactory) global
365: .get("db/InteractionFactory");
366: if (factory != null) {
367: try {
368: InteractionInstance instance = factory
369: .getInteractionInstance(Integer
370: .parseInt(idStr));
371: if (instance != null) {
372: evalContext.put("interaction", instance);
373: }
374:
375: String stepIdStr = httpRequest
376: .getParameter("interactionStep");
377: InteractionInstance.StepInstance step;
378: if (stepIdStr == null) {
379: step = instance
380: .getStepByStatus("processing");
381: } else {
382: step = instance.getStep(Integer
383: .parseInt(stepIdStr));
384: }
385:
386: if (step != null) {
387: evalContext.put("interactionStep", step);
388: }
389: } catch (SQLException e) {
390: throw new ServletException(e);
391: }
392: }
393: }
394: }
395: EvaluatorFactory eFactory = (EvaluatorFactory) (global == null ? null
396: : global.get("db/EvaluatorFactory"));
397:
398: Document doc = newDocument();
399: Element rootElement = AbstractDomObject.addElement(doc,
400: "response");
401: String contextPath = httpRequest.getContextPath();
402: if (contextPath != null) {
403: if ("/".equals(contextPath)) {
404: contextPath = "";
405: } else if (contextPath.endsWith("/")) {
406: contextPath = contextPath.substring(0, contextPath
407: .length() - 1);
408: }
409: rootElement.setAttribute("context-path", contextPath);
410: }
411: Element menuElement = AbstractDomObject.addElement(rootElement,
412: "menu");
413: root.toDom(menuElement, httpRequest);
414: if (matched != null) {
415: Element matchPath = AbstractDomObject.addElement(
416: rootElement, "match-path");
417: if (matched.hasHelp()) {
418: matchPath.setAttribute("has-help", "yes");
419: }
420: for (int i = 0; i < matched.getPath().length; ++i) {
421: Element match = AbstractDomObject.addTextElement(
422: matchPath, "match", matched.getPath()[i]
423: .getName());
424: match.setAttribute("id", String.valueOf(matched
425: .getPath()[i].getId()));
426: match.setAttribute("type", matched.getPath()[i]
427: .getType());
428: match.setAttribute("scope", matched.getScope());
429: String href = (String) matched.getPath()[i].get("href",
430: requestContext);
431: if (href != null) {
432: match.setAttribute("href", href);
433: }
434: }
435: }
436:
437: Element requestElement = AbstractDomObject.addElement(
438: rootElement, "request");
439: setAttribute(requestElement, "character-encoding", httpRequest
440: .getCharacterEncoding());
441: setAttribute(requestElement, "content-type", httpRequest
442: .getContentType());
443:
444: Enumeration pEnum = httpRequest.getParameterNames();
445: while (pEnum != null && pEnum.hasMoreElements()) {
446: String pName = (String) pEnum.nextElement();
447: String[] pValues = httpRequest.getParameterValues(pName);
448: if (pValues != null) {
449: for (int i = 0; i < pValues.length; ++i) {
450: Element pe = AbstractDomObject.addTextElement(
451: requestElement, "parameter", pValues[i]);
452: pe.setAttribute("name", pName);
453: }
454: }
455: }
456:
457: setAttribute(requestElement, "context-path", httpRequest
458: .getContextPath());
459:
460: Enumeration hEnum = httpRequest.getHeaderNames();
461: while (hEnum != null && hEnum.hasMoreElements()) {
462: String hName = (String) hEnum.nextElement();
463: Enumeration hValues = httpRequest.getHeaders(hName);
464: while (hValues != null && hValues.hasMoreElements()) {
465: Element he = AbstractDomObject.addTextElement(
466: requestElement, "header", (String) hValues
467: .nextElement());
468: he.setAttribute("name", hName);
469: }
470: }
471:
472: setAttribute(requestElement, "method", httpRequest.getMethod());
473: setAttribute(requestElement, "path-info", httpRequest
474: .getPathInfo());
475: setAttribute(requestElement, "path-translated", httpRequest
476: .getPathTranslated());
477: setAttribute(requestElement, "query-string", httpRequest
478: .getQueryString());
479: setAttribute(requestElement, "request-uri", httpRequest
480: .getRequestURI());
481: setAttribute(requestElement, "servlet-path", httpRequest
482: .getServletPath());
483:
484: // httpResponse.setDateHeader("Expires", 0);
485: // httpResponse.setDateHeader("Last-Modified", System.currentTimeMillis());
486:
487: String matchContentType;
488: if (matched == null) {
489: matchContentType = CT_FILTER;
490: } else if (Menu.MT_RESOURCE.equals(matchType)) {
491: matchContentType = CT_FILTER;
492: } else if (Menu.MT_ROOT.equals(matchType)) {
493: matchContentType = matched.getContentType();
494: } else if (Menu.MT_FORM_HANDLER.equals(matchType)) {
495: matchContentType = matched.getFormHandlerType();
496: } else {
497: throw new ServletException("Unknown match type: "
498: + matchType);
499: }
500:
501: EvaluationResult matchHandlerEvaluationResult = null;
502: if (matched != null && Menu.MT_ROOT.equals(matchType)
503: && matched.getMatchHandler() != null
504: && matched.getMatchHandler().trim().length() > 0) {
505: if (eFactory == null) {
506: throw new ServletException(
507: "Cannot evaluate match handler, evaluator factory not found");
508: }
509: try {
510: matchHandlerEvaluationResult = eFactory.evaluate(
511: "Java", matched.getMatchHandler(), "Menu "
512: + matched.getId() + " match handler",
513: evalContext, evalClassLoader);
514: } catch (HammurapiWebException e) {
515: logger.error(e);
516: exceptionToBody(e, rootElement);
517: matchHandlerEvaluationResult = new EvaluationResult() {
518:
519: public String getOutput() {
520: return "";
521: }
522:
523: public Object getResult() {
524: return Boolean.FALSE;
525: }
526:
527: };
528: }
529: }
530:
531: String output = null;
532: String body = null;
533: if (matchHandlerEvaluationResult != null
534: && Boolean.FALSE.equals(matchHandlerEvaluationResult
535: .getResult())) {
536: output = matchHandlerEvaluationResult.getOutput();
537: } else {
538: if (matchHandlerEvaluationResult != null
539: && matchHandlerEvaluationResult.getResult() != null) {
540: evalContext.put("result", matchHandlerEvaluationResult
541: .getResult());
542: }
543:
544: String matchHandlerOutput = matchHandlerEvaluationResult == null ? ""
545: : matchHandlerEvaluationResult.getOutput();
546:
547: if (matched == null && UB_MESSAGE.equals(unmatchedBehavior)) {
548: body = unmatchedMessage;
549: } else if (CT_FILTER.equals(matchContentType)) {
550: ResponseWrapper wrappedResponse = new ResponseWrapper(
551: httpResponse);
552: chain.doFilter(httpRequest, wrappedResponse);
553: output = matchHandlerOutput
554: + wrappedResponse.getResponseString();
555: } else if (CT_HTML.equals(matchContentType)) {
556: output = matchHandlerOutput + matched.getContent();
557: } else if (CT_TOC.equals(matchContentType)) {
558: StringWriter sw = new StringWriter();
559: try {
560: Transformer transformer = getTemplates(tocStyle)
561: .newTransformer();
562: transformer.transform(new DOMSource(doc),
563: new StreamResult(sw));
564: } catch (TransformerConfigurationException e) {
565: sw.write("<PRE>");
566: e.printStackTrace(new PrintWriter(sw));
567: sw.write("</PRE>");
568: } catch (TransformerException e) {
569: sw.write("<PRE>");
570: e.printStackTrace(new PrintWriter(sw));
571: sw.write("</PRE>");
572: }
573: sw.close();
574: output = matchHandlerOutput + sw.toString();
575: } else {
576: if (eFactory == null) {
577: body = "Cannot evaluate content, evaluator factory is not found";
578: } else {
579: String source;
580: if (Menu.MT_ROOT.equals(matchType)) {
581: source = matched.getContent();
582: } else if (Menu.MT_FORM_HANDLER.equals(matchType)) {
583: source = matched.getFormHandlerCode();
584: } else {
585: throw new ServletException(
586: "Unknown match type: " + matchType);
587: }
588: try {
589: EvaluationResult er = eFactory.evaluate(
590: matchContentType, source, "Menu "
591: + matched.getId() + " "
592: + matchType, evalContext,
593: evalClassLoader);
594: output = matchHandlerOutput + er.getOutput();
595: } catch (HammurapiWebException e) {
596: logger.error(e);
597: exceptionToBody(e, rootElement);
598: }
599: }
600: }
601: }
602:
603: String style = httpRequest.getParameter(styleParameter);
604: if (STYLE_TOOLTIP.equals(style)) {
605: if (output != null) {
606: httpResponse.getWriter().write(asTooltip(output));
607: } else if (body != null) {
608: httpResponse.getWriter().write(asTooltip(body));
609: }
610: } else if (STYLE_NONE.equals(style)) {
611: if (output != null) {
612: httpResponse.getWriter().write(output);
613: } else if (body != null) {
614: httpResponse.getWriter().write(body);
615: }
616: } else {
617: if (output != null) {
618: HTML html = new HTML(output);
619: if (html.getHead() != null) {
620: AbstractDomObject.addTextElement(rootElement,
621: "head", html.getHead());
622: }
623: if (html.getBody() != null) {
624: AbstractDomObject.addTextElement(rootElement,
625: "body", html.getBody());
626: }
627: } else if (body != null) {
628: AbstractDomObject.addTextElement(rootElement, "body",
629: body);
630: }
631:
632: try {
633: boolean bareXml = "barexml".equals(style);
634: httpResponse.setContentType(bareXml ? "text/xml"
635: : contentType);
636: Transformer transformer = bareXml ? transformerFactory
637: .newTransformer() : getTemplates(
638: styleParameter == null ? null : style)
639: .newTransformer();
640: // DOMUtils.serialize(doc, new File("C:\\debug.xml"));
641: transformer.transform(new DOMSource(doc),
642: new StreamResult(httpResponse.getWriter()));
643: } catch (TransformerConfigurationException e) {
644: throw new ServletException(
645: "Could not apply style to response: " + e, e);
646: } catch (TransformerException e) {
647: throw new ServletException(
648: "Could not apply style to response: " + e, e);
649: }
650: }
651: }
652:
653: private String asTooltip(String content) {
654: int maxTooltipLength = 1000;
655:
656: int idx = content.indexOf("<tooltipEnd/>");
657: if (idx != -1) {
658: return content.substring(0, idx) + Help.ELLIPSIS;
659: }
660:
661: if (content.length() <= maxTooltipLength) {
662: return content;
663: }
664:
665: // Paragraph detection.
666: Token lastPARA = null;
667: List tokenChain = new ArrayList();
668: HTMLLexer lexer = new HTMLLexer(new StringReader(content));
669: int textcounter = 0; // To protect against infinite loops.
670: try {
671: for (Token t = lexer.nextToken(); t != null
672: && t.getType() != HTMLTokenTypes.CHTML
673: && t.getType() != HTMLTokenTypes.EOF; t = lexer
674: .nextToken()) {
675: tokenChain.add(t);
676: if (t.getText() != null
677: && ((t.getType() == HTMLTokenTypes.UNDEFINED_TOKEN && t
678: .getText().length() == 1) || t
679: .getType() == HTMLTokenTypes.PCDATA)) {
680: textcounter += t.getText().length();
681: if (textcounter >= maxTooltipLength) {
682: tokenChain.add(new Token(
683: HTMLTokenTypes.UNDEFINED_TOKEN,
684: Help.ELLIPSIS));
685: break;
686: }
687: }
688:
689: switch (t.getType()) {
690: case HTMLTokenTypes.OPARA:
691: case HTMLTokenTypes.CPARA:
692: case HTMLTokenTypes.SAPARA:
693: lastPARA = t;
694: break;
695: }
696: }
697: } catch (TokenStreamException e) {
698: return content.substring(0, maxTooltipLength)
699: + Help.ELLIPSIS;
700: }
701:
702: if (lastPARA != null) {
703: StringBuffer rsb = new StringBuffer();
704: Iterator it = tokenChain.iterator();
705: while (it.hasNext()) {
706: Token t = (Token) it.next();
707: if (t == lastPARA) {
708: if (rsb.toString().trim().length() < 100) {
709: break;
710: }
711: rsb.append(Help.ELLIPSIS);
712: return rsb.toString();
713: }
714: rsb.append(t.getText());
715: }
716: }
717:
718: StringBuffer rsb = new StringBuffer();
719: Iterator it = tokenChain.iterator();
720: while (it.hasNext()) {
721: Token t = (Token) it.next();
722: rsb.append(t.getText());
723: }
724: return rsb.toString();
725: }
726:
727: private void exceptionToBody(Throwable e, Element rootElement)
728: throws IOException {
729: StringWriter sw = new StringWriter();
730: PrintWriter pw = new PrintWriter(sw);
731: e.printStackTrace(pw);
732: pw.close();
733: sw.close();
734: AbstractDomObject.addTextElement(rootElement, "body",
735: "<H1>Exception</H1><pre>" + sw.toString() + "</pre>");
736: }
737:
738: private Document newDocument() {
739: synchronized (documentBuilder) {
740: return documentBuilder.newDocument();
741: }
742: }
743:
744: /**
745: * Sets attribute if value is not null.
746: * @param holder
747: * @param name
748: * @param value
749: */
750: private void setAttribute(Element holder, String name, String value) {
751: if (value != null) {
752: holder.setAttribute(name, value);
753: }
754: }
755:
756: private Templates getTemplates(String style)
757: throws ServletException {
758: String actualStyle = style == null ? defaultStyle : style;
759: synchronized (templates) {
760: Templates ret = (Templates) templates.get(actualStyle);
761: if (ret == null) {
762: InputStream is = filterConfig.getServletContext()
763: .getResourceAsStream(
764: styleDir + "/" + actualStyle + ".xsl");
765: if (is == null) {
766: throw new ServletException(
767: "Stylesheet not found for style "
768: + actualStyle);
769: }
770:
771: Source source = new StreamSource(is);
772: try {
773: ret = transformerFactory.newTemplates(source);
774: } catch (TransformerConfigurationException e) {
775: throw new ServletException("Could not load style "
776: + actualStyle + ": " + e, e);
777: }
778:
779: templates.put(actualStyle, ret);
780: }
781: return ret;
782: }
783: }
784:
785: /**
786: * Return the filter configuration object for this filter.
787: */
788: public FilterConfig getFilterConfig() {
789: return (this .filterConfig);
790: }
791:
792: /**
793: * Set the filter configuration object for this filter.
794: *
795: * @param filterConfig The filter configuration object
796: */
797: public void setFilterConfig(FilterConfig filterConfig) {
798: this .filterConfig = filterConfig;
799: }
800:
801: /**
802: * Destroy method for this filter
803: *
804: */
805: public void destroy() {
806: // Nothing
807: }
808:
809: /**
810: * Return a String representation of this object.
811: */
812: public String toString() {
813: if (filterConfig == null) {
814: return ("MenuFilter()");
815: }
816: StringBuffer sb = new StringBuffer("MenuFilter(");
817: sb.append(filterConfig);
818: sb.append(")");
819: return (sb.toString());
820:
821: }
822:
823: public static void logRequest(HttpServletRequest request) {
824: if (!logger.isDebugEnabled()) {
825: return;
826: }
827:
828: logger.debug("URI: " + request.getRequestURI());
829: logger.debug("Context path: " + request.getContextPath());
830:
831: logger.debug("Request parameters:");
832: Enumeration enm = request.getParameterNames();
833: while (enm.hasMoreElements()) {
834: String param = (String) enm.nextElement();
835: logger.debug("\t" + param + "="
836: + request.getParameter(param));
837: }
838:
839: logger.debug("Request attributes:");
840: enm = request.getAttributeNames();
841: while (enm.hasMoreElements()) {
842: String attribute = (String) enm.nextElement();
843: logger.debug("\t"
844: + attribute
845: + "= ["
846: + request.getAttribute(attribute).getClass()
847: .getName() + "] "
848: + request.getAttribute(attribute));
849: }
850:
851: logger.debug("Session attributes:");
852: enm = request.getSession().getAttributeNames();
853: while (enm.hasMoreElements()) {
854: String attribute = (String) enm.nextElement();
855: logger.debug("\t"
856: + attribute
857: + "= ["
858: + request.getSession().getAttribute(attribute)
859: .getClass().getName() + "] "
860: + request.getSession().getAttribute(attribute));
861: }
862: /*
863: logger.debug("Context attributes:");
864: enum=filterConfig.getServletContext().getAttributeNames();
865: while (enum.hasMoreElements()) {
866: String attribute=(String) enum.nextElement();
867: logger.debug("\t"+attribute+"= ["+filterConfig.getServletContext().getAttribute(attribute).getClass().getName()+"] "+filterConfig.getServletContext().getAttribute(attribute));
868: }
869: */
870: }
871:
872: private Map templates = new HashMap();
873:
874: /**
875: * Builds menu
876: * @param request
877: * @return true if menu was built and started or if menu is not defined in the configuration.
878: * @throws HammurapiWebException
879: */
880: public boolean buildMenu(HttpServletRequest request)
881: throws HammurapiWebException {
882: Context global = ((Context) request.getAttribute("global"));
883: String menuId = (String) global.get("db/menu");
884: boolean fromParameter = false;
885: if (rootMenuParameter != null) {
886: String mid = request.getParameter(rootMenuParameter);
887: if (mid != null) {
888: menuId = mid;
889: fromParameter = true;
890: }
891: }
892:
893: if (menuId == null) {
894: return true;
895: }
896:
897: MenuEngine engine = (MenuEngine) global.get("db/MenuEngine");
898: try {
899: HttpSession session = request.getSession();
900: User user = (User) session.getAttribute(AuthFilter.USER);
901: Menu menu;
902: if (!fromParameter && user != null
903: && user.getMenuId() != null) {
904: menu = (Menu) engine.getXmenu(user.getMenuId()
905: .intValue(), Menu.class);
906: } else {
907: Collection xmenuXidEQ = engine.getXmenuXidEQ(menuId,
908: new ArrayList(), Menu.class);
909: menu = xmenuXidEQ.isEmpty() ? null : (Menu) xmenuXidEQ
910: .iterator().next();
911: }
912: if (menu == null) {
913: return false;
914: }
915: if (menu.start((AuthorizationProvider) session
916: .getAttribute(AuthFilter.AUTHORIZATION_PROVIDER),
917: global)) {
918: session.setAttribute(MENU_ATTRIBUTE, menu);
919: return true;
920: }
921: return false;
922: } catch (SQLException e) {
923: throw new HammurapiWebException(
924: "Could not load menu: " + e, e);
925: }
926: }
927:
928: }
|