001: package org.apache.velocity.runtime.directive;
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 org.apache.velocity.exception.ExtendedParseException;
023: import org.apache.velocity.runtime.parser.ParseException;
024: import org.apache.velocity.runtime.parser.Token;
025:
026: /**
027: * Exception to indicate problem happened while constructing #macro()
028: *
029: * For internal use in parser - not to be passed to app level
030: *
031: * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
032: * @author <a href="hps@intermeta.de">Henning P. Schmiedehausen</a>
033: * @version $Id: MacroParseException.java 463298 2006-10-12 16:10:32Z henning $
034: */
035: public class MacroParseException extends ParseException implements
036: ExtendedParseException {
037: private final String templateName;
038:
039: /**
040: * Version Id for serializable
041: */
042: private static final long serialVersionUID = -4985224672336070689L;
043:
044: /**
045: * @param msg
046: * @param templateName
047: * @param currentToken
048: */
049: public MacroParseException(final String msg,
050: final String templateName, final Token currentToken) {
051: super (msg);
052: this .currentToken = currentToken;
053: this .templateName = templateName;
054: }
055:
056: /**
057: * returns the Template name where this exception occured.
058: * @return The Template name where this exception occured.
059: */
060: public String getTemplateName() {
061: return templateName;
062: }
063:
064: /**
065: * returns the line number where this exception occured.
066: * @return The line number where this exception occured.
067: */
068: public int getLineNumber() {
069: if ((currentToken != null) && (currentToken.next != null)) {
070: return currentToken.next.beginLine;
071: } else {
072: return -1;
073: }
074: }
075:
076: /**
077: * returns the column number where this exception occured.
078: * @return The column number where this exception occured.
079: */
080: public int getColumnNumber() {
081: if ((currentToken != null) && (currentToken.next != null)) {
082: return currentToken.next.beginColumn;
083: } else {
084: return -1;
085: }
086: }
087:
088: /**
089: * This method has the standard behavior when this object has been
090: * created using the standard constructors. Otherwise, it uses
091: * "currentToken" and "expectedTokenSequences" to generate a parse
092: * error message and returns it. If this object has been created
093: * due to a parse error, and you do not catch it (it gets thrown
094: * from the parser), then this method is called during the printing
095: * of the final stack trace, and hence the correct error message
096: * gets displayed.
097: * @return the current message.
098: */
099: public String getMessage() {
100: if (!specialConstructor) {
101: StringBuffer sb = new StringBuffer(super .getMessage());
102: appendTemplateInfo(sb);
103: return sb.toString();
104: }
105:
106: int maxSize = 0;
107:
108: StringBuffer expected = new StringBuffer();
109:
110: for (int i = 0; i < expectedTokenSequences.length; i++) {
111: if (maxSize < expectedTokenSequences[i].length) {
112: maxSize = expectedTokenSequences[i].length;
113: }
114:
115: for (int j = 0; j < expectedTokenSequences[i].length; j++) {
116: expected.append(
117: tokenImage[expectedTokenSequences[i][j]])
118: .append(" ");
119: }
120:
121: if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
122: expected.append("...");
123: }
124:
125: expected.append(eol).append(" ");
126: }
127:
128: StringBuffer retval = new StringBuffer("Encountered \"");
129: Token tok = currentToken.next;
130:
131: for (int i = 0; i < maxSize; i++) {
132: if (i != 0) {
133: retval.append(" ");
134: }
135:
136: if (tok.kind == 0) {
137: retval.append(tokenImage[0]);
138: break;
139: }
140:
141: retval.append(add_escapes(tok.image));
142: tok = tok.next;
143: }
144:
145: retval.append("\"");
146: appendTemplateInfo(retval);
147:
148: if (expectedTokenSequences.length == 1) {
149: retval.append("Was expecting:").append(eol).append(" ");
150: } else {
151: retval.append("Was expecting one of:").append(eol).append(
152: " ");
153: }
154:
155: // avoid JDK 1.3 StringBuffer.append(Object o) vs 1.4 StringBuffer.append(StringBuffer sb) gotcha.
156: retval.append(expected.toString());
157: return retval.toString();
158: }
159:
160: /**
161: * @param sb
162: */
163: protected void appendTemplateInfo(final StringBuffer sb) {
164: sb.append(" at line ").append(getLineNumber()).append(
165: ", column ").append(getColumnNumber());
166:
167: if (getTemplateName() != null) {
168: sb.append(" of ").append(getTemplateName());
169: } else {
170: sb.append(".");
171: }
172: sb.append(eol);
173: }
174: }
|