001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.servicemix.expression;
018:
019: import java.io.IOException;
020:
021: import javax.jbi.messaging.MessageExchange;
022: import javax.jbi.messaging.MessagingException;
023: import javax.jbi.messaging.NormalizedMessage;
024: import javax.xml.parsers.ParserConfigurationException;
025: import javax.xml.transform.TransformerException;
026:
027: import org.w3c.dom.Node;
028:
029: import org.xml.sax.SAXException;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.apache.servicemix.jbi.jaxp.SourceTransformer;
034: import org.apache.servicemix.jbi.util.MessageUtil;
035: import org.jaxen.FunctionContext;
036: import org.jaxen.JaxenException;
037: import org.jaxen.NamespaceContext;
038: import org.jaxen.XPath;
039: import org.jaxen.dom.DOMXPath;
040: import org.springframework.beans.factory.InitializingBean;
041:
042: /**
043: * Evalutes an XPath expression on the given message using <a
044: * href="http://jaxen.org/"/>Jaxen</a>
045: *
046: * @version $Revision: 564900 $
047: */
048: public class JaxenXPathExpression implements Expression,
049: InitializingBean {
050:
051: private static final transient Log LOG = LogFactory
052: .getLog(JaxenXPathExpression.class);
053:
054: private String xpath;
055:
056: private boolean useMessageContent = true;
057:
058: private SourceTransformer transformer = new SourceTransformer();
059:
060: private JaxenVariableContext variableContext = new JaxenVariableContext();
061:
062: private XPath xpathObject;
063:
064: private NamespaceContext namespaceContext;
065:
066: private FunctionContext functionContext;
067:
068: public JaxenXPathExpression() {
069: }
070:
071: /**
072: * A helper constructor to make a fully created expression. This constructor
073: * will call the {@link #afterPropertiesSet()} method to ensure this POJO is
074: * properly constructed.
075: */
076: public JaxenXPathExpression(String xpath) throws Exception {
077: this .xpath = xpath;
078: init();
079: }
080:
081: public void afterPropertiesSet() throws Exception {
082: init();
083: }
084:
085: private void init() throws JaxenException {
086: if (xpathObject == null) {
087: if (xpath == null) {
088: throw new IllegalArgumentException(
089: "You must specify the xpath property");
090: }
091: xpathObject = createXPath(xpath);
092: xpathObject.setVariableContext(variableContext);
093: if (namespaceContext != null) {
094: xpathObject.setNamespaceContext(namespaceContext);
095: }
096: if (functionContext != null) {
097: xpathObject.setFunctionContext(functionContext);
098: }
099: }
100: }
101:
102: public Object evaluate(MessageExchange exchange,
103: NormalizedMessage message) throws MessagingException {
104: try {
105: Object object = getXMLNode(exchange, message);
106: if (object == null) {
107: return null;
108: }
109: synchronized (this ) {
110: variableContext.setExchange(exchange);
111: variableContext.setMessage(message);
112: return evaluateXPath(object);
113: }
114: } catch (TransformerException e) {
115: throw new MessagingException(e);
116: } catch (JaxenException e) {
117: throw new MessagingException(e);
118: } catch (ParserConfigurationException e) {
119: throw new MessagingException(e);
120: } catch (IOException e) {
121: throw new MessagingException(e);
122: } catch (SAXException e) {
123: throw new MessagingException(e);
124: }
125: }
126:
127: public boolean matches(MessageExchange exchange,
128: NormalizedMessage message) throws MessagingException {
129: try {
130: Object object = getXMLNode(exchange, message);
131: if (object == null) {
132: return false;
133: }
134: synchronized (this ) {
135: variableContext.setExchange(exchange);
136: variableContext.setMessage(message);
137: return evaluateXPathAsBoolean(object);
138: }
139: } catch (TransformerException e) {
140: throw new MessagingException(e);
141: } catch (JaxenException e) {
142: throw new MessagingException(e);
143: } catch (ParserConfigurationException e) {
144: throw new MessagingException(e);
145: } catch (IOException e) {
146: throw new MessagingException(e);
147: } catch (SAXException e) {
148: throw new MessagingException(e);
149: }
150: }
151:
152: // Properties
153: // -------------------------------------------------------------------------
154: public XPath getXpathObject() {
155: return xpathObject;
156: }
157:
158: public void setXpathObject(XPath xpathObject) {
159: this .xpathObject = xpathObject;
160: }
161:
162: public String getXpath() {
163: return xpath;
164: }
165:
166: public void setXpath(String xpath) {
167: this .xpath = xpath;
168: }
169:
170: public boolean isUseMessageContent() {
171: return useMessageContent;
172: }
173:
174: /**
175: * Specifies whether or not the XPath expression uses the message content.
176: *
177: * By default, this property is <code>true</code>, but you can set it to
178: * <code>false</code> to avoid that the message content is converted to
179: * {@link StringSource}
180: *
181: * @param useMessageContent
182: * specify <code>false</code> if this expression does not
183: * access the message content
184: */
185: public void setUseMessageContent(boolean useMessageContent) {
186: this .useMessageContent = useMessageContent;
187: }
188:
189: public SourceTransformer getTransformer() {
190: return transformer;
191: }
192:
193: public void setTransformer(SourceTransformer transformer) {
194: this .transformer = transformer;
195: }
196:
197: public JaxenVariableContext getVariableContext() {
198: return variableContext;
199: }
200:
201: public void setVariableContext(JaxenVariableContext variableContext) {
202: this .variableContext = variableContext;
203: }
204:
205: public NamespaceContext getNamespaceContext() {
206: return namespaceContext;
207: }
208:
209: public void setNamespaceContext(NamespaceContext namespaceContext) {
210: this .namespaceContext = namespaceContext;
211: }
212:
213: public FunctionContext getFunctionContext() {
214: return functionContext;
215: }
216:
217: public void setFunctionContext(FunctionContext functionContext) {
218: this .functionContext = functionContext;
219: }
220:
221: // Implementation methods
222: // -------------------------------------------------------------------------
223: protected final XPath createXPath(String xp) throws JaxenException {
224: return new DOMXPath(xp);
225: }
226:
227: protected Object evaluateXPath(Object object) throws JaxenException {
228: return xpathObject.evaluate(object);
229: }
230:
231: protected boolean evaluateXPathAsBoolean(Object object)
232: throws JaxenException {
233: return xpathObject.booleanValueOf(object);
234: }
235:
236: protected Object getXMLNode(MessageExchange exchange,
237: NormalizedMessage message) throws TransformerException,
238: MessagingException, ParserConfigurationException,
239: IOException, SAXException {
240: Node node = null;
241: // ensure re-readability of the content if the expression also needs to
242: // access the content
243: if (useMessageContent) {
244: MessageUtil.enableContentRereadability(message);
245: }
246: if (message != null) {
247: node = transformer.toDOMNode(message);
248: } else {
249: LOG.warn("Null message for exchange: " + exchange);
250: }
251: if (node == null) {
252: // lets make an empty document to avoid Jaxen throwing a
253: // NullPointerException
254: node = transformer.createDocument();
255: }
256: return node;
257: }
258: }
|