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 }