View Javadoc

1   package org.apache.velocity.runtime.parser;
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.exception.ExtendedParseException;
23  import org.apache.velocity.runtime.log.Log;
24  
25  
26  /**
27   * This is an extension of the ParseException, which also takes a
28   * template name.
29   *
30   * @see org.apache.velocity.runtime.parser.ParseException
31   *
32   * @author <a href="hps@intermeta.de">Henning P. Schmiedehausen</a>
33   * @version $Id: TemplateParseException.java 703544 2008-10-10 18:15:53Z nbubna $
34   * @since 1.5
35   */
36  public class TemplateParseException
37          extends ParseException
38          implements ExtendedParseException
39  {
40      private static final long serialVersionUID = -3146323135623083918L;
41  
42      /**
43       * This is the name of the template which contains the parsing error, or
44       * null if not defined.
45       */
46      private final String templateName;
47  
48      /**
49       * This constructor is used to add a template name
50       * to info cribbed from a ParseException generated in the parser.
51       * @param currentTokenVal
52       * @param expectedTokenSequencesVal
53       * @param tokenImageVal
54       * @param templateNameVal
55       */
56      public TemplateParseException(Token currentTokenVal, int [][] expectedTokenSequencesVal, String [] tokenImageVal,
57          String templateNameVal)
58      {
59          super(currentTokenVal, expectedTokenSequencesVal, tokenImageVal);
60          this.templateName = templateNameVal;
61      }
62  
63      /**
64       * This constructor is used by the method "generateParseException"
65       * in the generated parser.  Calling this constructor generates
66       * a new object of this type with the fields "currentToken",
67       * "expectedTokenSequences", and "tokenImage" set.  The boolean
68       * flag "specialConstructor" is also set to true to indicate that
69       * this constructor was used to create this object.
70       * This constructor calls its super class with the empty string
71       * to force the "toString" method of parent class "Throwable" to
72       * print the error message in the form:
73       *     ParseException: <result of getMessage>
74       * @param currentTokenVal
75       * @param expectedTokenSequencesVal
76       * @param tokenImageVal
77       */
78      public TemplateParseException(Token currentTokenVal, int [][] expectedTokenSequencesVal, String [] tokenImageVal)
79      {
80          super(currentTokenVal, expectedTokenSequencesVal, tokenImageVal);
81          templateName = "*unset*";
82      }
83  
84      /**
85       * The following constructors are for use by you for whatever
86       * purpose you can think of.  Constructing the exception in this
87       * manner makes the exception behave in the normal way - i.e., as
88       * documented in the class "Throwable".  The fields "errorToken",
89       * "expectedTokenSequences", and "tokenImage" do not contain
90       * relevant information.  The JavaCC generated code does not use
91       * these constructors.
92       */
93      public TemplateParseException()
94      {
95          super();
96          templateName = "*unset*";
97      }
98  
99      /**
100      * Creates a new TemplateParseException object.
101      *
102      * @param message TODO: DOCUMENT ME!
103      */
104     public TemplateParseException(String message)
105     {
106         super(message);
107         templateName = "*unset*";
108     }
109 
110     /**
111      * returns the Template name where this exception occured.
112      * @return The Template name where this exception occured.
113      */
114     public String getTemplateName()
115     {
116         return templateName;
117     }
118 
119     /**
120      * returns the line number where this exception occured.
121      * @return The line number where this exception occured.
122      */
123     public int getLineNumber()
124     {
125         if ((currentToken != null) && (currentToken.next != null))
126         {
127             return currentToken.next.beginLine;
128         }
129         else
130         {
131             return -1;
132         }
133     }
134 
135     /**
136      * returns the column number where this exception occured.
137      * @return The column number where this exception occured.
138      */
139     public int getColumnNumber()
140     {
141         if ((currentToken != null) && (currentToken.next != null))
142         {
143             return currentToken.next.beginColumn;
144         }
145         else
146         {
147             return -1;
148         }
149     }
150 
151     /**
152      * This method has the standard behavior when this object has been
153      * created using the standard constructors.  Otherwise, it uses
154      * "currentToken" and "expectedTokenSequences" to generate a parse
155      * error message and returns it.  If this object has been created
156      * due to a parse error, and you do not catch it (it gets thrown
157      * from the parser), then this method is called during the printing
158      * of the final stack trace, and hence the correct error message
159      * gets displayed.
160      * @return The error message.
161      */
162     public String getMessage()
163     {
164         if (!specialConstructor)
165         {
166             StringBuffer sb = new StringBuffer(super.getMessage());
167             appendTemplateInfo(sb);
168             return sb.toString();
169         }
170 
171         int maxSize = 0;
172 
173         StringBuffer expected = new StringBuffer();
174 
175         for (int i = 0; i < expectedTokenSequences.length; i++)
176         {
177             if (maxSize < expectedTokenSequences[i].length)
178             {
179                 maxSize = expectedTokenSequences[i].length;
180             }
181 
182             for (int j = 0; j < expectedTokenSequences[i].length; j++)
183             {
184                 expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
185             }
186 
187             if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0)
188             {
189                 expected.append("...");
190             }
191 
192             expected.append(eol).append("    ");
193         }
194 
195         StringBuffer retval = new StringBuffer("Encountered \"");
196         Token tok = currentToken.next;
197 
198         for (int i = 0; i < maxSize; i++)
199         {
200             if (i != 0)
201             {
202                 retval.append(" ");
203             }
204 
205             if (tok.kind == 0)
206             {
207                 retval.append(tokenImage[0]);
208                 break;
209             }
210 
211             retval.append(add_escapes(tok.image));
212             tok = tok.next;
213         }
214 
215         retval.append("\" at ");
216         appendTemplateInfo(retval);
217 
218         if (expectedTokenSequences.length == 1)
219         {
220             retval.append("Was expecting:").append(eol).append("    ");
221         }
222         else
223         {
224             retval.append("Was expecting one of:").append(eol).append("    ");
225         }
226 
227         // avoid JDK 1.3 StringBuffer.append(Object o) vs 1.4 StringBuffer.append(StringBuffer sb) gotcha.
228         retval.append(expected.toString());
229         return retval.toString();
230     }
231 
232     /**
233      * @param sb
234      */
235     protected void appendTemplateInfo(final StringBuffer sb)
236     {
237         sb.append(Log.formatFileString(getTemplateName(), getLineNumber(), getColumnNumber()));
238         sb.append(eol);
239     }
240 }