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 }