001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.runtime.evaluator;
046:
047: import org.apache.commons.jxpath.*;
048: import org.obe.OBERuntimeException;
049: import org.obe.client.api.repository.FunctionSetMetaData;
050: import org.obe.client.api.repository.RepositoryException;
051: import org.obe.spi.WorkflowContext;
052: import org.obe.spi.evaluator.EvaluatorException;
053: import org.obe.spi.model.AttributeInstance;
054: import org.obe.spi.model.ProcessInstance;
055: import org.obe.spi.service.FunctionFactory;
056: import org.obe.spi.service.ResourceRepository;
057:
058: import java.util.Collections;
059: import java.util.HashMap;
060: import java.util.Iterator;
061: import java.util.Map;
062:
063: /**
064: * Invokes JXPath to evaluate an XPath expression against the workflow data.
065: *
066: * @author Adrian Price
067: */
068: public final class JXPathEvaluator extends AbstractEvaluator {
069: private static final Map _compiledExpressions = new HashMap();
070: private static final ThreadLocal _jxpcCache = new ThreadLocal();
071: private static FunctionLibrary _funcLib;
072:
073: private static final class JXPathVariables extends BasicVariables {
074: private final WorkflowContext _ctx;
075: private final Map _data;
076:
077: private JXPathVariables(WorkflowContext ctx) {
078: _ctx = ctx;
079: try {
080: // Provide access to the workflow instance data.
081: ProcessInstance procInst = _ctx.getProcessInstance();
082: _data = procInst == null ? Collections.EMPTY_MAP
083: : procInst.getAttributeInstances();
084: } catch (RepositoryException e) {
085: throw new OBERuntimeException(e);
086: }
087: }
088:
089: public Object getVariable(String varName) {
090: return varName.equals(EvaluationContext.CONTEXT) ? _ctx
091: : ((AttributeInstance) _data.get(varName))
092: .getValue();
093: }
094:
095: public boolean isDeclaredVariable(String varName) {
096: return varName.equals(EvaluationContext.CONTEXT)
097: || _data.containsKey(varName);
098: }
099: }
100:
101: private static JXPathContext getJXPathContext(WorkflowContext ctx)
102: throws RepositoryException {
103:
104: // Check the cache first.
105: JXPathContext jxpc = (JXPathContext) _jxpcCache.get();
106: if (jxpc != null) {
107: ((EvaluationContext) jxpc.getContextBean()).setContext(ctx);
108: } else {
109: jxpc = JXPathContext.newContext(new EvaluationContext(ctx));
110: _jxpcCache.set(jxpc);
111: }
112:
113: jxpc.setVariables(new JXPathVariables(ctx));
114:
115: // TODO: figure out how to provide namespace support when evaluating
116: // expressions for inbound event data, when there is no workflow.
117: if (ctx.getWorkflow() != null) {
118: Map namespaces = ctx.getWorkflow().getPackage()
119: .getNamespaces();
120: Iterator iter = namespaces.entrySet().iterator();
121: while (iter.hasNext()) {
122: Map.Entry entry = (Map.Entry) iter.next();
123: jxpc.registerNamespace((String) entry.getKey(),
124: (String) entry.getValue());
125: }
126: }
127:
128: // Provide access to system functions.
129: if (_funcLib == null) {
130: _funcLib = new FunctionLibrary();
131: FunctionFactory fr = ctx.getServiceManager()
132: .getFunctionFactory();
133: ResourceRepository resourceRepository = ctx
134: .getServiceManager().getResourceRepository();
135: FunctionSetMetaData[] fsmd = fr.findFunctionMetaData();
136: for (int i = 0; i < fsmd.length; i++) {
137: FunctionSetMetaData metaData = fsmd[i];
138: _funcLib.addFunctions(new ClassFunctions(metaData
139: .createInstance(resourceRepository).getClass(),
140: metaData.getNsPrefix()));
141: }
142: }
143: jxpc.setFunctions(_funcLib);
144: return jxpc;
145: }
146:
147: private static synchronized CompiledExpression getCompiledExpression(
148: String expr) {
149:
150: CompiledExpression cexpr = (CompiledExpression) _compiledExpressions
151: .get(expr);
152: if (cexpr == null) {
153: cexpr = JXPathContext.compile(expr);
154: _compiledExpressions.put(expr, cexpr);
155: }
156: return cexpr;
157: }
158:
159: public JXPathEvaluator() {
160: }
161:
162: public Object evaluateExpression(String expr, WorkflowContext ctx)
163: throws EvaluatorException {
164:
165: try {
166: JXPathContext jxpc = getJXPathContext(ctx);
167:
168: // Evaluate the expression.
169: CompiledExpression cexpr = getCompiledExpression(expr);
170: Iterator iter = cexpr.iteratePointers(jxpc);
171: return iter.hasNext() ? ((Pointer) iter.next()).getNode()
172: : null;
173: } catch (RepositoryException e) {
174: throw new EvaluatorException(e);
175: }
176: }
177: }
|