View Javadoc

1   package org.apache.velocity.runtime.directive;
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.IOException;
23  import java.io.StringWriter;
24  import java.io.Writer;
25  
26  import org.apache.commons.lang.text.StrBuilder;
27  import org.apache.velocity.context.InternalContextAdapter;
28  import org.apache.velocity.exception.TemplateInitException;
29  import org.apache.velocity.runtime.Renderable;
30  import org.apache.velocity.runtime.RuntimeServices;
31  import org.apache.velocity.runtime.log.Log;
32  import org.apache.velocity.runtime.parser.node.Node;
33  
34  /**
35   * Directive that puts an unrendered AST block in the context
36   * under the specified key, postponing rendering until the
37   * reference is used and rendered.
38   *
39   * @author Andrew Tetlaw
40   * @author Nathan Bubna
41   * @author <a href="mailto:wyla@removethis.sci.fi">Jarkko Viinamaki</a>
42   * @since 1.7
43   * @version $Id: Block.java 686842 2008-08-18 18:29:31Z nbubna $
44   */
45  public abstract class Block extends Directive
46  {
47      protected Node block;
48      protected Log log;
49      protected int maxDepth;
50      protected String key;
51  
52      /**
53       * Return type of this directive.
54       */
55      public int getType()
56      {
57          return BLOCK;
58      }
59  
60      /**
61       *  simple init - get the key
62       */
63      public void init(RuntimeServices rs, InternalContextAdapter context, Node node)
64          throws TemplateInitException
65      {
66          super.init(rs, context, node);
67  
68          log = rs.getLog();
69  
70          /**
71           * No checking is done. We just grab the last child node and assume
72           * that it's the block!
73           */
74          block = node.jjtGetChild(node.jjtGetNumChildren() - 1);
75      }
76  
77      public boolean render(InternalContextAdapter context, Writer writer)
78      {
79          preRender(context);
80          try
81          {
82              return block.render(context, writer);
83          }
84          catch (IOException e)
85          {
86              String msg = "Failed to render " + id(context) + " to writer "
87                + " at " + Log.formatFileString(this);
88  
89              log.error(msg, e);
90              throw new RuntimeException(msg, e);
91          }
92          catch (StopCommand stop)
93          {
94              if (!stop.isFor(this))
95              {
96                  throw stop;
97              }
98              return true;
99          }
100         finally
101         {
102             postRender(context);
103         }
104     }
105 
106     /**
107      * Creates a string identifying the source and location of the block
108      * definition, and the current template being rendered if that is
109      * different.
110      */
111     protected String id(InternalContextAdapter context)
112     {
113         StrBuilder str = new StrBuilder(100)
114             .append("block $").append(key);
115         if (!context.getCurrentTemplateName().equals(getTemplateName()))
116         {
117             str.append(" used in ").append(context.getCurrentTemplateName());
118         }
119         return str.toString();
120     }
121     
122     /**
123      * actual class placed in the context, holds the context
124      * being used for the render, as well as the parent (which already holds
125      * everything else we need).
126      */
127     public static class Reference implements Renderable
128     {
129         private InternalContextAdapter context;
130         private Block parent;
131         private int depth;
132         
133         public Reference(InternalContextAdapter context, Block parent)
134         {
135             this.context = context;
136             this.parent = parent;
137         }
138         
139         /**
140          * Render the AST of this block into the writer using the context.
141          */
142         public boolean render(InternalContextAdapter context, Writer writer)
143         {
144             depth++;
145             if (depth > parent.maxDepth)
146             {
147                 /* this is only a debug message, as recursion can
148                  * happen in quasi-innocent situations and is relatively
149                  * harmless due to how we handle it here.
150                  * this is more to help anyone nuts enough to intentionally
151                  * use recursive block definitions and having problems
152                  * pulling it off properly.
153                  */
154                 parent.log.debug("Max recursion depth reached for " + parent.id(context)
155                     + " at " + Log.formatFileString(parent));
156                 depth--;
157                 return false;
158             }
159             else
160             {
161                 parent.render(context, writer);
162                 depth--;
163                 return true;
164             }
165         }
166 
167         public String toString()
168         {
169             Writer writer = new StringWriter();
170             if (render(context, writer))
171             {
172                 return writer.toString();
173             }
174             return null;
175         }
176     }
177 }