KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > treeprocessor > variables > PreparedVariableResolver


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.variables;
17
18 import org.apache.avalon.framework.activity.Disposable;
19 import org.apache.avalon.framework.component.ComponentManager;
20 import org.apache.avalon.framework.configuration.ConfigurationException;
21 import org.apache.avalon.framework.service.ServiceException;
22 import org.apache.avalon.framework.service.ServiceManager;
23 import org.apache.avalon.framework.service.ServiceSelector;
24 import org.apache.avalon.framework.service.WrapperServiceManager;
25 import org.apache.avalon.framework.thread.ThreadSafe;
26
27 import org.apache.cocoon.components.modules.input.InputModule;
28 import org.apache.cocoon.components.treeprocessor.InvokeContext;
29 import org.apache.cocoon.sitemap.PatternException;
30 import org.apache.commons.lang.builder.HashCodeBuilder;
31
32 import java.util.ArrayList JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Stack JavaDoc;
37
38 /**
39  * Prepared implementation of {@link VariableResolver} for fast evaluation.
40  *
41  * @author <a HREF="mailto:uv@upaya.co.uk">Upayavira</a>
42  * @version CVS $Id: PreparedVariableResolver.java 124754 2005-01-10 03:07:20Z antonio $
43  */

44 final public class PreparedVariableResolver extends VariableResolver implements Disposable {
45
46     private ServiceManager manager;
47     private ServiceSelector selector;
48     private List JavaDoc tokens;
49     private boolean needsMapStack;
50
51     private static final int OPEN = -2;
52     private static final int CLOSE = -3;
53     private static final int COLON = -4;
54     private static final int TEXT = -5;
55     private static final int EXPR = -7;
56     private static final int SITEMAP_VAR = -9;
57     private static final int THREADSAFE_MODULE = -10;
58     private static final int STATEFUL_MODULE = -11;
59     private static final int ROOT_SITEMAP_VARIABLE = 0;
60     private static final int ANCHOR_VAR = -1;
61
62     private static Token COLON_TOKEN = new Token(COLON);
63     private static Token OPEN_TOKEN = new Token(OPEN);
64     private static Token CLOSE_TOKEN = new Token(CLOSE);
65     private static Token EMPTY_TOKEN = new Token(EXPR);
66
67     /**
68      * @deprecated use the version with <code>ServiceManager</service>
69      */

70     public PreparedVariableResolver(String JavaDoc expr, ComponentManager manager) throws PatternException {
71         this(expr, new WrapperServiceManager(manager));
72     }
73
74     public PreparedVariableResolver(String JavaDoc expr, ServiceManager manager) throws PatternException {
75         super(expr);
76         this.manager = manager;
77         this.tokens = new ArrayList JavaDoc();
78
79         VariableExpressionTokenizer.tokenize(expr, new VariableExpressionTokenizer.TokenReciever() {
80             public void addToken(int type, String JavaDoc value) throws PatternException {
81                 switch (type) {
82                     case VariableExpressionTokenizer.TokenReciever.COLON:
83                         tokens.add(COLON_TOKEN);
84                         break;
85                     case VariableExpressionTokenizer.TokenReciever.OPEN:
86                         tokens.add(OPEN_TOKEN);
87                         break;
88                     case VariableExpressionTokenizer.TokenReciever.CLOSE:
89                         tokens.add(CLOSE_TOKEN);
90                         break;
91                     case VariableExpressionTokenizer.TokenReciever.TEXT:
92                         tokens.add(new Token(value));
93                         break;
94                     case VariableExpressionTokenizer.TokenReciever.MODULE:
95                         Token token;
96                         if (value.equals("sitemap")) {
97                             // Explicit prefix for sitemap variable
98
needsMapStack = true;
99                             token = new Token(SITEMAP_VAR);
100                         } else if (value.startsWith("#")) {
101                             // anchor syntax refering to a name result level
102
needsMapStack = true;
103                             token = new Token(ANCHOR_VAR, value.substring(1));
104                         } else {
105                             // Module used
106
token = getNewModuleToken(value);
107                         }
108                         tokens.add(token);
109                         break;
110                     case VariableExpressionTokenizer.TokenReciever.VARIABLE:
111                         needsMapStack = true;
112                         tokens.add(getNewVariableToken(value));
113                         break;
114                     default:
115                         throw new IllegalArgumentException JavaDoc("Unknown token type: " + type);
116                 }
117             }
118         });
119     }
120
121     private Token getNewVariableToken(String JavaDoc variable) {
122         if (variable.startsWith("/")) {
123             return new Token(ROOT_SITEMAP_VARIABLE, variable.substring(1));
124         } else {
125             // Find level
126
int level = 1; // Start at 1 since it will be substracted from list.size()
127
int pos = 0;
128             while (variable.startsWith("../", pos)) {
129                 level++;
130                 pos += "../".length();
131             }
132             return new Token(level, variable.substring(pos));
133         }
134     }
135
136
137     private Token getNewModuleToken(String JavaDoc moduleName) throws PatternException {
138         if (this.selector == null) {
139             try {
140                 // First access to a module : lookup selector
141
this.selector = (ServiceSelector) this.manager.lookup(InputModule.ROLE + "Selector");
142             } catch(ServiceException ce) {
143                 throw new PatternException("Cannot access input modules selector", ce);
144             }
145         }
146
147         // Get the module
148
InputModule module;
149         try {
150             module = (InputModule) this.selector.select(moduleName);
151         } catch (ServiceException e) {
152             throw new PatternException("Cannot get module named '" + moduleName +
153                                        "' in expression '" + this.originalExpr + "'", e);
154         }
155
156         Token token;
157         // Is this module threadsafe ?
158
if (module instanceof ThreadSafe) {
159             token = new Token(THREADSAFE_MODULE, module);
160         } else {
161             // Stateful module : release it and get a new one each time
162
this.selector.release(module);
163             token = new Token(STATEFUL_MODULE, moduleName);
164         }
165         return token;
166     }
167
168     public final String JavaDoc resolve(InvokeContext context, Map JavaDoc objectModel) throws PatternException {
169         List JavaDoc mapStack = null; // get the stack only when necessary - lazy inside the loop
170
int stackSize = 0;
171
172         if (needsMapStack) {
173             if (context == null) {
174                 throw new PatternException("Need an invoke context to resolve " + this);
175             }
176             mapStack = context.getMapStack();
177             stackSize = mapStack.size();
178         }
179
180         Stack JavaDoc stack = new Stack JavaDoc();
181
182         for (Iterator JavaDoc i = tokens.iterator(); i.hasNext();) {
183             Token token = (Token) i.next();
184             Token last;
185             switch (token.getType()){
186                 case TEXT:
187                     if (stack.empty()) {
188                         stack.push(new Token(EXPR, token.getStringValue()));
189                     } else {
190                         last = (Token)stack.peek();
191                         if (last.hasType(EXPR)) {
192                             last.merge(token);
193                         } else {
194                             stack.push(new Token(EXPR, token.getStringValue()));
195                         }
196                     }
197                     break;
198                 case CLOSE:
199                     Token expr = (Token)stack.pop();
200                     Token lastButOne = (Token)stack.pop();
201                     Token result;
202                     if (expr.hasType(COLON)) { // i.e. nothing was specified after the colon
203
stack.pop(); // Pop the OPEN
204
result = processModule(lastButOne, EMPTY_TOKEN, objectModel, context, mapStack, stackSize);
205                     } else if (lastButOne.hasType(COLON)) {
206                         Token module = (Token)stack.pop();
207                         stack.pop(); // Pop the OPEN
208
result = processModule(module, expr, objectModel, context, mapStack, stackSize);
209                     } else {
210                         result = processVariable(expr, mapStack, stackSize);
211                     }
212                     if (stack.empty()) {
213                         stack.push(result);
214                     } else {
215                         last = (Token)stack.peek();
216                         if (last.hasType(EXPR)) {
217                             last.merge(result);
218                         } else {
219                             stack.push(result);
220                         }
221                     }
222                     break;
223                 case OPEN:
224                 case COLON:
225                 case ANCHOR_VAR:
226                 case THREADSAFE_MODULE:
227                 case STATEFUL_MODULE:
228                 case ROOT_SITEMAP_VARIABLE:
229                 default: {
230                     stack.push(token);
231                     break;
232                 }
233             }
234         }
235         if (stack.size() !=1) {
236             throw new PatternException("Evaluation error in expression: " + originalExpr);
237         }
238         return ((Token)stack.pop()).getStringValue();
239     }
240
241     private Token processModule(Token module, Token expr, Map JavaDoc objectModel, InvokeContext context, List JavaDoc mapStack, int stackSize) throws PatternException {
242         int type = module.getType();
243
244         if (type == ANCHOR_VAR) {
245             Map JavaDoc levelResult = context.getMapByAnchor(module.getStringValue());
246
247             if (levelResult == null) {
248               throw new PatternException("Error while evaluating '" + this.originalExpr +
249                 "' : no anchor '" + String.valueOf(module.getStringValue()) + "' found in context");
250             }
251
252             Object JavaDoc result = levelResult.get(expr.getStringValue());
253             return new Token(EXPR, result==null ? "" : result.toString());
254         } else if (type == THREADSAFE_MODULE) {
255             try {
256                 InputModule im = module.getModule();
257                 Object JavaDoc result = im.getAttribute(expr.getStringValue(), null, objectModel);
258                 return new Token(EXPR, result==null ? "" : result.toString());
259
260             } catch(ConfigurationException confEx) {
261                 throw new PatternException("Cannot get variable '" + expr.getStringValue() +
262                     "' in expression '" + this.originalExpr + "'", confEx);
263             }
264
265         } else if (type == STATEFUL_MODULE) {
266             InputModule im = null;
267             String JavaDoc moduleName = module.getStringValue();
268             try {
269                 im = (InputModule) this.selector.select(moduleName);
270
271                 Object JavaDoc result = im.getAttribute(expr.getStringValue(), null, objectModel);
272                 return new Token(EXPR, result==null ? "" : result.toString());
273
274             } catch(ServiceException e) {
275                 throw new PatternException("Cannot get module '" + moduleName +
276                                            "' in expression '" + this.originalExpr + "'", e);
277
278             } catch(ConfigurationException confEx) {
279                 throw new PatternException("Cannot get variable '" + expr.getStringValue() +
280                     "' in expression '" + this.originalExpr + "'", confEx);
281
282             } finally {
283                 this.selector.release(im);
284             }
285         } else if (type == SITEMAP_VAR) {
286             // Prefixed sitemap variable must be parsed at runtime
287
String JavaDoc variable = expr.getStringValue();
288             Token token;
289             if (variable.startsWith("/")) {
290                 token = new Token(ROOT_SITEMAP_VARIABLE, variable.substring(1));
291             } else {
292                 // Find level
293
int level = 1; // Start at 1 since it will be substracted from list.size()
294
int pos = 0;
295                 while (variable.startsWith("../", pos)) {
296                     level++;
297                     pos += "../".length();
298                 }
299                 token = new Token(level, variable.substring(pos));
300             }
301             return processVariable(token, mapStack, stackSize);
302         } else {
303             throw new PatternException("Unknown token type: " + expr.getType());
304         }
305     }
306
307     private Token processVariable(Token expr, List JavaDoc mapStack, int stackSize) throws PatternException {
308         int type = expr.getType();
309         String JavaDoc value = expr.getStringValue();
310         if (type == ROOT_SITEMAP_VARIABLE) {
311             Object JavaDoc result = ((Map JavaDoc)mapStack.get(0)).get(value);
312             return new Token(EXPR, result==null ? "" : result.toString());
313         } else {
314             // relative sitemap variable
315
if (type > stackSize) {
316                 throw new PatternException("Error while evaluating '" + this.originalExpr +
317                     "' : not so many levels");
318             }
319
320             Object JavaDoc result = ((Map JavaDoc)mapStack.get(stackSize - type)).get(value);
321             return new Token(EXPR, result==null ? "" : result.toString());
322         }
323     }
324
325     public final void dispose() {
326         if (this.selector != null) {
327             for (Iterator JavaDoc i = tokens.iterator(); i.hasNext();) {
328                 Token token = (Token)i.next();
329                 if (token.hasType(THREADSAFE_MODULE)) {
330                     InputModule im = token.getModule();
331                     this.selector.release(im);
332                 }
333             }
334             this.manager.release(this.selector);
335             this.selector = null;
336             this.manager = null;
337         }
338     }
339
340     private static class Token {
341
342         private Object JavaDoc value;
343         private int type;
344
345         public Token(int type) {
346             if (type==EXPR) {
347                 this.value="";
348             } else {
349                 this.value = null;
350             }
351             this.type = type;
352         }
353
354         public Token(int type, String JavaDoc value) {
355             this.value = value;
356             this.type = type;
357         }
358
359         public Token(int type, InputModule module) {
360             this.value = module;
361             this.type = type;
362         }
363
364         public Token(String JavaDoc value) {
365             this.type = TEXT;
366             this.value = value;
367         }
368
369         public int getType() {
370           return type;
371         }
372
373         public String JavaDoc getStringValue() {
374             if (value instanceof String JavaDoc) {
375                 return (String JavaDoc)this.value;
376             } else {
377                 return null;
378             }
379         }
380
381         public boolean hasType(int type){
382             return this.type == type;
383         }
384
385         public boolean equals(Object JavaDoc o) {
386             if (o instanceof Token) {
387                 return ((Token)o).hasType(this.type);
388             } else {
389                 return false;
390             }
391         }
392         
393         public int hashCode() {
394             return new HashCodeBuilder().
395             append(value).
396             append(this.type).
397             toHashCode();
398         }
399
400         public void merge(Token newToken) {
401             this.value = this.value + newToken.getStringValue();
402         }
403
404         public InputModule getModule() {
405             if (value instanceof InputModule) {
406                 return (InputModule)value;
407             } else {
408                 return null;
409             }
410         }
411     }
412 }
413
Popular Tags