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 org.apache.velocity.context.Context;
23  import org.apache.velocity.exception.MethodInvocationException;
24  import org.apache.velocity.runtime.parser.Token;
25  
26  /**
27   * Utilities for dealing with the AST node structure.
28   *
29   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
30   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
31   * @version $Id: NodeUtils.java 463298 2006-10-12 16:10:32Z henning $
32   */
33  public class NodeUtils
34  {
35      /**
36       * Collect all the <SPECIAL_TOKEN>s that
37       * are carried along with a token. Special
38       * tokens do not participate in parsing but
39       * can still trigger certain lexical actions.
40       * In some cases you may want to retrieve these
41       * special tokens, this is simply a way to
42       * extract them.
43       * @param t
44       * @return String with the special tokens.
45       */
46      public static String specialText(Token t)
47      {
48          StringBuffer specialText = new StringBuffer();
49  
50          if (t.specialToken == null || t.specialToken.image.startsWith("##") )
51          {
52              return "";
53          }
54  
55          Token tmp_t = t.specialToken;
56  
57          while (tmp_t.specialToken != null)
58          {
59              tmp_t = tmp_t.specialToken;
60          }
61  
62          while (tmp_t != null)
63          {
64              String st = tmp_t.image;
65  
66              StringBuffer sb = new StringBuffer();
67  
68              for(int i = 0; i < st.length(); i++)
69              {
70                  char c = st.charAt(i);
71  
72                  if ( c == '#' || c == '$' )
73                  {
74                      sb.append( c );
75                  }
76  
77                  /*
78                   *  more dreaded MORE hack :)
79                   *
80                   *  looking for ("\\")*"$" sequences
81                   */
82  
83                  if ( c == '\\')
84                  {
85                      boolean ok = true;
86                      boolean term = false;
87  
88                      int j = i;
89                      for( ok = true; ok && j < st.length(); j++)
90                      {
91                          char cc = st.charAt( j );
92  
93                          if (cc == '\\')
94                          {
95                              /*
96                               *  if we see a \, keep going
97                               */
98                              continue;
99                          }
100                         else if( cc == '$' )
101                         {
102                             /*
103                              *  a $ ends it correctly
104                              */
105                             term = true;
106                             ok = false;
107                         }
108                         else
109                         {
110                             /*
111                              *  nah...
112                              */
113                             ok = false;
114                         }
115                     }
116 
117                     if (term)
118                     {
119                         String foo =  st.substring( i, j );
120                         sb.append( foo );
121                         i = j;
122                     }
123                 }
124             }
125 
126             // This is a potential JDK 1.3/JDK 1.4 gotcha. If we remove
127             // the toString() method call, then when compiling under JDK 1.4,
128             // this will be mapped to StringBuffer.append(StringBuffer) and
129             // under JDK 1.3, it will be mapped to StringBuffer.append(Object).
130             // So the JDK 1.4 compiled jar will bomb out under JDK 1.3 with a
131             // MethodNotFound error.
132             //
133             // @todo Once we are JDK 1.4+ only, remove the toString(), make this
134             // loop perform a little bit better.
135             specialText.append(sb.toString());
136 
137             tmp_t = tmp_t.next;
138         }
139 
140         return specialText.toString();
141     }
142 
143     /**
144      *  complete node literal
145      * @param t
146      * @return A node literal.
147      *
148      */
149     public static String tokenLiteral( Token t )
150     {
151         return specialText( t ) + t.image;
152     }
153 
154     /**
155      * Utility method to interpolate context variables
156      * into string literals. So that the following will
157      * work:
158      *
159      * #set $name = "candy"
160      * $image.getURI("${name}.jpg")
161      *
162      * And the string literal argument will
163      * be transformed into "candy.jpg" before
164      * the method is executed.
165      * @param argStr
166      * @param vars
167      * @return Interpoliation result.
168      * @throws MethodInvocationException
169      */
170     public static String interpolate(String argStr, Context vars) throws MethodInvocationException
171     {
172         StringBuffer argBuf = new StringBuffer();
173 
174         for (int cIdx = 0 ; cIdx < argStr.length();)
175         {
176             char ch = argStr.charAt(cIdx);
177 
178             switch (ch)
179             {
180                 case '$':
181                     StringBuffer nameBuf = new StringBuffer();
182                     for (++cIdx ; cIdx < argStr.length(); ++cIdx)
183                     {
184                         ch = argStr.charAt(cIdx);
185                         if (ch == '_' || ch == '-'
186                             || Character.isLetterOrDigit(ch))
187                             nameBuf.append(ch);
188                         else if (ch == '{' || ch == '}')
189                             continue;
190                         else
191                             break;
192                     }
193 
194                     if (nameBuf.length() > 0)
195                     {
196                         Object value = vars.get(nameBuf.toString());
197 
198                         if (value == null)
199                             argBuf.append("$").append(nameBuf.toString());
200                         else
201                             argBuf.append(value.toString());
202                     }
203                     break;
204 
205                 default:
206                     argBuf.append(ch);
207                     ++cIdx;
208                     break;
209             }
210         }
211 
212         return argBuf.toString();
213     }
214 }