• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.PrintStream;
26 import java.io.PrintWriter;
27 import java.io.Writer;
28 import java.nio.charset.Charset;
29 
30 import org.apache.velocity.Template;
31 import org.apache.velocity.context.InternalContextAdapter;
32 import org.apache.velocity.exception.MethodInvocationException;
33 import org.apache.velocity.exception.ParseErrorException;
34 import org.apache.velocity.exception.ResourceNotFoundException;
35 import org.apache.velocity.exception.TemplateInitException;
36 import org.apache.velocity.runtime.RuntimeConstants;
37 import org.apache.velocity.runtime.RuntimeServices;
38 import org.apache.velocity.runtime.parser.Parser;
39 import org.apache.velocity.runtime.parser.Token;
40 import org.apache.velocity.util.StringUtils;
41 
42 import org.slf4j.Logger;
43 
44 /**
45  *
46  */
47 public class SimpleNode implements Node, Cloneable
48 {
49     /** */
50     protected RuntimeServices rsvc = null;
51 
52     /** */
53     protected Logger log = null;
54 
55     /** */
56     protected Node parent;
57 
58     /** */
59     protected Node[] children;
60 
61     /** */
62     protected int id;
63 
64     /** */
65     protected Parser parser;
66 
67     /** */
68     protected int info;
69 
70     /** */
71     public boolean state;
72 
73     /** */
74     protected boolean invalid = false;
75 
76     /** */
77     protected Token first;
78 
79     /** */
80     protected Token last;
81 
82     protected Template template;
83 
84     /**
85      * For caching the literal value.
86      */
87     protected String literal = null;
88 
89     /**
90      * Line number for this Node in the vm source file.
91      */
92 
93     protected int line;
94 
95     /**
96      * Column number for this Node in the vm source file.
97      */
98     protected int column;
99 
100     /**
101      * String image variable of the first Token element that was parsed and connected to this Node.
102      */
103     protected String firstImage;
104 
105     /**
106      * String image variable of the last Token element that was parsed and connected to this Node.
107      */
108     protected String lastImage;
109 
getRuntimeServices()110     public RuntimeServices getRuntimeServices()
111     {
112       return rsvc;
113     }
114 
115     /**
116      * @param i
117      */
SimpleNode(int i)118     public SimpleNode(int i)
119     {
120         id = i;
121     }
122 
123     /**
124      * @param p
125      * @param i
126      */
SimpleNode(Parser p, int i)127     public SimpleNode(Parser p, int i)
128     {
129         this(i);
130         parser = p;
131         template = parser.getCurrentTemplate();
132     }
133 
134     /**
135      * @see org.apache.velocity.runtime.parser.node.Node#jjtOpen()
136      */
137     @Override
jjtOpen()138     public void jjtOpen()
139     {
140         first = parser.getToken(1); // added
141     }
142 
143     /**
144      * @see org.apache.velocity.runtime.parser.node.Node#jjtClose()
145      */
146     @Override
jjtClose()147     public void jjtClose()
148     {
149         last = parser.getToken(0); // added
150     }
151 
152     /**
153      * @param t
154      */
setFirstToken(Token t)155     public void setFirstToken(Token t)
156     {
157         this.first = t;
158     }
159 
160     /**
161      * @see org.apache.velocity.runtime.parser.node.Node#getFirstToken()
162      */
163     @Override
getFirstToken()164     public Token getFirstToken()
165     {
166         return first;
167     }
168 
169     /**
170      * @see org.apache.velocity.runtime.parser.node.Node#getLastToken()
171      */
172     @Override
getLastToken()173     public Token getLastToken()
174     {
175         return last;
176     }
177 
178     /**
179      * @see org.apache.velocity.runtime.parser.node.Node#jjtSetParent(org.apache.velocity.runtime.parser.node.Node)
180      */
181     @Override
jjtSetParent(Node n)182     public void jjtSetParent(Node n)
183     {
184         parent = n;
185     }
186 
187     /**
188      * @see org.apache.velocity.runtime.parser.node.Node#jjtGetParent()
189      */
190     @Override
jjtGetParent()191     public Node jjtGetParent()
192     {
193         return parent;
194     }
195 
196     /**
197      * @see org.apache.velocity.runtime.parser.node.Node#jjtAddChild(org.apache.velocity.runtime.parser.node.Node, int)
198      */
199     @Override
jjtAddChild(Node n, int i)200     public void jjtAddChild(Node n, int i)
201     {
202         if (children == null)
203         {
204             children = new Node[i + 1];
205         }
206         else if (i >= children.length)
207         {
208             Node c[] = new Node[i + 1];
209             System.arraycopy(children, 0, c, 0, children.length);
210             children = c;
211         }
212         children[i] = n;
213     }
214 
215     /**
216      * @see org.apache.velocity.runtime.parser.node.Node#jjtGetChild(int)
217      */
218     @Override
jjtGetChild(int i)219     public Node jjtGetChild(int i)
220     {
221         return children[i];
222     }
223 
224     /**
225      * @see org.apache.velocity.runtime.parser.node.Node#jjtGetNumChildren()
226      */
227     @Override
jjtGetNumChildren()228     public int jjtGetNumChildren()
229     {
230         return (children == null) ? 0 : children.length;
231     }
232 
233 
234     /**
235      * @see org.apache.velocity.runtime.parser.node.Node#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
236      */
237     @Override
jjtAccept(ParserVisitor visitor, Object data)238     public Object jjtAccept(ParserVisitor visitor, Object data)
239     {
240         return visitor.visit(this, data);
241     }
242 
243 
244     /**
245      * @see org.apache.velocity.runtime.parser.node.Node#childrenAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
246      */
247     @Override
childrenAccept(ParserVisitor visitor, Object data)248     public Object childrenAccept(ParserVisitor visitor, Object data)
249     {
250         if (children != null)
251         {
252             for (Node aChildren : children)
253             {
254                 aChildren.jjtAccept(visitor, data);
255             }
256         }
257         return data;
258     }
259 
260     /* You can override these two methods in subclasses of SimpleNode to
261         customize the way the node appears when the tree is dumped.  If
262         your output uses more than one line you should override
263         toString(String), otherwise overriding toString() is probably all
264         you need to do. */
265     /**
266      * @param prefix display prefix
267      * @return String representation of this node.
268      */
toString(String prefix)269     public String toString(String prefix)
270     {
271         return prefix + "_" + toString();
272     }
273 
274     /**
275      * <p>Dumps nodes tree on System.out.</p>
276      * <p>Override {@link #dump(String, PrintWriter)} if you want to customize
277      * how the node dumps out its children.
278      *
279      * @param prefix
280      */
dump(String prefix)281     public final void dump(String prefix)
282     {
283         dump(prefix, System.out);
284     }
285 
286     /**
287      * <p>Dumps nodes tree on System.out.</p>
288      * <p>Override {@link #dump(String, PrintWriter)} if you want to customize
289      * how the node dumps out its children.
290      *
291      * @param prefix display prefix
292      * @param out output print stream
293      */
dump(String prefix, PrintStream out)294     public final void dump(String prefix, PrintStream out)
295     {
296         Charset charset = null;
297         if (rsvc != null) /* may be null if node isn't yet initialized */
298         {
299             String encoding = rsvc.getString(RuntimeConstants.INPUT_ENCODING);
300             try
301             {
302                 charset = Charset.forName(encoding);
303             }
304             catch (Exception e) {}
305         }
306         if (charset == null)
307         {
308             charset = Charset.defaultCharset();
309         }
310         PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, charset));
311         dump(prefix, pw);
312         pw.flush();
313     }
314 
315     /**
316      * <p>Dumps nodes tree on System.out.</p>
317      * <p>Override this method if you want to customize how the node dumps
318      * out its children.</p>
319      *
320      * @param prefix display prefix
321      * @param out output print writer
322      */
dump(String prefix, PrintWriter out)323     public void dump(String prefix, PrintWriter out)
324     {
325         out.println(toString());
326         if (children != null)
327         {
328             for (int i = 0; i < children.length; ++i)
329             {
330                 SimpleNode n = (SimpleNode) children[i];
331                 out.print(prefix + " |_");
332                 if (n != null)
333                 {
334                     n.dump(prefix + ( i == children.length - 1 ? "   " : " | " ), out);
335                 }
336             }
337         }
338     }
339 
340     /**
341      * Return a string that tells the current location of this node.
342      * @param context
343      * @return location
344      */
getLocation(InternalContextAdapter context)345     protected String getLocation(InternalContextAdapter context)
346     {
347         return StringUtils.formatFileString(this);
348     }
349 
350     // All additional methods
351 
352     /**
353      * @see org.apache.velocity.runtime.parser.node.Node#literal()
354      */
355     @Override
literal()356     public String literal()
357     {
358         if( literal != null )
359         {
360             return literal;
361         }
362 
363         // if we have only one string, just return it and avoid
364         // buffer allocation. VELOCITY-606
365         if (first == last)
366         {
367             literal = NodeUtils.tokenLiteral(parser, first);
368             return literal;
369         }
370 
371         Token t = first;
372         StringBuilder sb = new StringBuilder(NodeUtils.tokenLiteral(parser, t));
373         while (t != last)
374         {
375             t = t.next;
376             sb.append(NodeUtils.tokenLiteral(parser, t));
377         }
378         literal = sb.toString();
379         return literal;
380     }
381 
382     /**
383      * @throws TemplateInitException
384      * @see org.apache.velocity.runtime.parser.node.Node#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)
385      */
386     @Override
init(InternalContextAdapter context, Object data)387     public Object init(InternalContextAdapter context, Object data) throws TemplateInitException
388     {
389         /*
390          * hold onto the RuntimeServices
391          */
392 
393         rsvc = (RuntimeServices) data;
394         log = rsvc.getLog("rendering");
395 
396         int i, k = jjtGetNumChildren();
397 
398         for (i = 0; i < k; i++)
399         {
400             jjtGetChild(i).init( context, data);
401         }
402 
403         line = first.beginLine;
404         column = first.beginColumn;
405 
406         return data;
407     }
408 
409     /**
410      * @see org.apache.velocity.runtime.parser.node.Node#evaluate(org.apache.velocity.context.InternalContextAdapter)
411      */
412     @Override
evaluate(InternalContextAdapter context)413     public boolean evaluate(InternalContextAdapter  context)
414         throws MethodInvocationException
415     {
416         return false;
417     }
418 
419     /**
420      * @see org.apache.velocity.runtime.parser.node.Node#value(org.apache.velocity.context.InternalContextAdapter)
421      */
422     @Override
value(InternalContextAdapter context)423     public Object value(InternalContextAdapter context)
424         throws MethodInvocationException
425     {
426         return null;
427     }
428 
429     /**
430      * @see org.apache.velocity.runtime.parser.node.Node#render(org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
431      */
432     @Override
render(InternalContextAdapter context, Writer writer)433     public boolean render(InternalContextAdapter context, Writer writer)
434         throws IOException, MethodInvocationException, ParseErrorException, ResourceNotFoundException
435     {
436         int i, k = jjtGetNumChildren();
437 
438         for (i = 0; i < k; i++)
439             jjtGetChild(i).render(context, writer);
440 
441         return true;
442     }
443 
444     /**
445      * @see org.apache.velocity.runtime.parser.node.Node#execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter)
446      */
447     @Override
execute(Object o, InternalContextAdapter context)448     public Object execute(Object o, InternalContextAdapter context)
449       throws MethodInvocationException
450     {
451         return null;
452     }
453 
454     /**
455      * @see org.apache.velocity.runtime.parser.node.Node#getType()
456      */
457     @Override
getType()458     public int getType()
459     {
460         return id;
461     }
462 
463     /**
464      * @see org.apache.velocity.runtime.parser.node.Node#setInfo(int)
465      */
466     @Override
setInfo(int info)467     public void setInfo(int info)
468     {
469         this.info = info;
470     }
471 
472     /**
473      * @see org.apache.velocity.runtime.parser.node.Node#getInfo()
474      */
475     @Override
getInfo()476     public int getInfo()
477     {
478         return info;
479     }
480 
481     /**
482      * @see org.apache.velocity.runtime.parser.node.Node#setInvalid()
483      */
484     @Override
setInvalid()485     public void setInvalid()
486     {
487         invalid = true;
488     }
489 
490     /**
491      * @see org.apache.velocity.runtime.parser.node.Node#isInvalid()
492      */
493     @Override
isInvalid()494     public boolean isInvalid()
495     {
496         return invalid;
497     }
498 
499     /**
500      * @see org.apache.velocity.runtime.parser.node.Node#getLine()
501      */
502     @Override
getLine()503     public int getLine()
504     {
505         return line;
506     }
507 
508     /**
509      * @see org.apache.velocity.runtime.parser.node.Node#getColumn()
510      */
511     @Override
getColumn()512     public int getColumn()
513     {
514         return column;
515     }
516 
517     /**
518      * @since 1.5
519      */
toString()520     public String toString()
521     {
522         StringBuilder tokens = new StringBuilder();
523 
524         for (Token t = getFirstToken(); t != null; )
525         {
526             tokens.append("[").append(t.image.replace("\n", "\\n")).append("]");
527             if (t.next != null)
528             {
529                 if (t.equals(getLastToken()))
530                 {
531                     break;
532                 }
533                 else
534                 {
535                     tokens.append(", ");
536                 }
537             }
538             t = t.next;
539         }
540         String tok = tokens.toString();
541         if (tok.length() > 50) tok = tok.substring(0, 50) + "...";
542         return getClass().getSimpleName() + " [id=" + id + ", info=" + info + ", invalid="
543                 + invalid
544                 + ", tokens=" + tok + "]";
545     }
546 
547     @Override
getTemplateName()548     public String getTemplateName()
549     {
550       return template.getName();
551     }
552 
553     /**
554      * Call before calling cleanupParserAndTokens() if you want to store image of
555      * the first and last token of this node.
556      */
saveTokenImages()557     public void saveTokenImages()
558     {
559         if( first != null )
560         {
561             this.firstImage = first.image;
562         }
563         if( last != null )
564         {
565             this.lastImage = last.image;
566         }
567     }
568 
569     /**
570      * Removes references to Parser and Tokens since they are not needed anymore at this point.
571      *
572      * This allows us to save memory quite a bit.
573      */
cleanupParserAndTokens()574     public void cleanupParserAndTokens()
575     {
576         this.parser = null;
577         this.first = null;
578         this.last = null;
579     }
580 
581     /**
582      * @return String image variable of the first Token element that was parsed and connected to this Node.
583      */
584     @Override
getFirstTokenImage()585     public String getFirstTokenImage()
586     {
587         return firstImage;
588     }
589 
590     /**
591      * @return String image variable of the last Token element that was parsed and connected to this Node.
592      */
593     @Override
getLastTokenImage()594     public String getLastTokenImage()
595     {
596         return lastImage;
597     }
598 
599     @Override
getTemplate()600     public Template getTemplate() { return template; }
601 
602     /**
603      * @return the parser which created this node
604      * @since 2.2
605      */
606     @Override
getParser()607     public Parser getParser()
608     {
609         return parser;
610     }
611 
612     /**
613      * Root node deep cloning
614      * @param template owner template
615      * @return cloned node
616      * @throws CloneNotSupportedException
617      * @since 2.4
618      */
clone(Template template)619     public Node clone(Template template) throws CloneNotSupportedException
620     {
621         if (parent != null) {
622             throw new IllegalStateException("cannot clone a child node without knowing its parent");
623         }
624         return clone(template, null);
625     }
626 
627     /**
628      * Child node deep cloning
629      * @param template owner template
630      * @param parent parent node
631      * @return cloned node
632      * @throws CloneNotSupportedException
633      * @since 2.4
634      */
clone(Template template, Node parent)635     protected Node clone(Template template, Node parent) throws CloneNotSupportedException
636     {
637         SimpleNode clone = (SimpleNode)super.clone();
638         clone.template = template;
639         clone.parent = parent;
640         if (children != null)
641         {
642             clone.children = new SimpleNode[children.length];
643             for (int i = 0; i < children.length; ++i)
644             {
645                 clone.children[i] = ((SimpleNode)children[i]).clone(template, clone);
646             }
647         }
648         return clone;
649     }
650 }
651