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.velocity.app.event.EventHandlerUtil;
26  import org.apache.velocity.context.InternalContextAdapter;
27  import org.apache.velocity.exception.MethodInvocationException;
28  import org.apache.velocity.exception.TemplateInitException;
29  import org.apache.velocity.runtime.RuntimeConstants;
30  import org.apache.velocity.runtime.parser.Parser;
31  import org.apache.velocity.runtime.parser.ParserVisitor;
32  import org.apache.velocity.util.introspection.Info;
33  
34  /**
35   * Node for the #set directive
36   *
37   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
38   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
39   * @version $Id: ASTSetDirective.java 471381 2006-11-05 08:56:58Z wglass $
40   */
41  public class ASTSetDirective extends SimpleNode
42  {
43      private String leftReference = "";
44      private Node right = null;
45      private ASTReference left = null;
46      boolean logOnNull = false;
47  
48      /**
49       *  This is really immutable after the init, so keep one for this node
50       */
51      protected Info uberInfo;
52  
53      /**
54       * @param id
55       */
56      public ASTSetDirective(int id)
57      {
58          super(id);
59      }
60  
61      /**
62       * @param p
63       * @param id
64       */
65      public ASTSetDirective(Parser p, int id)
66      {
67          super(p, id);
68      }
69  
70      /**
71       * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.ParserVisitor, java.lang.Object)
72       */
73      public Object jjtAccept(ParserVisitor visitor, Object data)
74      {
75          return visitor.visit(this, data);
76      }
77  
78      /**
79       *  simple init.  We can get the RHS and LHS as the the tree structure is static
80       * @param context
81       * @param data
82       * @return Init result.
83       * @throws TemplateInitException
84       */
85      public Object init(InternalContextAdapter context, Object data)
86      throws TemplateInitException
87      {
88          /*
89           *  init the tree correctly
90           */
91  
92          super.init( context, data );
93  
94          uberInfo = new Info(context.getCurrentTemplateName(),
95                  getLine(), getColumn());
96  
97          right = getRightHandSide();
98          left = getLeftHandSide();
99  
100         logOnNull = rsvc.getBoolean(RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, true);
101 
102         /*
103          *  grab this now.  No need to redo each time
104          */
105         leftReference = left.getFirstToken().image.substring(1);
106 
107         return data;
108     }
109 
110     /**
111      *   puts the value of the RHS into the context under the key of the LHS
112      * @param context
113      * @param writer
114      * @return True if rendering was sucessful.
115      * @throws IOException
116      * @throws MethodInvocationException
117      */
118     public boolean render( InternalContextAdapter context, Writer writer)
119         throws IOException, MethodInvocationException
120     {
121         /*
122          *  get the RHS node, and its value
123          */
124 
125         Object value = right.value(context);
126 
127         /*
128          * it's an error if we don't have a value of some sort AND
129          * it is not allowed by configuration
130          */
131 
132         if( !rsvc.getBoolean(RuntimeConstants.SET_NULL_ALLOWED,false) )
133         {
134             if ( value == null )
135             {                
136                 /*
137                  *  first, are we supposed to say anything anyway?
138                  */
139                 if(logOnNull)
140                 {
141                     boolean doit = EventHandlerUtil.shouldLogOnNullSet( rsvc, context, left.literal(), right.literal() );
142 
143                     if (doit && log.isInfoEnabled())
144                     {
145                         log.info("RHS of #set statement is null. Context will not be modified. "
146                                       + context.getCurrentTemplateName() + " [line " + getLine()
147                                       + ", column " + getColumn() + "]");
148                     }
149                 }
150                 
151                 String rightReference = null;
152                 if (right instanceof ASTExpression)
153                 {
154                     rightReference = ((ASTExpression) right).getLastToken().image;
155                 }
156                 EventHandlerUtil.invalidSetMethod(rsvc, context, leftReference, rightReference, uberInfo);
157                 
158                 return false;
159             }
160         }
161 
162         if ( value == null )
163         {
164             String rightReference = null;
165             if (right instanceof ASTExpression)
166             {
167                 rightReference = ((ASTExpression) right).getLastToken().image;
168             }
169             EventHandlerUtil.invalidSetMethod(rsvc, context, leftReference, rightReference, uberInfo);
170 
171             /*
172              * if RHS is null it doesn't matter if LHS is simple or complex
173              * because the LHS is removed from context
174              */
175             context.remove( leftReference );
176 
177             return false;
178 
179         }
180         else
181         {
182             /*
183              *  if the LHS is simple, just punch the value into the context
184              *  otherwise, use the setValue() method do to it.
185              *  Maybe we should always use setValue()
186              */
187 
188             if (left.jjtGetNumChildren() == 0)
189             {
190                 context.put( leftReference, value);
191             }
192             else
193             {
194                 left.setValue(context, value);
195             }
196         }
197 
198         return true;
199     }
200 
201     /**
202      *  returns the ASTReference that is the LHS of the set statememt
203      *  
204      *  @return left hand side of #set statement
205      */
206     private ASTReference getLeftHandSide()
207     {
208         return (ASTReference) jjtGetChild(0);
209     }
210 
211     /**
212      *  returns the RHS Node of the set statement
213      *  
214      *  @return right hand side of #set statement
215      */
216     private Node getRightHandSide()
217     {
218         return jjtGetChild(1);
219     }
220 }