001: /*
002: * Copyright 2002,2004 The Apache Software Foundation.
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.apache.commons.jelly.expression;
017:
018: import java.util.ArrayList;
019: import java.util.Collections;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.commons.collections.iterators.SingletonIterator;
024:
025: import org.apache.commons.jelly.JellyContext;
026: import org.apache.commons.jelly.JellyException;
027:
028: /**
029: * <p><code>CompositeExpression</code> is a Composite expression made up of several
030: * Expression objects which are concatenated into a single String.</p>
031: *
032: * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
033: * @version $Revision: 155420 $
034: */
035: public class CompositeExpression extends ExpressionSupport {
036:
037: /** The expressions */
038: private List expressions;
039:
040: public CompositeExpression() {
041: this .expressions = new ArrayList();
042: }
043:
044: public CompositeExpression(List expressions) {
045: this .expressions = expressions;
046: }
047:
048: public String toString() {
049: return super .toString() + "[expressions=" + expressions + "]";
050: }
051:
052: /**
053: * Parses the given String to be either a ConstantExpresssion, an Expression denoted as
054: * "${foo}" or some String with embedded expresssions such as "abc${something}def${else}xyz"
055: * which results in a CompositeExpression being returned.
056: *
057: * @param text is the String to parse into expressions
058: * @param factory is the Factory of Expression objects used to create expresssions for the contents
059: * of the String "foo" inside expressions such as "${foo}"
060: *
061: * @return the Expresssion for the given String.
062: * @throws JellyException if the text is invalid (such as missing '}' character).
063: * @throws JellyException if there was some problem creating the underlying Expression object
064: * from the ExpressionFactory
065: */
066: public static Expression parse(String text,
067: ExpressionFactory factory) throws JellyException {
068:
069: int len = text.length();
070:
071: int startIndex = text.indexOf("${");
072:
073: if (startIndex < 0) {
074: return new ConstantExpression(text);
075: }
076:
077: int endIndex = text.indexOf("}", startIndex + 2);
078:
079: if (endIndex < 0) {
080: throw new JellyException(
081: "Missing '}' character at the end of expression: "
082: + text);
083: }
084: if (startIndex == 0 && endIndex == len - 1) {
085: return factory
086: .createExpression(text.substring(2, endIndex));
087: }
088:
089: CompositeExpression answer = new CompositeExpression();
090:
091: int cur = 0;
092: char c = 0;
093:
094: StringBuffer chars = new StringBuffer();
095: StringBuffer expr = new StringBuffer();
096:
097: MAIN: while (cur < len) {
098: c = text.charAt(cur);
099:
100: switch (c) {
101: case ('$'):
102: if (cur + 1 < len) {
103: ++cur;
104: c = text.charAt(cur);
105:
106: switch (c) {
107: case ('$'):
108: chars.append(c);
109: break;
110: case ('{'):
111: if (chars.length() > 0) {
112: answer.addTextExpression(chars.toString());
113: chars.delete(0, chars.length());
114: }
115:
116: if (cur + 1 < len) {
117: ++cur;
118:
119: while (cur < len) {
120: c = text.charAt(cur);
121: switch (c) {
122: case ('"'):
123: expr.append(c);
124: ++cur;
125:
126: DOUBLE_QUOTE: while (cur < len) {
127: c = text.charAt(cur);
128:
129: switch (c) {
130: case ('\\'):
131: ++cur;
132: expr.append(c);
133: break;
134: case ('"'):
135: ++cur;
136: expr.append(c);
137: break DOUBLE_QUOTE;
138: default:
139: ++cur;
140: expr.append(c);
141: } // switch
142: } // while
143: break;
144: case ('\''):
145: expr.append(c);
146: ++cur;
147:
148: SINGLE_QUOTE: while (cur < len) {
149: c = text.charAt(cur);
150:
151: switch (c) {
152: case ('\\'):
153: ++cur;
154: expr.append(c);
155: break;
156: case ('\''):
157: ++cur;
158: expr.append(c);
159: break SINGLE_QUOTE;
160: default:
161: ++cur;
162: expr.append(c);
163: } // switch
164: } // while
165: break;
166: case ('}'):
167: answer.addExpression(factory
168: .createExpression(expr
169: .toString()));
170: expr.delete(0, expr.length());
171: ++cur;
172: continue MAIN;
173: default:
174: expr.append(c);
175: ++cur;
176: }
177: }
178: }
179: break;
180: default:
181: chars.append(c);
182: }
183: } else {
184: chars.append(c);
185: }
186: break;
187: default:
188: chars.append(c);
189: }
190: ++cur;
191: }
192:
193: if (chars.length() > 0) {
194: answer.addTextExpression(chars.toString());
195: }
196:
197: return answer;
198: }
199:
200: // Properties
201: //-------------------------------------------------------------------------
202:
203: /**
204: * @return the Expression objects that make up this
205: * composite expression
206: */
207: public List getExpressions() {
208: return expressions;
209: }
210:
211: /**
212: * Sets the Expression objects that make up this
213: * composite expression
214: */
215: public void setExpressions(List expressions) {
216: this .expressions = expressions;
217: }
218:
219: /**
220: * Adds a new expression to the end of the expression list
221: */
222: public void addExpression(Expression expression) {
223: expressions.add(expression);
224: }
225:
226: /**
227: * A helper method to add a new constant text expression
228: */
229: public void addTextExpression(String text) {
230: addExpression(new ConstantExpression(text));
231: }
232:
233: // Expression interface
234: //-------------------------------------------------------------------------
235:
236: public String getExpressionText() {
237: StringBuffer buffer = new StringBuffer();
238: for (Iterator iter = expressions.iterator(); iter.hasNext();) {
239: Expression expression = (Expression) iter.next();
240: buffer.append(expression.getExpressionText());
241: }
242: return buffer.toString();
243: }
244:
245: // inherit javadoc from interface
246: public Object evaluate(JellyContext context) {
247: return evaluateAsString(context);
248: }
249:
250: // inherit javadoc from interface
251: public String evaluateAsString(JellyContext context) {
252: StringBuffer buffer = new StringBuffer();
253: for (Iterator iter = expressions.iterator(); iter.hasNext();) {
254: Expression expression = (Expression) iter.next();
255: String value = expression.evaluateAsString(context);
256: if (value != null) {
257: buffer.append(value);
258: }
259: }
260: return buffer.toString();
261:
262: }
263:
264: // inherit javadoc from interface
265: public Iterator evaluateAsIterator(JellyContext context) {
266: String value = evaluateAsString(context);
267: if (value == null) {
268: return Collections.EMPTY_LIST.iterator();
269: } else {
270: return new SingletonIterator(value);
271: }
272: }
273: }
|