KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > base > util > string > FlexibleStringExpander


1 /*
2  * $Id: FlexibleStringExpander.java 5720 2005-09-13 03:10:59Z jonesde $
3  *
4  * Copyright (c) 2003 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */

24 package org.ofbiz.base.util.string;
25
26 import java.io.Serializable JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Locale JavaDoc;
31 import java.util.Map JavaDoc;
32
33 import org.ofbiz.base.util.BshUtil;
34 import org.ofbiz.base.util.Debug;
35 import org.ofbiz.base.util.collections.FlexibleMapAccessor;
36
37 import bsh.EvalError;
38
39 /**
40  * Expands string values with in a Map context supporting the ${} syntax for
41  * variable placeholders and the "." (dot) and "[]" (square-brace) syntax
42  * elements for accessing Map entries and List elements in the context.
43  *
44  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
45  * @version $Rev: 5720 $
46  * @since 2.2
47  */

48 public class FlexibleStringExpander implements Serializable JavaDoc {
49     
50     public static final String JavaDoc module = FlexibleStringExpander.class.getName();
51     
52     protected String JavaDoc original;
53     protected List JavaDoc stringElements = new LinkedList JavaDoc();
54     
55     public FlexibleStringExpander(String JavaDoc original) {
56         this.original = original;
57         
58         ParseElementHandler handler = new PreParseHandler(stringElements);
59         parseString(original, handler);
60     }
61     
62     public boolean isEmpty() {
63         if (this.original == null || this.original.length() == 0) {
64             return true;
65         } else {
66             return false;
67         }
68     }
69     
70     public String JavaDoc getOriginal() {
71         return this.original;
72     }
73
74     /**
75      * This expands the pre-parsed String given the context passed in. Note that
76      * pre-parsing can only parse the top-level place-holders and if there are
77      * nested expansions they will be done on the fly instead of pre-parsed because
78      * they are dependent on the context which isn't known until expansion time.
79      *
80      * @param context A context Map containing the variable values
81      * @return The original String expanded by replacing varaible place holders.
82      */

83     public String JavaDoc expandString(Map JavaDoc context) {
84         return this.expandString(context, null);
85     }
86     
87     /**
88      * This expands the pre-parsed String given the context passed in. Note that
89      * pre-parsing can only parse the top-level place-holders and if there are
90      * nested expansions they will be done on the fly instead of pre-parsed because
91      * they are dependent on the context which isn't known until expansion time.
92      *
93      * @param context A context Map containing the variable values
94      * @return The original String expanded by replacing varaible place holders.
95      */

96     public String JavaDoc expandString(Map JavaDoc context, Locale JavaDoc locale) {
97         StringBuffer JavaDoc expanded = new StringBuffer JavaDoc();
98         
99         Iterator JavaDoc stringElementIter = stringElements.iterator();
100         while (stringElementIter.hasNext()) {
101             StringElement element = (StringElement) stringElementIter.next();
102             element.appendElement(expanded, context, locale);
103         }
104         
105         //call back into this method with new String to take care of any/all nested expands
106
return expandString(expanded.toString(), context);
107     }
108     
109     /**
110      * Does on-the-fly parsing and expansion of the original String using
111      * varaible values from the passed context. Variables are denoted with
112      * the "${}" syntax and the variable name inside the curly-braces can use
113      * the "." (dot) syntax to access sub-Map entries and the "[]" square-brace
114      * syntax to access List elements.
115      *
116      * @param original The original String that will be expanded
117      * @param context A context Map containing the variable values
118      * @return The original String expanded by replacing varaible place holders.
119      */

120     public static String JavaDoc expandString(String JavaDoc original, Map JavaDoc context) {
121         return expandString(original, context, null);
122     }
123     
124     /**
125      * Does on-the-fly parsing and expansion of the original String using
126      * varaible values from the passed context. Variables are denoted with
127      * the "${}" syntax and the variable name inside the curly-braces can use
128      * the "." (dot) syntax to access sub-Map entries and the "[]" square-brace
129      * syntax to access List elements.
130      *
131      * @param original The original String that will be expanded
132      * @param context A context Map containing the variable values
133      * @return The original String expanded by replacing varaible place holders.
134      */

135     public static String JavaDoc expandString(String JavaDoc original, Map JavaDoc context, Locale JavaDoc locale) {
136         // if null or less than 3 return original; 3 chars because that is the minimum necessary for a ${}
137
if (original == null || original.length() < 3) {
138             return original;
139         }
140         
141         // start by checking to see if expansion is necessary for better performance
142
// this is also necessary for the nested stuff since this will be the stopping point for nested expansions
143
int start = original.indexOf("${");
144         if (start == -1) {
145             return original;
146         } else {
147             if (original.indexOf("}", start) == -1) {
148                 //no ending for the start, so we also have a stop condition
149
Debug.logWarning("Found a ${ without a closing } (curly-brace) in the String: " + original, module);
150                 return original;
151             }
152         }
153         
154         StringBuffer JavaDoc expanded = new StringBuffer JavaDoc();
155         ParseElementHandler handler = new OnTheFlyHandler(expanded, context, locale);
156         parseString(original, handler);
157         
158         //call back into this method with new String to take care of any/all nested expands
159
return expandString(expanded.toString(), context);
160     }
161     
162     public static void parseString(String JavaDoc original, ParseElementHandler handler) {
163         if (original == null || original.length() == 0) {
164             return;
165         }
166         
167         int start = original.indexOf("${");
168         if (start == -1) {
169             handler.handleConstant(original, 0);
170             return;
171         }
172         int currentInd = 0;
173         int end = -1;
174         while (start != -1) {
175             end = original.indexOf("}", start);
176             if (end == -1) {
177                 Debug.logWarning("Found a ${ without a closing } (curly-brace) in the String: " + original, module);
178                 break;
179             }
180             
181             // check to see if there is a nested ${}, ie something like ${foo.${bar}} or ${foo[$bar}]}
182
// since we are only handling one at a time, and then recusively looking for nested ones, just look backward from the } for another ${ and if found and is not the same start spot, update the start spot
183
int possibleNestedStart = original.lastIndexOf("${", end);
184             if (start != possibleNestedStart) {
185                 // found a nested one, could print something here, but just do the simple thing...
186
start = possibleNestedStart;
187             }
188             
189             // append everything from the current index to the start of the var
190
handler.handleConstant(original, currentInd, start);
191             
192             // check to see if this starts with a "bsh:", if so treat the rest of the string as a bsh scriptlet
193
if (original.indexOf("bsh:", start+2) == start+2) {
194                 // get the bsh scriptlet and append it
195
handler.handleBsh(original, start+6, end);
196             } else {
197                 // get the environment value and append it
198
handler.handleVariable(original, start+2, end);
199             }
200             
201             // reset the current index to after the var, and the start to the beginning of the next var
202
currentInd = end + 1;
203             start = original.indexOf("${", currentInd);
204         }
205         
206         // append the rest of the original string, ie after the last variable
207
if (currentInd < original.length()) {
208             handler.handleConstant(original, currentInd);
209         }
210     }
211
212     public static interface StringElement extends Serializable JavaDoc {
213         public void appendElement(StringBuffer JavaDoc buffer, Map JavaDoc context, Locale JavaDoc locale);
214     }
215     
216     public static class ConstantElement implements StringElement {
217         protected String JavaDoc value;
218         
219         public ConstantElement(String JavaDoc value) {
220             this.value = value;
221         }
222         
223         public void appendElement(StringBuffer JavaDoc buffer, Map JavaDoc context, Locale JavaDoc locale) {
224             buffer.append(this.value);
225         }
226     }
227     
228     public static class BshElement implements StringElement {
229         String JavaDoc scriptlet;
230         
231         public BshElement(String JavaDoc scriptlet) {
232             this.scriptlet = scriptlet;
233         }
234         
235         public void appendElement(StringBuffer JavaDoc buffer, Map JavaDoc context, Locale JavaDoc locale) {
236             try {
237                 Object JavaDoc scriptResult = BshUtil.eval(scriptlet, context);
238                 if (scriptResult != null) {
239                     buffer.append(scriptResult.toString());
240                 } else {
241                     Debug.logWarning("BSH scriplet evaluated to null [" + scriptlet + "], got no return so inserting nothing.", module);
242                 }
243             } catch (EvalError e) {
244                 Debug.logWarning(e, "Error evaluating BSH scriplet [" + scriptlet + "], inserting nothing; error was: " + e.toString(), module);
245             }
246         }
247     }
248     public static class VariableElement implements StringElement {
249         protected FlexibleMapAccessor fma;
250         
251         public VariableElement(String JavaDoc valueName) {
252             this.fma = new FlexibleMapAccessor(valueName);
253         }
254         
255         public void appendElement(StringBuffer JavaDoc buffer, Map JavaDoc context, Locale JavaDoc locale) {
256             Object JavaDoc retVal = fma.get(context, locale);
257             if (retVal != null) {
258                 buffer.append(retVal.toString());
259             } else {
260                 // otherwise do nothing
261
}
262         }
263     }
264
265     public static interface ParseElementHandler extends Serializable JavaDoc {
266         public void handleConstant(String JavaDoc original, int start);
267         public void handleConstant(String JavaDoc original, int start, int end);
268         public void handleVariable(String JavaDoc original, int start, int end);
269         public void handleBsh(String JavaDoc original, int start, int end);
270     }
271     
272     public static class PreParseHandler implements ParseElementHandler {
273         protected List JavaDoc stringElements;
274         
275         public PreParseHandler(List JavaDoc stringElements) {
276             this.stringElements = stringElements;
277         }
278         
279         public void handleConstant(String JavaDoc original, int start) {
280             stringElements.add(new ConstantElement(original.substring(start)));
281         }
282         
283         public void handleConstant(String JavaDoc original, int start, int end) {
284             stringElements.add(new ConstantElement(original.substring(start, end)));
285         }
286         
287         public void handleVariable(String JavaDoc original, int start, int end) {
288             stringElements.add(new VariableElement(original.substring(start, end)));
289         }
290
291         public void handleBsh(String JavaDoc original, int start, int end) {
292             stringElements.add(new BshElement(original.substring(start, end)));
293         }
294     }
295     
296     public static class OnTheFlyHandler implements ParseElementHandler {
297         protected StringBuffer JavaDoc targetBuffer;
298         protected Map JavaDoc context;
299         protected Locale JavaDoc locale;
300         
301         public OnTheFlyHandler(StringBuffer JavaDoc targetBuffer, Map JavaDoc context, Locale JavaDoc locale) {
302             this.targetBuffer = targetBuffer;
303             this.context = context;
304             this.locale = locale;
305         }
306         
307         public void handleConstant(String JavaDoc original, int start) {
308             targetBuffer.append(original.substring(start));
309         }
310         
311         public void handleConstant(String JavaDoc original, int start, int end) {
312             targetBuffer.append(original.substring(start, end));
313         }
314         
315         public void handleVariable(String JavaDoc original, int start, int end) {
316             //get the environment value and append it
317
String JavaDoc envName = original.substring(start, end);
318             FlexibleMapAccessor fma = new FlexibleMapAccessor(envName);
319             Object JavaDoc envVal = fma.get(context, locale);
320             if (envVal != null) {
321                 targetBuffer.append(envVal.toString());
322             } else {
323                 Debug.logWarning("Could not find value in environment for the name [" + envName + "], inserting nothing.", module);
324             }
325         }
326
327         public void handleBsh(String JavaDoc original, int start, int end) {
328             //run the scriplet and append the result
329
String JavaDoc scriptlet = original.substring(start, end);
330             try {
331                 Object JavaDoc scriptResult = BshUtil.eval(scriptlet, context);
332                 if (scriptResult != null) {
333                     targetBuffer.append(scriptResult.toString());
334                 } else {
335                     Debug.logWarning("BSH scriplet evaluated to null [" + scriptlet + "], got no return so inserting nothing.", module);
336                 }
337             } catch (EvalError e) {
338                 Debug.logWarning(e, "Error evaluating BSH scriplet [" + scriptlet + "], inserting nothing; error was: " + e.toString(), module);
339             }
340         }
341     }
342 }
343
Popular Tags