001: package org.apache.velocity.runtime.parser.node;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.IOException;
023: import java.io.Writer;
024:
025: import org.apache.velocity.app.event.EventHandlerUtil;
026: import org.apache.velocity.context.InternalContextAdapter;
027: import org.apache.velocity.exception.MethodInvocationException;
028: import org.apache.velocity.exception.TemplateInitException;
029: import org.apache.velocity.runtime.RuntimeConstants;
030: import org.apache.velocity.runtime.parser.Parser;
031: import org.apache.velocity.runtime.parser.ParserVisitor;
032: import org.apache.velocity.util.introspection.Info;
033:
034: /**
035: * Node for the #set directive
036: *
037: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
038: * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
039: * @version $Id: ASTSetDirective.java 471381 2006-11-05 08:56:58Z wglass $
040: */
041: public class ASTSetDirective extends SimpleNode {
042: private String leftReference = "";
043: private Node right = null;
044: private ASTReference left = null;
045: boolean logOnNull = false;
046:
047: /**
048: * This is really immutable after the init, so keep one for this node
049: */
050: protected Info uberInfo;
051:
052: /**
053: * @param id
054: */
055: public ASTSetDirective(int id) {
056: super (id);
057: }
058:
059: /**
060: * @param p
061: * @param id
062: */
063: public ASTSetDirective(Parser p, int id) {
064: super (p, id);
065: }
066:
067: /**
068: * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.ParserVisitor, java.lang.Object)
069: */
070: public Object jjtAccept(ParserVisitor visitor, Object data) {
071: return visitor.visit(this , data);
072: }
073:
074: /**
075: * simple init. We can get the RHS and LHS as the the tree structure is static
076: * @param context
077: * @param data
078: * @return Init result.
079: * @throws TemplateInitException
080: */
081: public Object init(InternalContextAdapter context, Object data)
082: throws TemplateInitException {
083: /*
084: * init the tree correctly
085: */
086:
087: super .init(context, data);
088:
089: uberInfo = new Info(context.getCurrentTemplateName(),
090: getLine(), getColumn());
091:
092: right = getRightHandSide();
093: left = getLeftHandSide();
094:
095: logOnNull = rsvc.getBoolean(
096: RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID,
097: true);
098:
099: /*
100: * grab this now. No need to redo each time
101: */
102: leftReference = left.getFirstToken().image.substring(1);
103:
104: return data;
105: }
106:
107: /**
108: * puts the value of the RHS into the context under the key of the LHS
109: * @param context
110: * @param writer
111: * @return True if rendering was sucessful.
112: * @throws IOException
113: * @throws MethodInvocationException
114: */
115: public boolean render(InternalContextAdapter context, Writer writer)
116: throws IOException, MethodInvocationException {
117: /*
118: * get the RHS node, and its value
119: */
120:
121: Object value = right.value(context);
122:
123: /*
124: * it's an error if we don't have a value of some sort AND
125: * it is not allowed by configuration
126: */
127:
128: if (!rsvc.getBoolean(RuntimeConstants.SET_NULL_ALLOWED, false)) {
129: if (value == null) {
130: /*
131: * first, are we supposed to say anything anyway?
132: */
133: if (logOnNull) {
134: boolean doit = EventHandlerUtil.shouldLogOnNullSet(
135: rsvc, context, left.literal(), right
136: .literal());
137:
138: if (doit && log.isInfoEnabled()) {
139: log
140: .info("RHS of #set statement is null. Context will not be modified. "
141: + context
142: .getCurrentTemplateName()
143: + " [line "
144: + getLine()
145: + ", column "
146: + getColumn()
147: + "]");
148: }
149: }
150:
151: String rightReference = null;
152: if (right instanceof ASTExpression) {
153: rightReference = ((ASTExpression) right)
154: .getLastToken().image;
155: }
156: EventHandlerUtil.invalidSetMethod(rsvc, context,
157: leftReference, rightReference, uberInfo);
158:
159: return false;
160: }
161: }
162:
163: if (value == null) {
164: String rightReference = null;
165: if (right instanceof ASTExpression) {
166: rightReference = ((ASTExpression) right).getLastToken().image;
167: }
168: EventHandlerUtil.invalidSetMethod(rsvc, context,
169: 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: } else {
180: /*
181: * if the LHS is simple, just punch the value into the context
182: * otherwise, use the setValue() method do to it.
183: * Maybe we should always use setValue()
184: */
185:
186: if (left.jjtGetNumChildren() == 0) {
187: context.put(leftReference, value);
188: } else {
189: left.setValue(context, value);
190: }
191: }
192:
193: return true;
194: }
195:
196: /**
197: * returns the ASTReference that is the LHS of the set statememt
198: *
199: * @return left hand side of #set statement
200: */
201: private ASTReference getLeftHandSide() {
202: return (ASTReference) jjtGetChild(0);
203: }
204:
205: /**
206: * returns the RHS Node of the set statement
207: *
208: * @return right hand side of #set statement
209: */
210: private Node getRightHandSide() {
211: return jjtGetChild(1);
212: }
213: }
|