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 }