View Javadoc

1   package org.apache.velocity.tools.view.jsp;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.StringWriter;
23  import java.io.Writer;
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.jsp.JspException;
26  import javax.servlet.jsp.PageContext;
27  import javax.servlet.jsp.tagext.BodyTagSupport;
28  import org.apache.velocity.Template;
29  import org.apache.velocity.app.VelocityEngine;
30  import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
31  import org.apache.velocity.runtime.resource.util.StringResourceRepository;
32  import org.apache.velocity.tools.view.ServletUtils;
33  import org.apache.velocity.tools.view.ViewToolContext;
34  import org.apache.velocity.tools.view.VelocityView;
35  
36  /**
37   * <p>This tag enables use of Velocity and VelocityTools within JSP files and tags.
38   * This makes it trivial to render embedded VTL (Velocity Template Language)
39   * or include a separate Velocity template within a JSP using the current
40   * page context.  This also automatically provides the typical 
41   * {@link VelocityView} toolbox support, much like the VelocityViewServlet
42   * and VelocityLayoutServlets have.  In fact, this will by default share
43   * the {@link VelocityView} instance used with those servlets.  This allows
44   * for consistent configuration and shared resources (better performance).
45   * </p>
46   *
47   * @author Nathan Bubna
48   * @version $Id: VelocityViewTag.java,v 1.1 2001/08/14 00:07:39 geirm Exp $
49   * @since VelocityTools 2.0
50   */
51  public class VelocityViewTag extends BodyTagSupport
52  {
53      public static final String DEFAULT_BODY_CONTENT_KEY = "bodyContent";
54      private static final long serialVersionUID = -3329444102562079189L;
55  
56      protected transient VelocityView view;
57      protected transient ViewToolContext context;
58      protected transient StringResourceRepository repository;
59  
60      protected String var;
61      protected String scope;
62      protected String template;
63      protected String bodyContentKey = DEFAULT_BODY_CONTENT_KEY;
64      private boolean cache = false;
65  
66      /**
67       * Release any per-invocation resources, resetting any resources or state
68       * that should be cleared between successive invocations of
69       * {@link javax.servlet.jsp.tagext.Tag#doEndTag()} and
70       * {@link javax.servlet.jsp.tagext.Tag#doStartTag()}.
71       */
72      protected void reset()
73      {
74          super.setId(null);
75          var = null;
76          scope = null;
77          template = null;
78          bodyContentKey = DEFAULT_BODY_CONTENT_KEY;
79          cache = false;
80      }
81  
82      public void setId(String id)
83      {
84          if (id == null)
85          {
86              throw new NullPointerException("id cannot be null");
87          }
88          super.setId(id);
89          // assume they want this cached
90          cache = true;
91      }
92  
93      protected String getLogId()
94      {
95          String id = super.getId();
96          if (id == null)
97          {
98              id = getClass().getSimpleName();
99          }
100         return id;
101     }
102 
103     public void setVar(String var)
104     {
105         this.var = var;
106     }
107 
108     public String getVar()
109     {
110         return this.var;
111     }
112 
113     public void setScope(String scope)
114     {
115         this.scope = scope;
116     }
117 
118     public String getScope()
119     {
120         return this.scope;
121     }
122 
123     public void setTemplate(String template)
124     {
125         this.template = template;
126     }
127 
128     public String getTemplate()
129     {
130         return this.template;
131     }
132 
133     public void setBodyContentKey(String key)
134     {
135         this.bodyContentKey = DEFAULT_BODY_CONTENT_KEY;
136     }
137 
138     public String getBodyContentKey()
139     {
140         return this.bodyContentKey;
141     }
142 
143     public void setCache(String s)
144     {
145         this.cache = "true".equalsIgnoreCase(s);
146     }
147 
148     public String getCache()
149     {
150         return String.valueOf(this.cache);
151     }
152 
153     public VelocityView getVelocityView()
154     {
155         return this.view;
156     }
157 
158     public void setVelocityView(VelocityView view)
159     {
160         this.view = view;
161     }
162 
163     public ViewToolContext getViewToolContext()
164     {
165         return this.context;
166     }
167 
168     public void setViewToolContext(ViewToolContext context)
169     {
170         this.context = context;
171     }
172 
173     public StringResourceRepository getRepository()
174     {
175         if (this.repository == null)
176         {
177             setRepository(StringResourceLoader.getRepository());
178         }
179         return this.repository;
180     }
181 
182     public void setRepository(StringResourceRepository repo)
183     {
184         this.repository = repo;
185     }
186 
187     public int doStartTag() throws JspException
188     {
189         initializeView();
190 
191         return EVAL_BODY_BUFFERED;
192     }
193 
194     public int doEndTag() throws JspException
195     {
196         if (hasContent())
197         {
198             try
199             {
200                 // check for a var attribute
201                 String varname = getVar();
202                 if (varname == null)
203                 {
204                     // if none, render into the pageout
205                     renderContent(this.pageContext.getOut());
206                 }
207                 else
208                 {
209                     // if we have a var, render into a string
210                     StringWriter out = new StringWriter();
211                     renderContent(out);
212 
213                     // and insert the string into the specified scope
214                     // if none specified, default is PAGE_SCOPE
215                     this.pageContext.setAttribute(varname,
216                                                   out.toString(),
217                                                   toScopeInt(getScope()));
218                 }
219             }
220             catch (Exception e)
221             {
222                 throw new JspException("Failed to render " + getClass() +
223                                        ": "+getLogId(), e);
224             }
225         }
226         return EVAL_PAGE;
227     }
228 
229 
230     protected void initializeView()
231     {
232         // get the VelocityView for this app
233         VelocityView view =
234             ServletUtils.getVelocityView(this.pageContext.getServletConfig());
235 
236         // now make a Context
237         ViewToolContext context =
238             new JspToolContext(view.getVelocityEngine(), this.pageContext);
239 
240         view.prepareContext(context, (HttpServletRequest)this.pageContext.getRequest());
241 
242         setVelocityView(view);
243         setViewToolContext(context);
244     }
245 
246     protected boolean hasContent()
247     {
248         return (getBodyContent() != null || getTemplate() != null);
249     }
250 
251     protected void renderContent(Writer out) throws Exception
252     {
253         if (getTemplate() != null)
254         {
255             VelocityView view = getVelocityView();
256             ViewToolContext context = getViewToolContext();
257 
258             // get the actual Template
259             Template template = view.getTemplate(getTemplate());
260 
261             if (getBodyContent() != null)
262             {
263                 context.put(getBodyContentKey(), getRenderedBody());
264             }
265 
266             // render the template into the writer
267             template.merge(context, out);
268         }
269         else
270         {
271             // render the body into the writer
272             renderBody(out);
273         }
274     }
275 
276     protected String getRenderedBody() throws Exception
277     {
278         // render the body into a string
279         StringWriter out = new StringWriter();
280         renderBody(out);
281         return out.toString();
282     }
283 
284     protected boolean isCached()
285     {
286         return getRepository().getStringResource(getId()) != null;
287     }
288 
289     protected void renderBody(Writer out) throws Exception
290     {
291         String name = getId();
292         // if it hasn't been cached, try that
293         if (cache && !isCached())
294         {
295             String template = getBodyContent().getString();
296             // if no id was set, use the template as the id
297             if (name == null)
298             {
299                 name = template;
300             }
301             cache(name, template);
302         }
303         // if it can't be cached, eval it
304         if (!cache)
305         {
306             evalBody(out);
307         }
308         else
309         {
310             // load template from cache
311             Template template = getVelocityView().getTemplate(name);
312             template.merge(getViewToolContext(), out);
313         }
314     }
315 
316     protected void evalBody(Writer out) throws Exception
317     {
318         VelocityEngine engine = getVelocityView().getVelocityEngine();
319         engine.evaluate(getViewToolContext(), out, getLogId(),
320                         getBodyContent().getReader());
321     }
322 
323     protected static int toScopeInt(String scope)
324     {
325         if (scope == null)
326         {
327             return PageContext.PAGE_SCOPE;
328         }
329         if (scope.equalsIgnoreCase("request"))
330         {
331             return PageContext.REQUEST_SCOPE;
332         }
333         if (scope.equalsIgnoreCase("session"))
334         {
335             return PageContext.SESSION_SCOPE;
336         }
337         if (scope.equalsIgnoreCase("application"))
338         {
339             return PageContext.APPLICATION_SCOPE;
340         }
341         if (scope.equalsIgnoreCase("page"))
342         {
343             return PageContext.PAGE_SCOPE;
344         }
345         throw new IllegalArgumentException("Unknown scope: "+scope);
346     }
347 
348     protected void cache(String name, String template)
349     {
350         try
351         {
352             getRepository().putStringResource(name, template);
353         }
354         catch (Exception cnfe)
355         {
356             getVelocityView().getLog()
357                 .error("Could not cache body in a StringResourceRepository", cnfe);
358             cache = false;
359         }
360     }
361 
362     /**
363      * Release any per-instance resources, releasing any resources or state
364      * before this tag instance is disposed.
365      *
366      * @see javax.servlet.jsp.tagext.Tag#release()
367      */
368     @Override
369     public void release()
370     {
371         super.release();
372         reset();
373     }
374 
375 }