001    /** 
002     * Copyright 2005 Hiram Chirino
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); 
005     * you may not use this file except in compliance with the License. 
006     * You may obtain a copy of the License at 
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, 
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
013     * See the License for the specific language governing permissions and 
014     * limitations under the License. 
015     * 
016     **/
017    package org.activemq.filter;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.InvocationTargetException;
021    
022    import javax.jms.JMSException;
023    import javax.jms.Message;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    
028    /**
029     * Used to evaluate an XPath Expression in a JMS selector.
030     */
031    public final class XPathExpression implements BooleanExpression {
032    
033        private static final Log log = LogFactory.getLog(XPathExpression.class);
034        private static final String EVALUATOR_SYSTEM_PROPERTY = "org.activemq.XPathEvaluatorClassName";
035        private static final String DEFAULT_EVALUATOR_CLASS_NAME=XalanXPathEvaluator.class.getName();
036        
037        private static final Constructor EVALUATOR_CONSTRUCTOR;
038        
039        static {
040            String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME);        
041            Constructor m = null;
042            try {
043                try {
044                    m = getXPathEvaluatorConstructor(cn);
045                } catch (Throwable e) {
046                    log.warn("Invalid "+XPathEvaluator.class.getName()+" implementation: "+cn+", reason: "+e,e);
047                    cn = DEFAULT_EVALUATOR_CLASS_NAME;
048                    try {
049                        m = getXPathEvaluatorConstructor(cn);
050                    } catch (Throwable e2) {
051                        log.error("Default XPath evaluator could not be loaded",e);
052                    }
053                }
054            } finally {
055                EVALUATOR_CONSTRUCTOR = m;
056            }
057        }
058    
059        private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException {
060            Class c = XPathExpression.class.getClassLoader().loadClass(cn);
061            if( !XPathEvaluator.class.isAssignableFrom(c) ) {
062                throw new ClassCastException(""+c+" is not an instance of "+XPathEvaluator.class);
063            }
064            return c.getConstructor(new Class[]{String.class});
065        }
066        
067        private final String xpath;
068        private final XPathEvaluator evaluator;
069        
070        static public interface XPathEvaluator {
071            public boolean evaluate(Message message) throws JMSException;
072        }    
073        
074        XPathExpression(String xpath) {
075            this.xpath = xpath;
076            this.evaluator = createEvaluator(xpath);
077        }
078    
079        private XPathEvaluator createEvaluator(String xpath2) {
080            try {
081                return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[]{xpath});
082            } catch (InvocationTargetException e) {
083                Throwable cause = e.getCause();
084                if( cause instanceof RuntimeException ) {
085                    throw (RuntimeException)cause;
086                }
087                throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e);
088            } catch (Throwable e) {
089                throw new RuntimeException("Invalid XPath Expression: "+xpath+" reason: "+e.getMessage(), e);
090            }
091        }
092    
093        public Object evaluate(Message message) throws JMSException {
094            return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE;
095        }
096    
097        public String toString() {
098            return "XPATH "+ConstantExpression.encodeString(xpath);
099        }
100    }