KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > treeprocessor > MapStackResolver


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.components.treeprocessor;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.apache.avalon.framework.parameters.Parameters;
26 import org.apache.cocoon.sitemap.PatternException;
27
28 /**
29  * Utility class for handling {...} pattern substitutions from a List of Maps.
30  *
31  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
32  * @version CVS $Id: MapStackResolver.java 30932 2004-07-29 17:35:38Z vgritsenko $
33  * @deprecated use {@link org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory}
34  */

35
36 public abstract class MapStackResolver {
37
38     public static final Map JavaDoc EMPTY_MAP = Collections.unmodifiableMap(new java.util.HashMap JavaDoc(0));
39
40     /**
41      * Resolve all {...} patterns using the values given in the list of maps.
42      */

43     public abstract String JavaDoc resolve(List JavaDoc mapStack) throws PatternException;
44
45     /**
46      * Does an expression need resolving (i.e. contain {...} patterns) ?
47      */

48     public static boolean needsResolve(String JavaDoc expression) {
49         if (expression == null || expression.length() == 0) {
50             return false;
51         }
52
53         // Is the first char a '{' ?
54
if (expression.charAt(0) == '{') {
55             return true;
56         }
57
58         if (expression.length() < 2) {
59             return false;
60         }
61
62         // Is there any unescaped '{' ?
63
int pos = 1;
64         while ( (pos = expression.indexOf('{', pos)) != -1) {
65             // Found a '{' : is it escaped ?
66
if (expression.charAt(pos - 1) != '\\') {
67                 // No : need to resolve
68
return true;
69             }
70             pos++;
71         }
72         // Nothing found...
73
return false;
74     }
75
76     /**
77      * Unescape an expression that doesn't need to be resolved, but may contain
78      * escaped '{' characters.
79      *
80      * @param expression the expression to unescape.
81      * @return the unescaped result, or <code>expression</code> if unescaping isn't necessary.
82      */

83     public static String JavaDoc unescape(String JavaDoc expression) {
84         // Does it need escaping ?
85
if (expression == null || expression.indexOf("\\{") == -1) {
86             return expression;
87         }
88
89         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
90         for (int i = 0; i < expression.length(); i++) {
91             char ch = expression.charAt(i);
92             if (ch != '\\' || i >= (expression.length() - 1) || expression.charAt(i+1) != '{') {
93                 buf.append(ch);
94             }
95         }
96
97         return buf.toString();
98     }
99
100     /**
101      * Get a resolver for a given expression. Chooses the most efficient implementation
102      * depending on <code>expression</code>.
103      */

104     public static MapStackResolver getResolver(String JavaDoc expression) throws PatternException {
105         if (needsResolve(expression)) {
106 // return new RealResolver(expression);
107
return new CompiledResolver(expression);
108         } else {
109             return new NullResolver(expression);
110         }
111     }
112
113     /**
114      * Build a <code>Parameters</code> object from a Map of named <code>ListOfMapResolver</code>s and
115      * a list of Maps used for resolution.
116      *
117      * @return a fully resolved <code>Parameters</code>.
118      */

119     public static Parameters buildParameters(Map JavaDoc expressions, List JavaDoc mapStack) throws PatternException {
120         if (expressions == null || expressions.size() == 0) {
121             return Parameters.EMPTY_PARAMETERS;
122         }
123
124         Parameters result = new Parameters();
125
126         Iterator JavaDoc iter = expressions.entrySet().iterator();
127         while (iter.hasNext()) {
128             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
129             result.setParameter(
130                 ((MapStackResolver)entry.getKey()).resolve(mapStack),
131                 ((MapStackResolver)entry.getValue()).resolve(mapStack)
132             );
133         }
134
135         return result;
136     }
137
138     /**
139      * Resolve all values of a <code>Map</code> from a Map of named <code>ListOfMapResolver</code>s and
140      * a list of Maps used for resolution.
141      *
142      * @return a fully resolved <code>Map</code>.
143      */

144     public static Map JavaDoc resolveMap(Map JavaDoc expressions, List JavaDoc mapStack) throws PatternException {
145         int size;
146         if (expressions == null || (size = expressions.size()) == 0) {
147             return EMPTY_MAP;
148         }
149
150         Map JavaDoc result = new HashMap JavaDoc(size);
151
152         Iterator JavaDoc iter = expressions.entrySet().iterator();
153         while (iter.hasNext()) {
154             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
155             result.put(
156                 ((MapStackResolver)entry.getKey()).resolve(mapStack),
157                 ((MapStackResolver)entry.getValue()).resolve(mapStack)
158             );
159         }
160
161         return result;
162     }
163
164     //-------------------------------------------------------------------------
165
/**
166      * No-op resolver for expressions that don't need to be resolved.
167      */

168     private static class NullResolver extends MapStackResolver {
169         private String JavaDoc originalExpr = null;
170         private String JavaDoc expression = null;
171
172         public NullResolver(String JavaDoc expression) {
173             if (expression != null) {
174                 this.originalExpr = expression;
175                 this.expression = unescape(expression);
176             }
177         }
178
179         public String JavaDoc toString() {
180             return this.originalExpr;
181         }
182
183         public final String JavaDoc resolve(List JavaDoc mapStack) {
184             return this.expression;
185         }
186     }
187
188     //-------------------------------------------------------------------------
189

190     /**
191      * Compiled form for faster substitution
192      */

193     private static class CompiledResolver extends MapStackResolver {
194         private String JavaDoc originalExpr;
195
196         private String JavaDoc[] strings;
197         private int[] levels;
198
199         public CompiledResolver(String JavaDoc expression) throws PatternException {
200             this.originalExpr = expression;
201             compile(expression);
202         }
203
204         public String JavaDoc toString() {
205             return this.originalExpr;
206         }
207
208         private void compile(String JavaDoc expr) throws PatternException {
209             // We're sure here that expr *contains* some substitutions
210

211             List JavaDoc stringList = new ArrayList JavaDoc();
212             List JavaDoc levelList = new ArrayList JavaDoc();
213
214             int length = expr.length();
215             int prev = 0; // position after last closing brace
216

217             comp : while(prev < length) {
218                 // find next unescaped '{'
219
int pos = prev;
220                 while(pos < length &&
221                       (pos = expr.indexOf('{', pos)) != -1 &&
222                       (pos != 0 && expr.charAt(pos - 1) == '\\')) {
223                     pos++;
224                 }
225
226                 if (pos >= length || pos == -1) {
227                     // no more braces
228
if (prev < length) {
229                         stringList.add(unescape(expr.substring(prev)));
230                         levelList.add(new Integer JavaDoc(-1));
231                     }
232                     break comp;
233                 }
234
235                 // Pass closing brace
236
pos++;
237
238                 // Add litteral strings between closing and next opening brace
239
if (prev < pos-1) {
240                     stringList.add(unescape(expr.substring(prev, pos - 1)));
241                     levelList.add(new Integer JavaDoc(-1));
242                 }
243
244                 // Determine subst level
245
int level = 1; // Start at 1 since it will be substracted from list.size()
246
while(expr.startsWith("../", pos)) {
247                     level++;
248                     pos += "../".length();
249                 }
250
251                 int end = expr.indexOf('}', pos);
252                 if (end == -1) {
253                     throw new PatternException("Unmatched '{' in " + expr);
254                 }
255
256                 stringList.add(expr.substring(pos, end));
257                 levelList.add(new Integer JavaDoc(level));
258
259                 prev = end + 1;
260             }
261
262             this.strings = new String JavaDoc[stringList.size()];
263             this.levels = new int[stringList.size()];
264             for (int i = 0; i < strings.length; i++) {
265                 this.strings[i] = (String JavaDoc)stringList.get(i);
266                 this.levels[i] = ((Integer JavaDoc)levelList.get(i)).intValue();
267             }
268         }
269
270         public final String JavaDoc resolve(List JavaDoc mapStack) throws PatternException {
271             StringBuffer JavaDoc result = new StringBuffer JavaDoc();
272             int stackSize = mapStack.size();
273
274             for (int i = 0; i < this.strings.length; i++) {
275                 int level = this.levels[i];
276                 if (level == -1) {
277                     result.append(this.strings[i]);
278
279                 } else {
280                     if (level > stackSize) {
281                         throw new PatternException("Error while evaluating '" + this.originalExpr +
282                             "' : not so many levels");
283                     }
284
285                     Object JavaDoc value = ((Map JavaDoc)mapStack.get(stackSize - level)).get(this.strings[i]);
286                     if (value != null) {
287                         result.append(value);
288                     }
289                 }
290             }
291
292             return result.toString();
293         }
294
295 // public void dump() {
296
// System.out.println(this.originalExpr + " compiled in :");
297
// for (int i = 0; i < this.strings.length; i++) {
298
// System.out.print("[" + this.levels[i] + ":'" + this.strings[i] + "'] ");
299
// }
300
// System.out.println();
301
// System.out.println();
302
// }
303
}
304
305 // public static void main(String [] args) throws Exception {
306
//
307
// new CompiledResolver("&{../../blah}").dump();
308
// new CompiledResolver("{t1}tt{t2}x").dump();
309
// new CompiledResolver("\\{t1}tt{t2}xx").dump();
310
// new CompiledResolver("{t1}tt\\{t2}xx").dump();
311
// new CompiledResolver("{t1}tt{t2}xx").dump();
312
// new CompiledResolver("xx{../t1}{../../../t2}zz").dump();
313
// new CompiledResolver("xx{../t1}\\{../../../t2}zz").dump();
314
//
315
// }
316
}
317
Popular Tags