001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.xwork.util;
006:
007: import com.opensymphony.util.TextUtils;
008:
009: import java.util.HashSet;
010: import java.util.Set;
011:
012: /**
013: * Utility class for text parsing.
014: *
015: * @author Jason Carreira
016: * @author Rainer Hermanns
017: * @author tm_jee
018: *
019: * @version $Date: 2007-07-16 16:46:59 +0200 (Mon, 16 Jul 2007) $ $Id: TextParseUtil.java 1545 2007-07-16 14:46:59Z mrdon $
020: */
021: public class TextParseUtil {
022:
023: private static final int MAX_RECURSION = 1;
024:
025: /**
026: * Converts all instances of ${...} in <code>expression</code> to the value returned
027: * by a call to {@link OgnlValueStack#findValue(java.lang.String)}. If an item cannot
028: * be found on the stack (null is returned), then the entire variable ${...} is not
029: * displayed, just as if the item was on the stack but returned an empty string.
030: *
031: * @param expression an expression that hasn't yet been translated
032: * @return the parsed expression
033: */
034: public static String translateVariables(String expression,
035: OgnlValueStack stack) {
036: return translateVariables('$', expression, stack, String.class,
037: null).toString();
038: }
039:
040: /**
041: * Function similarly as {@link #translateVariables(char, String, OgnlValueStack)}
042: * except for the introduction of an additional <code>evaluator</code> that allows
043: * the parsed value to be evaluated by the <code>evaluator</code>. The <code>evaluator</code>
044: * could be null, if it is it will just be skipped as if it is just calling
045: * {@link #translateVariables(char, String, OgnlValueStack)}.
046: *
047: * <p/>
048: *
049: * A typical use-case would be when we need to URL Encode the parsed value. To do so
050: * we could just supply a URLEncodingEvaluator for example.
051: *
052: * @see {@link TextParseUtil.ParsedValueEvaluator}
053: * @param expression
054: * @param stack
055: * @param evaluator The parsed Value evaluator (could be null).
056: * @return the parsed (and possibly evaluated) variable String.
057: */
058: public static String translateVariables(String expression,
059: OgnlValueStack stack, ParsedValueEvaluator evaluator) {
060: return translateVariables('$', expression, stack, String.class,
061: evaluator).toString();
062: }
063:
064: /**
065: * Converts all instances of ${...} in <code>expression</code> to the value returned
066: * by a call to {@link OgnlValueStack#findValue(java.lang.String)}. If an item cannot
067: * be found on the stack (null is returned), then the entire variable ${...} is not
068: * displayed, just as if the item was on the stack but returned an empty string.
069: *
070: * @param open
071: * @param expression
072: * @param stack
073: * @return Translated variable String
074: */
075: public static String translateVariables(char open,
076: String expression, OgnlValueStack stack) {
077: return translateVariables(open, expression, stack,
078: String.class, null).toString();
079: }
080:
081: /**
082: * Converted object from variable translation.
083: *
084: * @param open
085: * @param expression
086: * @param stack
087: * @param asType
088: * @return Converted object from variable translation.
089: */
090: public static Object translateVariables(char open,
091: String expression, OgnlValueStack stack, Class asType) {
092: return translateVariables(open, expression, stack, asType, null);
093: }
094:
095: /**
096: * Converted object from variable translation.
097: *
098: * @param open
099: * @param expression
100: * @param stack
101: * @param asType
102: * @param evaluator
103: * @return Converted object from variable translation.
104: */
105: public static Object translateVariables(char open,
106: String expression, OgnlValueStack stack, Class asType,
107: ParsedValueEvaluator evaluator) {
108: return translateVariables(open, expression, stack, asType,
109: evaluator, MAX_RECURSION);
110: }
111:
112: /**
113: * Converted object from variable translation.
114: *
115: * @param open
116: * @param expression
117: * @param stack
118: * @param asType
119: * @param evaluator
120: * @return Converted object from variable translation.
121: */
122: public static Object translateVariables(char open,
123: String expression, OgnlValueStack stack, Class asType,
124: ParsedValueEvaluator evaluator, int maxLoopCount) {
125: // deal with the "pure" expressions first!
126: //expression = expression.trim();
127: Object result = expression;
128: int loopCount = 1;
129: int pos = 0;
130: while (true) {
131:
132: int start = expression.indexOf(open + "{", pos);
133: if (start == -1) {
134: pos = 0;
135: loopCount++;
136: start = expression.indexOf(open + "{");
137: }
138: if (loopCount > maxLoopCount) {
139: // translateVariables prevent infinite loop / expression recursive evaluation
140: break;
141: }
142: int length = expression.length();
143: int x = start + 2;
144: int end;
145: char c;
146: int count = 1;
147: while (start != -1 && x < length && count != 0) {
148: c = expression.charAt(x++);
149: if (c == '{') {
150: count++;
151: } else if (c == '}') {
152: count--;
153: }
154: }
155: end = x - 1;
156:
157: if ((start != -1) && (end != -1) && (count == 0)) {
158: String var = expression.substring(start + 2, end);
159:
160: Object o = stack.findValue(var, asType);
161: if (evaluator != null) {
162: o = evaluator.evaluate(o);
163: }
164:
165: String left = expression.substring(0, start);
166: String right = expression.substring(end + 1);
167: String middle = null;
168: if (o != null) {
169: middle = o.toString();
170: if (!TextUtils.stringSet(left)) {
171: result = o;
172: } else {
173: result = left + middle;
174: }
175:
176: if (TextUtils.stringSet(right)) {
177: result = result + right;
178: }
179:
180: expression = left + middle + right;
181: } else {
182: // the variable doesn't exist, so don't display anything
183: result = left + right;
184: expression = left + right;
185: }
186: pos = (left != null && left.length() > 0 ? left
187: .length() - 1 : 0)
188: + (middle != null && middle.length() > 0 ? middle
189: .length() - 1
190: : 0) + 1;
191: pos = Math.max(pos, 1);
192: } else {
193: break;
194: }
195: }
196:
197: return XWorkConverter.getInstance().convertValue(
198: stack.getContext(), result, asType);
199: }
200:
201: /**
202: * Returns a set from comma delimted Strings.
203: * @param s The String to parse.
204: * @return A set from comma delimted Strings.
205: */
206: public static Set commaDelimitedStringToSet(String s) {
207: Set set = new HashSet();
208: String[] split = s.split(",");
209: for (int i = 0; i < split.length; i++) {
210: String trimmed = split[i].trim();
211: if (trimmed.length() > 0)
212: set.add(trimmed);
213: }
214: return set;
215: }
216:
217: /**
218: * A parsed value evaluator for {@link TextParseUtil}. It could be supplied by
219: * calling {@link TextParseUtil#translateVariables(char, String, OgnlValueStack, Class, ParsedValueEvaluator)}.
220: *
221: * <p/>
222: *
223: * By supplying this <code>ParsedValueEvaluator</code>, the parsed value
224: * (parsed against the value stack) value will be
225: * given to <code>ParsedValueEvaluator</code> to be evaluated before the
226: * translateVariable process goes on.
227: *
228: * <p/>
229: *
230: * A typical use-case would be to have a custom <code>ParseValueEvaluator</code>
231: * to URL Encode the parsed value.
232: *
233: * @author tm_jee
234: *
235: * @version $Date: 2007-07-16 16:46:59 +0200 (Mon, 16 Jul 2007) $ $Id: TextParseUtil.java 1545 2007-07-16 14:46:59Z mrdon $
236: */
237: public static interface ParsedValueEvaluator {
238:
239: /**
240: * Evaluated the value parsed by Ognl value stack.
241: *
242: * @param parsedValue - value parsed by ognl value stack
243: * @return return the evaluted value.
244: */
245: Object evaluate(Object parsedValue);
246: }
247: }
|