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
018package org.apache.activemq.filter;
019
020import java.io.StringReader;
021
022import javax.jms.BytesMessage;
023import javax.jms.JMSException;
024import javax.jms.TextMessage;
025import javax.xml.parsers.DocumentBuilder;
026import javax.xml.parsers.DocumentBuilderFactory;
027import javax.xml.xpath.XPath;
028
029import org.w3c.dom.Document;
030import org.w3c.dom.traversal.NodeIterator;
031import org.xml.sax.InputSource;
032
033import org.apache.activemq.command.Message;
034import org.apache.activemq.util.ByteArrayInputStream;
035import org.apache.xpath.CachedXPathAPI;
036import org.apache.xpath.objects.XObject;
037
038
039public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
040
041    private final String xpath;
042
043    public XalanXPathEvaluator(String xpath) {
044        this.xpath = xpath;
045    }
046
047    public boolean evaluate(Message m) throws JMSException {
048        if (m instanceof TextMessage) {
049            String text = ((TextMessage)m).getText();
050            return evaluate(text);
051        } else if (m instanceof BytesMessage) {
052            BytesMessage bm = (BytesMessage)m;
053            byte data[] = new byte[(int)bm.getBodyLength()];
054            bm.readBytes(data);
055            return evaluate(data);
056        }
057        return false;
058    }
059
060    private boolean evaluate(byte[] data) {
061        try {
062
063            InputSource inputSource = new InputSource(new ByteArrayInputStream(data));
064
065            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
066            factory.setNamespaceAware(true);
067            DocumentBuilder dbuilder = factory.newDocumentBuilder();
068            Document doc = dbuilder.parse(inputSource);
069            
070            CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
071            XObject result = cachedXPathAPI.eval(doc, xpath);
072            if (result.bool())
073                return true;
074            else {
075                NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc, xpath);
076                return (iterator.nextNode() != null);
077            }  
078
079        } catch (Throwable e) {
080            return false;
081        }
082    }
083
084    private boolean evaluate(String text) {
085        try {
086            InputSource inputSource = new InputSource(new StringReader(text));
087
088            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
089            factory.setNamespaceAware(true);
090            DocumentBuilder dbuilder = factory.newDocumentBuilder();
091            Document doc = dbuilder.parse(inputSource);
092
093            //An XPath expression could return a true or false value instead of a node.
094            //eval() is a better way to determine the boolean value of the exp.
095            //For compliance with legacy behavior where selecting an empty node returns true,
096            //selectNodeIterator is attempted in case of a failure.
097            
098            CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
099            XObject result = cachedXPathAPI.eval(doc, xpath);
100            if (result.bool())
101                return true;
102            else {
103                NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc, xpath);
104                return (iterator.nextNode() != null);
105            }           
106            
107        } catch (Throwable e) {
108            return false;
109        }
110    }
111}