001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.binding.expression.support;
017:
018: import java.util.LinkedList;
019: import java.util.List;
020:
021: import org.springframework.binding.expression.Expression;
022: import org.springframework.binding.expression.ExpressionParser;
023: import org.springframework.binding.expression.ParserException;
024: import org.springframework.binding.expression.SettableExpression;
025: import org.springframework.util.StringUtils;
026:
027: /**
028: * Abstract base class for expression parsers.
029: *
030: * @author Keith Donald
031: * @author Erwin Vervaet
032: */
033: public abstract class AbstractExpressionParser implements
034: ExpressionParser {
035:
036: /**
037: * The expression prefix.
038: */
039: private static final String DEFAULT_EXPRESSION_PREFIX = "${";
040:
041: /**
042: * The expression suffix.
043: */
044: private static final String DEFAULT_EXPRESSION_SUFFIX = "}";
045:
046: /**
047: * The marked expression delimter prefix.
048: */
049: private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;
050:
051: /**
052: * The marked expression delimiter suffix.
053: */
054: private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;
055:
056: /**
057: * Returns the configured expression delimiter prefix. Defaults to "${".
058: */
059: public String getExpressionPrefix() {
060: return expressionPrefix;
061: }
062:
063: /**
064: * Sets the expression delimiter prefix.
065: */
066: public void setExpressionPrefix(String expressionPrefix) {
067: this .expressionPrefix = expressionPrefix;
068: }
069:
070: /**
071: * Returns the expression delimiter suffix. Defaults to "}".
072: */
073: public String getExpressionSuffix() {
074: return expressionSuffix;
075: }
076:
077: /**
078: * Sets the expression delimiter suffix.
079: */
080: public void setExpressionSuffix(String expressionSuffix) {
081: this .expressionSuffix = expressionSuffix;
082: }
083:
084: /**
085: * Check whether or not given criteria are expressed as an expression.
086: */
087: public boolean isDelimitedExpression(String expressionString) {
088: int prefixIndex = expressionString
089: .indexOf(getExpressionPrefix());
090: if (prefixIndex == -1) {
091: return false;
092: }
093: int suffixIndex = expressionString.indexOf(
094: getExpressionSuffix(), prefixIndex);
095: if (suffixIndex == -1) {
096: return false;
097: } else {
098: if (suffixIndex == prefixIndex
099: + getExpressionPrefix().length()) {
100: return false;
101: } else {
102: return true;
103: }
104: }
105: }
106:
107: public final Expression parseExpression(String expressionString)
108: throws ParserException {
109: Expression[] expressions = parseExpressions(expressionString);
110: if (expressions.length == 1) {
111: return expressions[0];
112: } else {
113: return new CompositeStringExpression(expressions);
114: }
115: }
116:
117: public final SettableExpression parseSettableExpression(
118: String expressionString) throws ParserException,
119: UnsupportedOperationException {
120: expressionString = expressionString.trim();
121: // a settable expression should just be a single expression
122: if (expressionString.startsWith(getExpressionPrefix())
123: && expressionString.endsWith(getExpressionSuffix())) {
124: expressionString = expressionString.substring(
125: getExpressionPrefix().length(), expressionString
126: .length()
127: - getExpressionSuffix().length());
128: }
129: return doParseSettableExpression(expressionString);
130: }
131:
132: /**
133: * Helper that parses given expression string using the configured parser.
134: * The expression string can contain any number of expressions all contained
135: * in "${...}" markers. For instance: "foo${expr0}bar${expr1}". The static
136: * pieces of text will also be returned as Expressions that just return that
137: * static piece of text. As a result, evaluating all returned expressions
138: * and concatenating the results produces the complete evaluated string.
139: * @param expressionString the expression string
140: * @return the parsed expressions
141: * @throws ParserException when the expressions cannot be parsed
142: */
143: private Expression[] parseExpressions(String expressionString)
144: throws ParserException {
145: List expressions = new LinkedList();
146: if (StringUtils.hasText(expressionString)) {
147: int startIdx = 0;
148: while (startIdx < expressionString.length()) {
149: int prefixIndex = expressionString.indexOf(
150: getExpressionPrefix(), startIdx);
151: if (prefixIndex >= startIdx) {
152: // an expression was found
153: if (prefixIndex > startIdx) {
154: expressions.add(new StaticExpression(
155: expressionString.substring(startIdx,
156: prefixIndex)));
157: startIdx = prefixIndex;
158: }
159: int nextPrefixIndex = expressionString.indexOf(
160: getExpressionPrefix(), prefixIndex
161: + getExpressionPrefix().length());
162: int suffixIndex;
163: if (nextPrefixIndex == -1) {
164: // this is the last expression in the expression string
165: suffixIndex = expressionString
166: .lastIndexOf(getExpressionSuffix());
167: } else {
168: // another expression exists after this one in the expression string
169: suffixIndex = expressionString.lastIndexOf(
170: getExpressionSuffix(), nextPrefixIndex);
171: }
172: if (suffixIndex < (prefixIndex + getExpressionPrefix()
173: .length())) {
174: throw new ParserException(
175: expressionString,
176: "No ending suffix '"
177: + getExpressionSuffix()
178: + "' for expression starting at character "
179: + prefixIndex
180: + ": "
181: + expressionString
182: .substring(prefixIndex),
183: null);
184: } else if (suffixIndex == prefixIndex
185: + getExpressionPrefix().length()) {
186: throw new ParserException(expressionString,
187: "No expression defined within delimiter '"
188: + getExpressionPrefix()
189: + getExpressionSuffix()
190: + "' at character "
191: + prefixIndex, null);
192: } else {
193: String expr = expressionString.substring(
194: prefixIndex
195: + getExpressionPrefix()
196: .length(), suffixIndex);
197: expressions.add(doParseExpression(expr));
198: startIdx = suffixIndex + 1;
199: }
200: } else {
201: if (startIdx == 0) {
202: // treat entire string as one expression
203: expressions
204: .add(doParseExpression(expressionString));
205: } else {
206: // no more ${expressions} found in string
207: expressions.add(new StaticExpression(
208: expressionString.substring(startIdx)));
209: }
210: startIdx = expressionString.length();
211: }
212: }
213: } else {
214: expressions.add(new StaticExpression(expressionString));
215: }
216: return (Expression[]) expressions
217: .toArray(new Expression[expressions.size()]);
218: }
219:
220: // template methods
221:
222: /**
223: * Template method for parsing a filtered expression string. Subclasses should
224: * override.
225: * @param expressionString the expression string
226: * @return the parsed expression
227: * @throws ParserException an exception occured during parsing
228: */
229: protected abstract Expression doParseExpression(
230: String expressionString) throws ParserException;
231:
232: /**
233: * Template method for parsing a filtered settable expression string. Subclasses
234: * should override.
235: * @param expressionString the expression string
236: * @return the parsed expression
237: * @throws ParserException an exception occured during parsing
238: * @throws UnsupportedOperationException this parser does not support
239: * settable expressions
240: */
241: protected abstract SettableExpression doParseSettableExpression(
242: String expressionString) throws ParserException,
243: UnsupportedOperationException;
244:
245: }
|