View Javadoc

1   /**
2    * This file Copyright (c) 2003-2012 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.blossom.view;
35  
36  import java.lang.reflect.Constructor;
37  import java.lang.reflect.InvocationTargetException;
38  import java.util.Map;
39  import javax.jcr.Node;
40  import javax.servlet.ServletContext;
41  import javax.servlet.http.HttpServletRequest;
42  import javax.servlet.http.HttpServletResponse;
43  
44  import info.magnolia.context.MgnlContext;
45  import info.magnolia.module.blossom.render.RenderContext;
46  import info.magnolia.rendering.context.RenderingContext;
47  import info.magnolia.rendering.engine.RenderException;
48  import info.magnolia.rendering.model.RenderingModel;
49  import info.magnolia.rendering.renderer.FreemarkerRenderer;
50  import info.magnolia.rendering.template.RenderableDefinition;
51  
52  import org.springframework.util.ClassUtils;
53  import org.springframework.web.servlet.support.RequestContext;
54  import org.springframework.web.servlet.view.AbstractTemplateView;
55  
56  /**
57   * Renders freemarker templates.
58   *
59   * @since 1.0
60   */
61  public class FreemarkerTemplateViewRenderer extends FreemarkerRenderer {
62  
63  
64      private boolean exposeModelAsRequestAttributes = true;
65      private boolean exposeSpringMacroHelpers = true;
66  
67      public boolean isExposeModelAsRequestAttributes() {
68          return exposeModelAsRequestAttributes;
69      }
70  
71      public void setExposeModelAsRequestAttributes(boolean exposeModelAsRequestAttributes) {
72          this.exposeModelAsRequestAttributes = exposeModelAsRequestAttributes;
73      }
74  
75      public boolean isExposeSpringMacroHelpers() {
76          return exposeSpringMacroHelpers;
77      }
78  
79      public void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {
80          this.exposeSpringMacroHelpers = exposeSpringMacroHelpers;
81      }
82  
83      @Override
84      protected void setupContext(Map<String, Object> ctx, Node content, RenderableDefinition definition, RenderingModel<?> model, Object actionResult) {
85          super.setupContext(ctx, content, definition, model, actionResult);
86          ctx.putAll(RenderContext.get().getModel());
87      }
88  
89      @Override
90      protected String resolveTemplateScript(Node content, RenderableDefinition definition, RenderingModel<?> model, String actionResult) {
91          return RenderContext.get().getTemplateScript();
92      }
93  
94      @Override
95      protected void onRender(Node content, RenderableDefinition definition, RenderingContext renderingCtx, Map<String, Object> ctx, String templateScript) throws RenderException {
96  
97          if (MgnlContext.isWebContext()) {
98  
99              @SuppressWarnings("unchecked")
100             Map<String, Object> model = ctx;
101 
102             // Expose RequestContext instance for Spring macros.
103             // See org.springframework.web.servlet.view.AbstractTemplateView#setExposeSpringMacroHelpers
104             if (this.exposeSpringMacroHelpers) {
105                 model.put(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE, createRequestContext(model));
106             }
107 
108             // Expose the model objects in the given map as request attributes.
109             // Necessary to let JSP tags access them, especially the spring form taglib.
110             // See org.springframework.web.servlet.view.AbstractView#exposeModelAsRequestAttributes
111             if (this.exposeModelAsRequestAttributes) {
112                 HttpServletRequest request = MgnlContext.getWebContext().getRequest();
113                 for (Map.Entry<String, Object> entry : model.entrySet()) {
114                     String modelName = entry.getKey();
115                     Object modelValue = entry.getValue();
116                     if (modelValue != null) {
117                         request.setAttribute(modelName, modelValue);
118                     } else {
119                         request.removeAttribute(modelName);
120                     }
121                 }
122             }
123         }
124 
125         super.onRender(content, definition, renderingCtx, ctx, templateScript);
126     }
127 
128     private static final Constructor<RequestContext> spring30RequestContextConstructor = ClassUtils.getConstructorIfAvailable(RequestContext.class, new Class[] {HttpServletRequest.class, HttpServletResponse.class, ServletContext.class, Map.class});
129     private static final Constructor<RequestContext> spring25RequestContextConstructor = ClassUtils.getConstructorIfAvailable(RequestContext.class, new Class[] {HttpServletRequest.class, ServletContext.class, Map.class});
130 
131     /**
132      * Create a RequestContext object using reflection to handle the fact that in Spring 3.0 the constructor on
133      * RequestContext changed to also require a HttpServletResponse argument.
134      */
135     private RequestContext createRequestContext(Map<String, Object> model) throws RenderException {
136         try {
137 
138             // Spring 3.0+
139             if (spring30RequestContextConstructor != null) {
140                 return spring30RequestContextConstructor.newInstance(
141                         MgnlContext.getWebContext().getRequest(),
142                         MgnlContext.getWebContext().getResponse(),
143                         MgnlContext.getWebContext().getServletContext(),
144                         model);
145             }
146 
147             // Spring 2.5.x
148             if (spring25RequestContextConstructor != null) {
149                 return spring25RequestContextConstructor.newInstance(
150                         MgnlContext.getWebContext().getRequest(),
151                         MgnlContext.getWebContext().getServletContext(),
152                         model);
153             }
154 
155             throw new RenderException("Could not create RequestContext");
156 
157         } catch (InstantiationException e) {
158             throw new RenderException("Could not create RequestContext", e);
159         } catch (IllegalAccessException e) {
160             throw new RenderException("Could not create RequestContext", e);
161         } catch (InvocationTargetException e) {
162             throw new RenderException("Could not create RequestContext", e);
163         }
164     }
165 }