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