View Javadoc

1   package org.apache.velocity.runtime.parser.node;
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.Writer;
24  
25  import org.apache.commons.lang.builder.ToStringBuilder;
26  import org.apache.velocity.context.InternalContextAdapter;
27  import org.apache.velocity.exception.MethodInvocationException;
28  import org.apache.velocity.exception.ParseErrorException;
29  import org.apache.velocity.exception.ResourceNotFoundException;
30  import org.apache.velocity.exception.TemplateInitException;
31  import org.apache.velocity.runtime.directive.Directive;
32  import org.apache.velocity.runtime.directive.RuntimeMacro;
33  import org.apache.velocity.runtime.parser.ParseException;
34  import org.apache.velocity.runtime.parser.Parser;
35  import org.apache.velocity.util.ExceptionUtils;
36  
37  /**
38   * This class is responsible for handling the pluggable
39   * directives in VTL.
40   *
41   * For example :  #foreach()
42   *
43   * Please look at the Parser.jjt file which is
44   * what controls the generation of this class.
45   *
46   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
47   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
48   * @author <a href="mailto:kav@kav.dk">Kasper Nielsen</a>
49   * @version $Id: ASTDirective.java 724825 2008-12-09 18:56:06Z nbubna $
50   */
51  public class ASTDirective extends SimpleNode
52  {
53      private Directive directive = null;
54      private String directiveName = "";
55      private boolean isDirective;
56      private boolean isInitialized;
57  
58      /**
59       * @param id
60       */
61      public ASTDirective(int id)
62      {
63          super(id);
64      }
65  
66      /**
67       * @param p
68       * @param id
69       */
70      public ASTDirective(Parser p, int id)
71      {
72          super(p, id);
73      }
74  
75  
76      /**
77       * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
78       */
79      public Object jjtAccept(ParserVisitor visitor, Object data)
80      {
81          return visitor.visit(this, data);
82      }
83  
84      /**
85       * @see org.apache.velocity.runtime.parser.node.SimpleNode#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)
86       */
87      public synchronized Object init( InternalContextAdapter context, Object data)
88      throws TemplateInitException
89      {
90          /** method is synchronized to avoid concurrent directive initialization **/
91          
92          if (!isInitialized)
93          {
94              super.init( context, data );
95  
96              /*
97               *  only do things that are not context dependent
98               */
99      
100             if (parser.isDirective( directiveName ))
101             {
102                 isDirective = true;
103     
104                 try
105                 {
106                     directive = (Directive) parser.getDirective( directiveName )
107                         .getClass().newInstance();
108                 } 
109                 catch (InstantiationException e)
110                 {
111                     throw ExceptionUtils.createRuntimeException("Couldn't initialize " +
112                             "directive of class " +
113                             parser.getDirective(directiveName).getClass().getName(),
114                             e);
115                 }
116                 catch (IllegalAccessException e)
117                 {
118                     throw ExceptionUtils.createRuntimeException("Couldn't initialize " +
119                             "directive of class " +
120                             parser.getDirective(directiveName).getClass().getName(),
121                             e);
122                 }
123                         
124                 directive.setLocation(getLine(), getColumn(), getTemplateName());
125                 directive.init(rsvc, context,this);
126             }
127             else
128             {
129                 /**
130                  * Create a new RuntimeMacro
131                  */
132                 directive = new RuntimeMacro(directiveName, getTemplateName());
133                 directive.setLocation(getLine(), getColumn(), getTemplateName());
134         
135                 /**
136                  * Initialize it
137                  */
138                 try
139                 {
140                     directive.init( rsvc, context, this );
141                 }
142     
143                 /**
144                  * correct the line/column number if an exception is caught
145                  */
146                 catch (TemplateInitException die)
147                 {
148                     throw new TemplateInitException(die.getMessage(),
149                             (ParseException) die.getWrappedThrowable(),
150                             die.getTemplateName(),
151                             die.getColumnNumber() + getColumn(),
152                             die.getLineNumber() + getLine());
153                 }
154                 isDirective = true;
155             }
156             
157             isInitialized = true;
158         }
159            
160         return data;
161     }
162 
163     /**
164      * @see org.apache.velocity.runtime.parser.node.SimpleNode#render(org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
165      */
166     public boolean render( InternalContextAdapter context, Writer writer)
167         throws IOException,MethodInvocationException, ResourceNotFoundException, ParseErrorException
168     {
169         /*
170          *  normal processing
171          */
172 
173         if (isDirective)
174         {
175             directive.render(context, writer, this);
176         }
177         else
178         {
179             if (context.getAllowRendering())
180             {
181                 writer.write( "#");
182                 writer.write( directiveName );
183             }
184         }
185 
186         return true;
187     }
188 
189     /**
190      *   Sets the directive name.  Used by the parser.  This keeps us from having to
191      *   dig it out of the token stream and gives the parse the change to override.
192      * @param str
193      */
194     public void setDirectiveName( String str )
195     {
196         directiveName = str;
197     }
198 
199     /**
200      *  Gets the name of this directive.
201      *  @return The name of this directive.
202      */
203     public String getDirectiveName()
204     {
205         return directiveName;
206     }
207     
208     /**
209      * @since 1.5
210      */
211     public String toString()
212     {
213         return new ToStringBuilder(this)
214             .appendSuper(super.toString())
215             .append("directiveName", getDirectiveName())
216             .toString();
217     }
218 
219 }
220 
221 
222