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