001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018:
019: package org.apache.roller.ui.rendering.velocity;
020:
021: import java.io.StringWriter;
022: import java.io.Writer;
023: import java.util.Map;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.apache.roller.pojos.Template;
027: import org.apache.roller.ui.rendering.Renderer;
028: import org.apache.roller.ui.rendering.RenderingException;
029: import org.apache.roller.ui.rendering.model.UtilitiesModel;
030: import org.apache.velocity.VelocityContext;
031: import org.apache.velocity.context.Context;
032: import org.apache.velocity.exception.MethodInvocationException;
033: import org.apache.velocity.exception.ParseErrorException;
034: import org.apache.velocity.exception.ResourceNotFoundException;
035:
036: /**
037: * Renderer for Velocity templates.
038: */
039: public class VelocityRenderer implements Renderer {
040:
041: private static Log log = LogFactory.getLog(VelocityRenderer.class);
042:
043: // the original template we are supposed to render
044: private Template renderTemplate = null;
045:
046: // the velocity templates
047: private org.apache.velocity.Template velocityTemplate = null;
048: private org.apache.velocity.Template velocityDecorator = null;
049:
050: // a possible exception
051: private Exception parseException = null;
052:
053: public VelocityRenderer(Template template) throws Exception {
054:
055: // the Template we are supposed to render
056: this .renderTemplate = template;
057:
058: try {
059: // make sure that we can locate the template
060: // if we can't then this will throw an exception
061: velocityTemplate = RollerVelocity.getTemplate(template
062: .getId(), "UTF-8");
063:
064: // if there is a decorator then look that up too
065: Template decorator = renderTemplate.getDecorator();
066: if (decorator != null) {
067: velocityDecorator = RollerVelocity
068: .getTemplate(decorator.getId());
069: }
070:
071: } catch (ResourceNotFoundException ex) {
072: // velocity couldn't find the resource so lets log a warning
073: log.warn("Error creating renderer for " + template.getId()
074: + " due to [" + ex.getMessage() + "]");
075:
076: // then just rethrow so that the caller knows this instantiation failed
077: throw ex;
078:
079: } catch (ParseErrorException ex) {
080: // in the case of a parsing error we want to render an
081: // error page instead so the user knows what was wrong
082: parseException = ex;
083:
084: // need to lookup error page template
085: velocityTemplate = RollerVelocity
086: .getTemplate("templates/error-page.vm");
087:
088: } catch (Exception ex) {
089: // some kind of generic/unknown exception, dump it to the logs
090: log.error("Unknown exception creatting renderer for "
091: + template.getId(), ex);
092:
093: // throw if back to the caller
094: throw ex;
095: }
096: }
097:
098: public void render(Map model, Writer out) throws RenderingException {
099:
100: try {
101: if (parseException != null) {
102:
103: Context ctx = new VelocityContext(model);
104: ctx.put("exception", parseException);
105: ctx.put("exceptionSource", renderTemplate.getId());
106: ctx.put("utils", new UtilitiesModel());
107:
108: // render output to Writer
109: velocityTemplate.merge(ctx, out);
110:
111: // and we're done
112: return;
113: }
114:
115: long startTime = System.currentTimeMillis();
116:
117: // convert model to Velocity Context
118: Context ctx = new VelocityContext(model);
119:
120: if (velocityDecorator != null) {
121:
122: /**
123: * We only allow decorating once, so the process isn't
124: * fully recursive. This is just to keep it simple.
125: */
126:
127: // render base template to a temporary StringWriter
128: StringWriter sw = new StringWriter();
129: velocityTemplate.merge(ctx, sw);
130:
131: // put rendered template into context
132: ctx.put("decorator_body", sw.toString());
133:
134: log.debug("Applying decorator "
135: + velocityDecorator.getName());
136:
137: // now render decorator to our output writer
138: velocityDecorator.merge(ctx, out);
139:
140: } else {
141:
142: // no decorator, so just merge template to our output writer
143: velocityTemplate.merge(ctx, out);
144: }
145:
146: long endTime = System.currentTimeMillis();
147: long renderTime = (endTime - startTime) / 1000;
148:
149: log.debug("Rendered [" + renderTemplate.getId() + "] in "
150: + renderTime + " secs");
151:
152: } catch (Exception ex) {
153: // wrap and rethrow so caller can deal with it
154: throw new RenderingException("Error during rendering", ex);
155: }
156: }
157:
158: }
|