001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.velocity;
018:
019: import java.io.File;
020: import java.util.Locale;
021: import java.util.Map;
022:
023: import javax.portlet.PortletConfig;
024: import javax.portlet.PortletMode;
025: import javax.portlet.PortletRequest;
026: import javax.portlet.RenderRequest;
027: import javax.portlet.RenderResponse;
028: import javax.portlet.WindowState;
029: import javax.servlet.ServletConfig;
030: import javax.servlet.ServletException;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.apache.commons.collections.ExtendedProperties;
035: import org.apache.commons.collections.map.LRUMap;
036: import org.apache.commons.configuration.Configuration;
037: import org.apache.commons.configuration.ConfigurationException;
038: import org.apache.commons.configuration.PropertiesConfiguration;
039: import org.apache.commons.logging.Log;
040: import org.apache.commons.logging.LogFactory;
041: import org.apache.jetspeed.Jetspeed;
042: import org.apache.jetspeed.PortalReservedParameters;
043: import org.apache.jetspeed.capabilities.CapabilityMap;
044: import org.apache.jetspeed.components.ComponentManager;
045: import org.apache.jetspeed.desktop.JetspeedDesktopContext;
046: import org.apache.jetspeed.locator.LocatorDescriptor;
047: import org.apache.jetspeed.locator.TemplateDescriptor;
048: import org.apache.jetspeed.locator.TemplateLocator;
049: import org.apache.jetspeed.locator.TemplateLocatorException;
050: import org.apache.jetspeed.om.page.Fragment;
051: import org.apache.jetspeed.om.page.Page;
052: import org.apache.jetspeed.request.RequestContext;
053: import org.apache.pluto.Constants;
054: import org.apache.portals.bridges.velocity.BridgesVelocityViewServlet;
055: import org.apache.velocity.Template;
056: import org.apache.velocity.app.VelocityEngine;
057: import org.apache.velocity.app.event.EventCartridge;
058: import org.apache.velocity.app.event.NullSetEventHandler;
059: import org.apache.velocity.context.Context;
060: import org.apache.velocity.exception.ParseErrorException;
061: import org.apache.velocity.exception.ResourceNotFoundException;
062: import org.apache.velocity.runtime.RuntimeConstants;
063: import org.apache.velocity.tools.generic.log.LogSystemCommonsLog;
064: import org.apache.velocity.tools.view.servlet.WebappLoader;
065:
066: /**
067: * @version $Id: JetspeedVelocityViewServlet.java 550655 2007-06-26 01:41:35Z taylor $
068: */
069: public class JetspeedVelocityViewServlet extends
070: BridgesVelocityViewServlet {
071: /** logging */
072: private static final Log log = LogFactory
073: .getLog(JetspeedVelocityViewServlet.class);
074:
075: /** default cache size */
076: private static final long DEFAULT_CACHE_SIZE = 50;
077:
078: /** default cache validation interval */
079: private static final String CACHE_SIZE_PARAMETER = "org.apache.jetspeed.cache.size";
080:
081: /** default cache validation interval */
082: private static final long DEFAULT_CACHE_VALIDATION_INTERVAL = 10000;
083:
084: /** default cache validation interval */
085: private static final String CACHE_VALIDATION_INTERVAL_PARAMETER = "org.apache.jetspeed.cache.validation.interval";
086:
087: /** TLS for Context propagation */
088: private static ThreadLocal handlingRequestContext = new ThreadLocal();
089:
090: /** decoration locators */
091: private TemplateLocator decorationLocator;
092:
093: /** velocity engine configuration caching object */
094: private class VelocityEngineConfig {
095: public String decoration;
096: public String type;
097: public String mediaType;
098: public String language;
099: public String country;
100:
101: public File macros;
102: public long macrosLastModified;
103: public long lastValidated;
104:
105: public VelocityEngineConfig(String decoration, String type,
106: String mediaType, String language, String country) {
107: this .decoration = decoration;
108: this .type = type;
109: this .mediaType = mediaType;
110: this .language = language;
111: this .country = country;
112:
113: this .macrosLastModified = -1;
114: this .lastValidated = System.currentTimeMillis();
115: }
116: }
117:
118: /** VelocityEngine configuration cache by decoration */
119: private Map velocityEngineConfigCache;
120:
121: /** VelocityEngine cache by macros locators */
122: private Map velocityEngineCache;
123:
124: /** cache validation interval */
125: private long cacheValidationInterval;
126:
127: /** default velocity engine */
128: private VelocityEngine defaultVelocityEngine;
129:
130: /** Velocity EventCartridge for handling event */
131: EventCartridge eventCartridge;
132:
133: /**
134: * Initialize servlet, BridgesVelocityViewServlet, and VelocityViewServlet.
135: *
136: * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet.init()
137: *
138: * @param config servlet configuation
139: */
140: public void init(ServletConfig config) throws ServletException {
141: // initialize
142: super .init(config);
143:
144: // get jetspeed component manager configuration for decorations
145: ComponentManager cm = Jetspeed.getComponentManager();
146: int count = 0;
147: while (cm == null) {
148: try {
149: Thread.sleep(200);
150: } catch (InterruptedException ie) {
151:
152: }
153: cm = Jetspeed.getComponentManager();
154: if (count > 5) {
155: if (null == cm)
156: throw new ServletException(
157: "Could not get Jetspeed Component Manager after "
158: + count + "tries");
159: }
160: count++;
161:
162: }
163: decorationLocator = (TemplateLocator) cm
164: .getComponent("DecorationLocator");
165:
166: // initialize thread safe velocity engine cache
167: int cacheSize = (int) getLongInitParameter(config,
168: CACHE_SIZE_PARAMETER, DEFAULT_CACHE_SIZE);
169: velocityEngineConfigCache = new LRUMap(cacheSize);
170: velocityEngineCache = new LRUMap(cacheSize / 2);
171:
172: eventCartridge = new EventCartridge();
173: // setup NullSetEventHandler to ignore those pesky "ERROR velocity - RHS of #set statement is null. Context will not be modified."
174: eventCartridge.addEventHandler(new NullSetEventHandler() {
175: public boolean shouldLogOnNullSet(String lhs, String rhs) {
176: return false;
177: }
178: });
179:
180: // initialize velocity engine cache validation interval
181: cacheValidationInterval = getLongInitParameter(config,
182: CACHE_VALIDATION_INTERVAL_PARAMETER,
183: DEFAULT_CACHE_VALIDATION_INTERVAL);
184: }
185:
186: /**
187: * overriding VelocityViewServlet initialization of global Velocity to properly provide our own velocity.properties
188: * so to prevent an ERROR logging for not finding the default global VM_global_library.vm (which isn't available).
189: */
190: protected void initVelocity(ServletConfig config)
191: throws ServletException {
192: VelocityEngine velocity = new VelocityEngine();
193: setVelocityEngine(velocity);
194:
195: // register this engine to be the default handler of log messages
196: // if the user points commons-logging to the LogSystemCommonsLog
197: LogSystemCommonsLog.setVelocityEngine(velocity);
198:
199: velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY,
200: getServletContext());
201:
202: // default to servletlogger, which logs to the servlet engines log
203: velocity.setProperty(
204: RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
205: "org.apache.velocity.tools.view.servlet.ServletLogger");
206:
207: // by default, load resources with webapp resource loader
208: velocity
209: .setProperty(RuntimeConstants.RESOURCE_LOADER, "webapp");
210: velocity.setProperty("webapp.resource.loader.class",
211: WebappLoader.class.getName());
212:
213: // Try reading an overriding Velocity configuration
214: try {
215: ExtendedProperties p = loadConfiguration(config);
216: p.addProperty("velocimacro.library",
217: "/WEB-INF/jetspeed_macros.vm");
218: p.setProperty("file.resource.loader.path",
219: getServletContext().getRealPath("/"));
220: velocity.setExtendedProperties(p);
221: } catch (Exception e) {
222: getServletContext().log(
223: "VelocityViewServlet: Unable to read Velocity configuration file: "
224: + e);
225: getServletContext()
226: .log(
227: "VelocityViewServlet: Using default Velocity configuration.");
228: }
229:
230: // now all is ready - init Velocity
231: try {
232: velocity.init();
233: } catch (Exception e) {
234: getServletContext().log(
235: "VelocityViewServlet: PANIC! unable to init() - "
236: + e);
237: throw new ServletException(e);
238: }
239: }
240:
241: /**
242: * Handle the template processing request.
243: *
244: * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet.handleRequest()
245: *
246: * @param request client request
247: * @param response client response
248: * @param ctx VelocityContext to fill
249: * @return Velocity Template object or null
250: */
251: protected Template handleRequest(HttpServletRequest request,
252: HttpServletResponse response, Context ctx) throws Exception {
253: RequestContext requestContext = (RequestContext) request
254: .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
255: if (requestContext == null) {
256: throw new IllegalStateException(
257: "JetspeedVelocityViewServlet unable to handle request because there is no RequestContext in "
258: + "the HttpServletRequest.");
259: }
260:
261: // hook up eventHandlers to the context, specifically our own IgnoringNullSetEventHandling
262: eventCartridge.attachToContext(ctx);
263:
264: JetspeedDesktopContext desktopContext = (JetspeedDesktopContext) request
265: .getAttribute(JetspeedDesktopContext.DESKTOP_CONTEXT_ATTRIBUTE);
266: if (desktopContext != null) {
267: // standard render request and response also available in context
268: ctx.put(JetspeedDesktopContext.DESKTOP_CONTEXT_ATTRIBUTE,
269: desktopContext);
270: ctx.put("JS2RequestContext", requestContext);
271:
272: // setup TLS for Context propagation
273: handlingRequestContext.set(ctx);
274: return super .handleRequest(request, response, ctx);
275: }
276: // configure velocity context
277: PortletRequest renderRequest = (PortletRequest) request
278: .getAttribute(Constants.PORTLET_REQUEST);
279: RenderResponse renderResponse = (RenderResponse) request
280: .getAttribute(Constants.PORTLET_RESPONSE);
281: PortletConfig portletConfig = (PortletConfig) request
282: .getAttribute(Constants.PORTLET_CONFIG);
283: if (renderRequest != null) {
284: renderRequest.setAttribute(VELOCITY_CONTEXT_ATTR, ctx);
285: }
286:
287: JetspeedVelocityPowerTool jpt = (JetspeedVelocityPowerTool) renderRequest
288: .getAttribute(PortalReservedParameters.JETSPEED_POWER_TOOL_REQ_ATTRIBUTE);
289: if (jpt == null) {
290: throw new IllegalStateException(
291: "JetspeedVelocityViewServlet unable to handle request because there is no JetspeedPowerTool in "
292: + "the HttpServletRequest.");
293: }
294:
295: jpt.setVelocityContext(ctx);
296: ctx.put("jetspeed", jpt);
297: ctx.put("JS2RequestContext", requestContext);
298: ctx.put("renderRequest", renderRequest);
299: ctx.put("renderResponse", renderResponse);
300: ctx.put("portletConfig", portletConfig);
301: ctx.put("portletModeView", PortletMode.VIEW);
302: ctx.put("portletModeEdit", PortletMode.EDIT);
303: ctx.put("portletModeHelp", PortletMode.HELP);
304: ctx.put("windowStateNormal", WindowState.NORMAL);
305: ctx.put("windowStateMinimized", WindowState.MINIMIZED);
306: ctx.put("windowStateMaximized", WindowState.MAXIMIZED);
307: ctx.put("rco", requestContext.getObjects());
308: StringBuffer appRoot = new StringBuffer();
309: if (!requestContext.getPortalURL().isRelativeOnly()) {
310: appRoot.append(request.getScheme()).append("://").append(
311: request.getServerName()).append(":").append(
312: request.getServerPort());
313: }
314: appRoot.append(renderRequest.getContextPath());
315: ctx.put("appRoot", appRoot.toString());
316:
317: // setup TLS for Context propagation
318: handlingRequestContext.set(ctx);
319:
320: // handle request normally
321: return super .handleRequest(request, response, ctx);
322: }
323:
324: /**
325: * Retrieves the requested template.
326: *
327: * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet.getTemplate()
328: *
329: * @param name The file name of the template to retrieve relative to the template root.
330: * @return The requested template.
331: * @throws ResourceNotFoundException if template not found from any available source.
332: * @throws ParseErrorException if template cannot be parsed due to syntax (or other) error.
333: * @throws Exception if an error occurs in template initialization
334: */
335: public Template getTemplate(String name)
336: throws ResourceNotFoundException, ParseErrorException,
337: Exception {
338: // retrieve Context to lookup appropriate velocity engine
339: Context ctx = (Context) handlingRequestContext.get();
340: if (ctx != null) {
341: // create or lookup cached velocity engine
342: VelocityEngine velocity = getVelocityEngine(ctx);
343: if (velocity != null) {
344: // get template from velocity engine
345: return velocity.getTemplate(name);
346: }
347: }
348:
349: // no velocity engine available
350: throw new Exception(
351: "No velocity engine available for request context.");
352: }
353:
354: /**
355: * Retrieves the requested template with the specified character encoding.
356: *
357: * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet.getTemplate()
358: *
359: * @param name The file name of the template to retrieve relative to the template root.
360: * @param encoding the character encoding of the template
361: * @return The requested template.
362: * @throws ResourceNotFoundException if template not found from any available source.
363: * @throws ParseErrorException if template cannot be parsed due to syntax (or other) error.
364: * @throws Exception if an error occurs in template initialization
365: */
366: public Template getTemplate(String name, String encoding)
367: throws ResourceNotFoundException, ParseErrorException,
368: Exception {
369: // retrieve Context to lookup appropriate velocity engine
370: Context ctx = (Context) handlingRequestContext.get();
371: if (ctx != null) {
372: // create or lookup cached velocity engine
373: VelocityEngine velocity = getVelocityEngine(ctx);
374: if (velocity != null) {
375: // get template from velocity engine
376: return velocity.getTemplate(name, encoding);
377: }
378: }
379:
380: // no velocity engine available
381: throw new Exception(
382: "No velocity engine available for request context.");
383: }
384:
385: /**
386: * Get VelocityEngine for template access.
387: *
388: * @param ctx the velocity context.
389: * @return The VelocityEngine or null.
390: */
391: private VelocityEngine getVelocityEngine(Context ctx) {
392: RequestContext requestContext = (RequestContext) ctx
393: .get("JS2RequestContext");
394: JetspeedDesktopContext desktopContext = (JetspeedDesktopContext) requestContext
395: .getRequest()
396: .getAttribute(
397: JetspeedDesktopContext.DESKTOP_CONTEXT_ATTRIBUTE);
398: if (desktopContext != null) {
399: if (defaultVelocityEngine == null) {
400: defaultVelocityEngine = initVelocity((TemplateDescriptor) null);
401: }
402: return defaultVelocityEngine;
403: }
404: // get render request and request context from Context
405: RenderRequest renderRequest = (RenderRequest) ctx
406: .get("renderRequest");
407: JetspeedVelocityPowerTool jpt = (JetspeedVelocityPowerTool) ctx
408: .get("jetspeed");
409: if ((renderRequest != null) && (requestContext != null)) {
410: // get layout type and decoration, fallback to
411: // page default decorations
412: Fragment layout = (Fragment) renderRequest
413: .getAttribute(JetspeedVelocityPowerTool.LAYOUT_ATTR);
414: if (layout == null) {
415: // layout = (Fragment) renderRequest.getAttribute(JetspeedPowerTool.FRAGMENT_ATTR);
416: layout = jpt.getCurrentFragment();
417: }
418: String layoutType = layout.getType();
419: String layoutDecoration = layout.getDecorator();
420: if (layoutDecoration == null) {
421: //Page page = (Page) renderRequest.getAttribute(PortalReservedParameters.PAGE_ATTRIBUTE_KEY);
422: Page page = requestContext.getPage();
423: layoutDecoration = page
424: .getEffectiveDefaultDecorator(layoutType);
425: }
426:
427: // get layout capabilites and locale
428: CapabilityMap capabilityMap = requestContext
429: .getCapabilityMap();
430: Locale locale = requestContext.getLocale();
431: String layoutMediaType = capabilityMap
432: .getPreferredMediaType().getName();
433: String layoutLanguage = locale.getLanguage();
434: String layoutCountry = locale.getCountry();
435:
436: // lookup cache config based on decoration cache key
437: String cacheKey = layoutDecoration + ":" + layoutType + ":"
438: + layoutMediaType + ":" + layoutLanguage + ":"
439: + layoutCountry;
440: VelocityEngineConfig config = null;
441: synchronized (velocityEngineConfigCache) {
442: config = (VelocityEngineConfig) velocityEngineConfigCache
443: .get(cacheKey);
444: }
445:
446: // validate cached configuration and return VelocityEngine if cached
447: long now = System.currentTimeMillis();
448: if ((config != null)
449: && ((cacheValidationInterval == -1) || (now <= (config.lastValidated + cacheValidationInterval)))) {
450: if (config.macros != null) {
451: synchronized (velocityEngineCache) {
452: // use cached velocity engine if available
453: VelocityEngine velocity = (VelocityEngine) velocityEngineCache
454: .get(config.macros.getAbsolutePath());
455: if (velocity != null) {
456: return velocity;
457: }
458: }
459: } else {
460: // use default velocity engine
461: synchronized (this ) {
462: // construct and cache default velocity engine
463: if (defaultVelocityEngine == null) {
464: defaultVelocityEngine = initVelocity((TemplateDescriptor) null);
465: }
466: return defaultVelocityEngine;
467: }
468: }
469: }
470:
471: // load and/or verify decorator macros configuration
472: TemplateDescriptor macrosDescriptor = null;
473:
474: // create reusable decoration base descriptor
475: LocatorDescriptor descriptor = null;
476: try {
477: descriptor = decorationLocator
478: .createLocatorDescriptor(null);
479: } catch (TemplateLocatorException tle) {
480: log
481: .error(
482: "getVelocityEngine(): unable create base descriptor",
483: tle);
484: }
485: descriptor.setMediaType(layoutMediaType);
486: descriptor.setCountry(layoutCountry);
487: descriptor.setLanguage(layoutLanguage);
488: descriptor.setType(layoutType);
489:
490: // get decoration configuration properties descriptor
491: descriptor.setName(layoutDecoration + "/"
492: + JetspeedVelocityPowerTool.DECORATOR_TYPE
493: + ".properties");
494: TemplateDescriptor propertiesDescriptor = null;
495: try {
496: propertiesDescriptor = decorationLocator
497: .locateTemplate(descriptor);
498: } catch (TemplateLocatorException tle) {
499: // fallback to generic template type
500: try {
501: descriptor
502: .setType(JetspeedVelocityPowerTool.GENERIC_TEMPLATE_TYPE);
503: propertiesDescriptor = decorationLocator
504: .locateTemplate(descriptor);
505: } catch (TemplateLocatorException tleFallback) {
506: }
507: }
508: // load configuration properties
509: Configuration configuration = null;
510: if (propertiesDescriptor != null) {
511: try {
512: configuration = new PropertiesConfiguration(
513: propertiesDescriptor.getAbsolutePath());
514: } catch (ConfigurationException ce) {
515: log.warn(
516: "getVelocityEngine(): unable read decorator properties from "
517: + propertiesDescriptor
518: .getAbsolutePath(), ce);
519: }
520: }
521: if (configuration != null) {
522: // get decoration template macros extension and suffix
523: String ext = configuration
524: .getString("template.extension");
525: String macros = configuration
526: .getString("template.macros");
527:
528: // get decoration template macros descriptor if defined
529: if ((ext != null) && (ext.length() > 0)
530: && (macros != null) && (macros.length() > 0)) {
531: descriptor.setName(layoutDecoration + "/"
532: + JetspeedVelocityPowerTool.DECORATOR_TYPE
533: + macros + ext);
534: try {
535: macrosDescriptor = decorationLocator
536: .locateTemplate(descriptor);
537: } catch (TemplateLocatorException tle) {
538: // fallback to extends decoration, (assume macros named the
539: // same in the parent decoration as configured here)
540: try {
541: String parent = configuration
542: .getString("extends");
543: if ((parent != null)
544: && (parent.length() > 0)) {
545: descriptor
546: .setName(parent
547: + "/"
548: + JetspeedVelocityPowerTool.DECORATOR_TYPE
549: + macros + ext);
550: macrosDescriptor = decorationLocator
551: .locateTemplate(descriptor);
552: }
553: } catch (TemplateLocatorException tleExtends) {
554: }
555: }
556: }
557: }
558:
559: // compare located macros file with cached version
560: // to validate/refresh cached config and velocity engine
561: boolean newVelocityEngineConfig = false;
562: boolean forceVelocityEngineRefresh = false;
563: if (config == null) {
564: config = new VelocityEngineConfig(layoutDecoration,
565: layoutType, layoutMediaType, layoutLanguage,
566: layoutCountry);
567: synchronized (velocityEngineConfigCache) {
568: velocityEngineConfigCache.put(cacheKey, config);
569: }
570: newVelocityEngineConfig = true;
571: }
572: if (((macrosDescriptor == null) && (config.macros != null))
573: || ((macrosDescriptor != null) && (config.macros == null))
574: || ((macrosDescriptor != null)
575: && (config.macros != null) && (!macrosDescriptor
576: .getAbsolutePath().equals(
577: config.macros.getAbsolutePath()) || (config.macros
578: .lastModified() != config.macrosLastModified)))) {
579: // set or reset configuration cache entry
580: config.lastValidated = now;
581: if (macrosDescriptor != null) {
582: // save macros file
583: config.macros = new File(macrosDescriptor
584: .getAbsolutePath());
585: config.macrosLastModified = config.macros
586: .lastModified();
587: } else {
588: // clear macros file
589: config.macros = null;
590: config.macrosLastModified = -1;
591: }
592:
593: // aggressively force creation of new velocity engine
594: // if any configuration change detected
595: forceVelocityEngineRefresh = !newVelocityEngineConfig;
596: } else {
597: // config validated
598: config.lastValidated = now;
599: }
600:
601: // get or create new velocity engine intialized with
602: // validated macros configuration
603: VelocityEngine velocity = null;
604: if ((macrosDescriptor != null) && (config.macros != null)) {
605: synchronized (velocityEngineCache) {
606: if (!forceVelocityEngineRefresh) {
607: // use cached velocity engine
608: velocity = (VelocityEngine) velocityEngineCache
609: .get(config.macros.getAbsolutePath());
610: }
611: if (velocity == null) {
612: // create and cache new velocity engine
613: velocity = initVelocity(macrosDescriptor);
614: if (velocity != null) {
615: velocityEngineCache.put(config.macros
616: .getAbsolutePath(), velocity);
617: }
618: }
619: }
620: }
621:
622: // fallback to default velocity engine
623: if (velocity == null) {
624: synchronized (this ) {
625: // construct and cache default velocity engine
626: if (defaultVelocityEngine == null) {
627: defaultVelocityEngine = initVelocity((TemplateDescriptor) null);
628: }
629: velocity = defaultVelocityEngine;
630: }
631: }
632:
633: // return velocity engine for validated configuration
634: return velocity;
635: }
636: return null;
637: }
638:
639: /**
640: * Initialize new velocity instance using specified macros template.
641: *
642: * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet.initVelocity()
643: *
644: * @param macros template descriptor.
645: * @return new VelocityEngine instance.
646: */
647: private VelocityEngine initVelocity(TemplateDescriptor macros) {
648: try {
649: // create new instance to initialize
650: VelocityEngine velocity = new VelocityEngine();
651:
652: // initialize new instance as is done with the default
653: // velocity singleton, appending macros template to the
654: // base configuration velocimacro.library property
655: velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY,
656: getServletContext());
657: velocity
658: .setProperty(
659: VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,
660: "org.apache.velocity.tools.view.servlet.ServletLogger");
661: ExtendedProperties configuration = loadConfiguration(getServletConfig());
662: if (macros != null) {
663: configuration.addProperty("velocimacro.library", macros
664: .getAppRelativePath());
665: }
666: configuration.setProperty("file.resource.loader.path",
667: getServletContext().getRealPath("/"));
668: velocity.setExtendedProperties(configuration);
669:
670: // initialize and return velocity engine
671: velocity.init();
672: if (macros != null) {
673: log
674: .debug("initVelocity(): create new VelocityEngine instance to support "
675: + macros.getAppRelativePath()
676: + " decoration template macros");
677: } else {
678: log
679: .debug("initVelocity(): create new default VelocityEngine instance");
680: }
681: return velocity;
682: } catch (Exception e) {
683: log
684: .error(
685: "initVelocity(): unable to initialize velocity engine instance, using default singleton",
686: e);
687: }
688: return null;
689: }
690:
691: /**
692: * Utility to get long init parameters.
693: *
694: * @param config servlet config
695: * @param name of init parameter
696: * @param defaultValue value
697: * @return parameter value
698: */
699: private long getLongInitParameter(ServletConfig config,
700: String name, long defaultValue) {
701: String value = config.getInitParameter(name);
702: if ((value == null) || (value.length() == 0)) {
703: value = config.getServletContext().getInitParameter(name);
704: }
705: if ((value != null) && (value.length() > 0)) {
706: try {
707: return Long.parseLong(value);
708: } catch (Exception e) {
709: }
710: }
711: return defaultValue;
712: }
713:
714: protected void error(HttpServletRequest request,
715: HttpServletResponse response, Exception e)
716: throws ServletException {
717: try {
718: StringBuffer html = new StringBuffer();
719: html.append("<b>\n");
720: html.append("Content is not available");
721: html.append("<b>\n");
722: getResponseWriter(response).write(html.toString());
723: log.error("Error processing vm template ", e);
724: } catch (Exception e2) {
725: log
726: .error(
727: "Error writing error message to vm template ",
728: e2);
729: }
730: }
731:
732: }
|