You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by cz...@apache.org on 2004/04/15 15:44:37 UTC
cvs commit: cocoon-2.2/src/java/org/apache/cocoon/components/cprocessor/variables PreparedVariableResolver.java VariableResolverFactory.java
cziegeler 2004/04/15 06:44:37
Modified: src/java/org/apache/cocoon/components/cprocessor/variables
PreparedVariableResolver.java
VariableResolverFactory.java
Log:
Using new resolver from 2.1.x
Revision Changes Path
1.4 +335 -221 cocoon-2.2/src/java/org/apache/cocoon/components/cprocessor/variables/PreparedVariableResolver.java
Index: PreparedVariableResolver.java
===================================================================
RCS file: /home/cvs/cocoon-2.2/src/java/org/apache/cocoon/components/cprocessor/variables/PreparedVariableResolver.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- PreparedVariableResolver.java 15 Apr 2004 13:13:17 -0000 1.3
+++ PreparedVariableResolver.java 15 Apr 2004 13:44:36 -0000 1.4
@@ -26,116 +26,152 @@
import org.apache.cocoon.sitemap.PatternException;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Stack;
/**
* Prepared implementation of {@link VariableResolver} for fast evaluation.
*
- * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
- * @author <a href="mailto:tcurdt@apache.org">Torsten Curdt</a>
+ * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a>
* @version CVS $Id$
*/
final public class PreparedVariableResolver extends VariableResolver implements Disposable {
private ServiceManager manager;
private ServiceSelector selector;
+ private List tokens;
+ private boolean needsMapStack;
- final private List items = new ArrayList();
+ private static final int OPEN = -2;
+ private static final int CLOSE = -3;
+ private static final int COLON = -4;
+ private static final int TEXT = -5;
+ private static final int EVAL = -6;
+ private static final int EXPR = -7;
+ private static final int SITEMAP_VAR = -8;
+ private static final int PREFIXED_SITEMAP_VAR = -9;
+ private static final int THREADSAFE_MODULE = -10;
+ private static final int STATEFUL_MODULE = -11;
+ private static final int ROOT_SITEMAP_VARIABLE = 0;
+ private static final int ANCHOR_VAR = -1;
+
+ private static Token COLON_TOKEN = new Token(COLON);
+ private static Token OPEN_TOKEN = new Token(OPEN);
+ private static Token CLOSE_TOKEN = new Token(CLOSE);
- // Special constants used for levels
- // ROOT and ANCHOR are placed first as they need a context to be resolved (see resolve())
- static final int ROOT = 0;
- static final int ANCHOR = -1;
- static final int LITERAL = -2;
- static final int THREADSAFE_MODULE = -3;
- static final int STATEFUL_MODULE = -4;
-
- private static final Integer ROOT_OBJ = new Integer(ROOT);
- private static final Integer LITERAL_OBJ = new Integer(LITERAL);
- private static final Integer THREADSAFE_MODULE_OBJ = new Integer(THREADSAFE_MODULE);
- private static final Integer STATEFUL_MODULE_OBJ = new Integer(STATEFUL_MODULE);
- private static final Integer ANCHOR_OBJ = new Integer(ANCHOR);
public PreparedVariableResolver(String expr, ServiceManager manager) throws PatternException {
super(expr);
this.manager = manager;
-
- int length = expr.length();
- int prev = 0; // position after last closing brace
-
- compile : while(prev < length) {
- // find next unescaped '{'
- int pos = prev;
- while(pos < length &&
- (pos = expr.indexOf('{', pos)) != -1 &&
- (pos != 0 && expr.charAt(pos - 1) == '\\')) {
- pos++;
- }
-
- if (pos >= length || pos == -1) {
- // no more braces : add ending literal
- if (prev < length) {
- addLiteral(expr.substring(prev));
+ int openCount = 0;
+ int closeCount = 0;
+
+ needsMapStack = false;
+
+ tokens = new ArrayList();
+ int pos=0;
+ int i;
+ boolean escape = false;
+ for (i=0;i< expr.length();i++) {
+ char c = expr.charAt(i);
+ if (escape) {
+ escape = false;
+ } else if (c=='\\' && i< expr.length()) {
+ char nextChar = expr.charAt(i+1);
+ if (nextChar == '{' || nextChar == '}') {
+ expr = expr.substring(0, i) + expr.substring(i+1);
+ escape = true;
+ i--;
}
- break compile;
- }
-
- // Pass closing brace
- pos++;
-
- // Add litteral strings between closing and next opening brace
- if (prev < pos-1) {
- addLiteral(expr.substring(prev, pos - 1));
- }
-
- int end = expr.indexOf('}', pos);
- if (end == -1) {
- throw new PatternException("Unmatched '{' in " + expr);
- }
-
- int colon = expr.indexOf(':', pos);
- if (colon != -1 && colon < end) {
- if (expr.startsWith("sitemap:", pos)) {
- // Explicit prefix for sitemap variable
- String variable = expr.substring(pos + "sitemap:".length(), end);
- addSitemapVariable(variable);
- } else {
+ } else if (c=='{') {
+ if (i> pos) {
+ tokens.add(new Token(expr.substring(pos, i)));
+ }
+ openCount++;
+ tokens.add(OPEN_TOKEN);
+ int colonPos = indexOf(expr, ":", i);
+ int closePos = indexOf(expr, "}", i);
+ int openPos = indexOf(expr, "{", i);
+ if (openPos < colonPos && openPos < closePos) {
+ throw new PatternException("Invalid '{' at position "+ i + " in expression " + expr);
+ } else if (colonPos < closePos) {
+ // we've found a module
+ Token token;
+ String module = expr.substring(i+1, colonPos);
- String module = expr.substring(pos, colon);
- String variable = expr.substring(colon + 1, end);
-
- if (module.startsWith("#")) {
+ if (module.equals("sitemap")) {
+ // Explicit prefix for sitemap variable
+ needsMapStack = true;
+ token = new Token(PREFIXED_SITEMAP_VAR);
+ } else if (module.startsWith("#")) {
// anchor syntax refering to a name result level
- addAnchorVariable(module.substring(1), variable);
- }
- else {
+ needsMapStack = true;
+ token = new Token(ANCHOR_VAR, module.substring(1));
+ } else {
// Module used
- addModuleVariable(module, variable);
+ token = getNewModuleToken(module);
}
+ tokens.add(token);
+ i = colonPos-1;
+ } else {
+ // Unprefixed name : sitemap variable
+ needsMapStack = true;
+ tokens.add(getNewSitemapToken(expr.substring(i+1, closePos)));
+ i = closePos-1;
}
- } else {
- // Unprefixed name : sitemap variable
- addSitemapVariable(expr.substring(pos, end));
+ pos=i+1;
+ } else if (c=='}') {
+ if (i>0 && expr.charAt(i-1) == '\\') {
+ continue;
+ }
+ if (i> pos) {
+ tokens.add(new Token(expr.substring(pos, i)));
+ }
+ closeCount++;
+ tokens.add(CLOSE_TOKEN);
+ pos=i+1;
+ } else if (c==':') {
+ if (tokens.size()>0) {
+ int lastTokenType = ((Token)tokens.get(tokens.size()-1)).getType();
+ if (lastTokenType != PREFIXED_SITEMAP_VAR &&
+ lastTokenType != ANCHOR_VAR &&
+ lastTokenType != THREADSAFE_MODULE &&
+ lastTokenType != STATEFUL_MODULE) {
+ continue;
+ }
+ }
+ if (i != pos || tokens.size()==0) {
+ // this colon isn't part of a module reference
+ continue;
+ }
+ if (i> pos) {
+ tokens.add(new Token(expr.substring(pos, i)));
+ }
+ tokens.add(COLON_TOKEN);
+ pos=i+1;
}
-
- prev = end + 1;
+ }
+ if (i> pos) {
+ tokens.add(new Token(expr.substring(pos, i)));
+ }
+ if (openCount != closeCount) {
+ throw new PatternException("Mismatching braces in expression: " + expr);
}
}
- private void addLiteral(String litteral) {
- this.items.add(LITERAL_OBJ);
- this.items.add(litteral);
+ private int indexOf(String expr, String chr, int pos) {
+ int location;
+ return (location = expr.indexOf(chr, pos+1))!=-1 ? location : expr.length();
}
- private void addSitemapVariable(String variable) {
+ private Token getNewSitemapToken(String variable) {
if (variable.startsWith("/")) {
- this.items.add(ROOT_OBJ);
- this.items.add(variable.substring(1));
- }
- else {
+ return new Token(ROOT_SITEMAP_VARIABLE, variable.substring(1));
+ } else {
// Find level
int level = 1; // Start at 1 since it will be substracted from list.size()
int pos = 0;
@@ -143,18 +179,12 @@
level++;
pos += "../".length();
}
- this.items.add(new Integer(level));
- this.items.add(variable.substring(pos));
+ return new Token(level, variable.substring(pos));
}
}
- private void addAnchorVariable(String anchor, String variable) {
- this.items.add(ANCHOR_OBJ);
- this.items.add(anchor);
- this.items.add(variable);
- }
- private void addModuleVariable(String moduleName, String variable) throws PatternException {
+ private Token getNewModuleToken(String moduleName) throws PatternException {
if (this.selector == null) {
try {
// First access to a module : lookup selector
@@ -172,176 +202,260 @@
throw new PatternException("Cannot get InputModule named '" + moduleName +
"' in expression '" + this.originalExpr + "'", ce);
}
+ Token token;
// Is this module threadsafe ?
if (module instanceof ThreadSafe) {
- this.items.add(THREADSAFE_MODULE_OBJ);
- this.items.add(module);
- this.items.add(variable);
+ token = new Token(THREADSAFE_MODULE, module);
} else {
- // Statefull module : release it
+ // Stateful module : release it and get a new one each time
this.selector.release(module);
- this.items.add(STATEFUL_MODULE_OBJ);
- this.items.add(moduleName);
- this.items.add(variable);
+ token = new Token(STATEFUL_MODULE, moduleName);
}
+ return token;
}
public final String resolve(InvokeContext context, Map objectModel) throws PatternException {
List mapStack = null; // get the stack only when necessary - lazy inside the loop
int stackSize = 0;
-
- StringBuffer result = new StringBuffer();
- for (int i = 0; i < this.items.size(); i++) {
- int type = ((Integer)this.items.get(i)).intValue();
-
- if (type >= ANCHOR && mapStack == null) {
- if (context == null) {
- throw new PatternException("Need an invoke context to resolve " + this);
- }
- mapStack = context.getMapStack();
- stackSize = mapStack.size();
- }
-
- if (type > 0) {
- // relative sitemap variable
- if (type > stackSize) {
- throw new PatternException("Error while evaluating '" + this.originalExpr +
- "' : not so many levels");
- }
+ if (needsMapStack) {
+ if (context == null) {
+ throw new PatternException("Need an invoke context to resolve " + this);
+ }
+ mapStack = context.getMapStack();
+ stackSize = mapStack.size();
+ }
- Object key = this.items.get(++i);
- Object value = ((Map)mapStack.get(stackSize - type)).get(key);
- if (value != null) {
- result.append(value);
- }
-
- } else {
- // other variable types
- switch(type) {
- case LITERAL :
- result.append(items.get(++i));
- break;
+ Stack stack = new Stack();
- case ROOT :
- {
- Object key = this.items.get(++i);
- Object value = ((Map)mapStack.get(0)).get(key);
- if (value != null) {
- result.append(value);
+ for (Iterator i = tokens.iterator(); i.hasNext();) {
+ Token token = (Token) i.next();
+ Token last;
+ switch (token.getType()){
+ case TEXT:
+ if (stack.empty()) {
+ stack.push(new Token(EXPR, token.getStringValue()));
+ } else {
+ last = (Token)stack.peek();
+ if (last.hasType(EXPR)) {
+ last.merge(token);
+ } else {
+ stack.push(new Token(EXPR, token.getStringValue()));
}
}
break;
-
- case ANCHOR:
- {
- String name = (String) this.items.get(++i);
- Object variable = this.items.get(++i);
- Map levelResult = context.getMapByAnchor(name);
-
- if (levelResult == null) {
- throw new PatternException("Error while evaluating '" + this.originalExpr +
- "' : no anchor '" + String.valueOf(name) + "' found in context");
- }
-
- Object value = levelResult.get(variable);
- if (value != null) {
- result.append(value);
- }
+ case CLOSE:
+ Token expr = (Token)stack.pop();
+ Token lastButOne = (Token)stack.pop();
+ Token result;
+ if (lastButOne.hasType(COLON)) {
+ Token module = (Token)stack.pop();
+ stack.pop(); // Pop the OPEN
+ result = processModule(module, expr, objectModel, context, mapStack, stackSize);
+ } else {
+ result = processVariable(expr, mapStack, stackSize);
}
- break;
-
- case THREADSAFE_MODULE :
- {
- InputModule module = (InputModule)items.get(++i);
- String variable = (String)items.get(++i);
-
- try {
- Object value = module.getAttribute(variable, null, objectModel);
-
- if (value != null) {
- result.append(value);
- }
-
- } catch(ConfigurationException confEx) {
- throw new PatternException("Cannot get variable '" + variable +
- "' in expression '" + this.originalExpr + "'", confEx);
+ if (stack.empty()) {
+ stack.push(result);
+ } else {
+ last = (Token)stack.peek();
+ if (last.hasType(EXPR)) {
+ last.merge(result);
+ } else {
+ stack.push(result);
}
}
break;
-
- case STATEFUL_MODULE :
- {
- InputModule module = null;
- String moduleName = (String)items.get(++i);
- String variableName = (String)items.get(++i);
- try {
- module = (InputModule)this.selector.select(moduleName);
-
- Object value = module.getAttribute(variableName, null, objectModel);
-
- if (value != null) {
- result.append(value);
- }
-
- } catch(ServiceException compEx) {
- throw new PatternException("Cannot get module '" + moduleName +
- "' in expression '" + this.originalExpr + "'", compEx);
-
- } catch(ConfigurationException confEx) {
- throw new PatternException("Cannot get variable '" + variableName +
- "' in expression '" + this.originalExpr + "'", confEx);
-
- } finally {
- this.selector.release(module);
- }
- }
+ case OPEN:
+ case COLON:
+ case EVAL:
+ case SITEMAP_VAR:
+ case ANCHOR_VAR:
+ case THREADSAFE_MODULE:
+ case STATEFUL_MODULE:
+ case ROOT_SITEMAP_VARIABLE:
+ default: {
+ stack.push(token);
break;
}
}
}
+ if (stack.size() !=1) {
+ throw new PatternException("Evaluation error in expression: " + originalExpr);
+ }
+ return ((Token)stack.pop()).getStringValue();
+ }
+
+ private Token processModule(Token module, Token expr, Map objectModel, InvokeContext context, List mapStack, int stackSize) throws PatternException {
+ int type = module.getType();
- return result.toString();
-
+ if (type == ANCHOR_VAR) {
+ Map levelResult = context.getMapByAnchor(module.getStringValue());
+
+ if (levelResult == null) {
+ throw new PatternException("Error while evaluating '" + this.originalExpr +
+ "' : no anchor '" + String.valueOf(module.getStringValue()) + "' found in context");
+ }
+
+ Object result = levelResult.get(expr.getStringValue());
+ return new Token(EXPR, result==null ? "" : result.toString());
+ } else if (type == THREADSAFE_MODULE) {
+ try {
+ InputModule im = module.getModule();
+ Object result = im.getAttribute(expr.getStringValue(), null, objectModel);
+ return new Token(EXPR, result==null ? "" : result.toString());
+
+ } catch(ConfigurationException confEx) {
+ throw new PatternException("Cannot get variable '" + expr.getStringValue() +
+ "' in expression '" + this.originalExpr + "'", confEx);
+ }
+
+ } else if (type == STATEFUL_MODULE) {
+ InputModule im = null;
+ String moduleName = module.getStringValue();
+ try {
+ im = (InputModule)this.selector.select(moduleName);
+
+ Object result = im.getAttribute(expr.getStringValue(), null, objectModel);
+ return new Token(EXPR, result==null ? "" : result.toString());
+
+ } catch(ServiceException compEx) {
+ throw new PatternException("Cannot get module '" + moduleName +
+ "' in expression '" + this.originalExpr + "'", compEx);
+
+ } catch(ConfigurationException confEx) {
+ throw new PatternException("Cannot get variable '" + expr.getStringValue() +
+ "' in expression '" + this.originalExpr + "'", confEx);
+
+ } finally {
+ this.selector.release(im);
+ }
+ } else if (type == PREFIXED_SITEMAP_VAR) {
+ // Prefixed sitemap variable must be parsed at runtime
+ String variable = expr.getStringValue();
+ Token token;
+ if (variable.startsWith("/")) {
+ token = new Token(ROOT_SITEMAP_VARIABLE, variable.substring(1));
+ } else {
+ // Find level
+ int level = 1; // Start at 1 since it will be substracted from list.size()
+ int pos = 0;
+ while (variable.startsWith("../", pos)) {
+ level++;
+ pos += "../".length();
+ }
+ token = new Token(level, variable.substring(pos));
+ }
+ return processVariable(token, mapStack, stackSize);
+ } else {
+ throw new PatternException("Unknown token type: " + expr.getType());
+ }
+ }
+
+ private Token processVariable(Token expr, List mapStack, int stackSize) throws PatternException {
+ int type = expr.getType();
+ String value = expr.getStringValue();
+ if (type == ROOT_SITEMAP_VARIABLE) {
+ Object result = ((Map)mapStack.get(0)).get(value);
+ return new Token(EXPR, result==null ? "" : result.toString());
+ } else {
+ // relative sitemap variable
+ if (type > stackSize) {
+ throw new PatternException("Error while evaluating '" + this.originalExpr +
+ "' : not so many levels");
+ }
+
+ Object result = ((Map)mapStack.get(stackSize - type)).get(value);
+ return new Token(EXPR, result==null ? "" : result.toString());
+ }
}
public final void dispose() {
if (this.selector != null) {
- for (int i = 0; i < this.items.size(); i++) {
- int type = ((Integer) this.items.get(i)).intValue();
-
- switch (type) {
- case ROOT:
- i++; // variable
- break;
-
- case LITERAL:
- i++; // literal string
- break;
-
- case ANCHOR:
- i += 2; // anchor name, variable
- break;
-
- case THREADSAFE_MODULE:
- i++; // module
- this.selector.release(this.items.get(i));
- i++; // variable
- break;
-
- case STATEFUL_MODULE:
- i += 2; // module name, variable
- break;
-
- default:
- // relative sitemap variable
- i++; // variable
+ for (Iterator i = tokens.iterator(); i.hasNext();) {
+ Token token = (Token)i.next();
+ if (token.hasType(THREADSAFE_MODULE)) {
+ InputModule im = token.getModule();
+ this.selector.release(im);
}
}
this.manager.release(this.selector);
this.selector = null;
this.manager = null;
+ }
+ }
+
+ private static class Token {
+
+ private Object value;
+ private int type;
+
+ public Token(int type) {
+ this.value = null;
+ this.type = type;
+ }
+
+ public Token(int type, String value) {
+ this.value = value;
+ this.type = type;
+ }
+
+ public Token(int type, InputModule module) {
+ this.value = module;
+ this.type = type;
+ }
+
+ public Token(char c) {
+ this.value = null;
+ if (c=='{') {
+ this.type = OPEN;
+ } else if (c=='}') {
+ this.type = CLOSE;
+ } else if (c==':') {
+ this.type = COLON;
+ }
+ }
+
+ public Token(String value) {
+ this.type = TEXT;
+ this.value = value;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public String getStringValue() {
+ if (value instanceof String) {
+ return (String)this.value;
+ } else {
+ return null;
+ }
+ }
+
+ public boolean hasType(int type){
+ return this.type == type;
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof Token) {
+ return ((Token)o).hasType(this.type);
+ } else {
+ return false;
+ }
+ }
+
+ public void merge(Token newToken) {
+ this.value = this.value + newToken.getStringValue();
+ }
+
+ public InputModule getModule() {
+ if (value instanceof InputModule) {
+ return (InputModule)value;
+ } else {
+ return null;
+ }
}
}
}
1.3 +2 -5 cocoon-2.2/src/java/org/apache/cocoon/components/cprocessor/variables/VariableResolverFactory.java
Index: VariableResolverFactory.java
===================================================================
RCS file: /home/cvs/cocoon-2.2/src/java/org/apache/cocoon/components/cprocessor/variables/VariableResolverFactory.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- VariableResolverFactory.java 8 Mar 2004 13:57:37 -0000 1.2
+++ VariableResolverFactory.java 15 Apr 2004 13:44:36 -0000 1.3
@@ -108,12 +108,9 @@
return resolver;
} else {
- return new NOPVariableResolver(expression);
-
+ return new NOPVariableResolver(expression);
}
}
-
-
}