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 */ 017package org.apache.activemq.filter; 018 019import java.io.IOException; 020import java.lang.reflect.Constructor; 021import java.lang.reflect.InvocationTargetException; 022 023import javax.jms.JMSException; 024 025import org.apache.activemq.command.Message; 026import org.apache.activemq.util.JMSExceptionSupport; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030/** 031 * Used to evaluate an XPath Expression in a JMS selector. 032 */ 033public final class XPathExpression implements BooleanExpression { 034 035 private static final Logger LOG = LoggerFactory.getLogger(XPathExpression.class); 036 private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.activemq.XPathEvaluatorClassName"; 037 private static final String DEFAULT_EVALUATOR_CLASS_NAME = XalanXPathEvaluator.class.getName(); 038 039 private static final Constructor EVALUATOR_CONSTRUCTOR; 040 041 static { 042 String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); 043 Constructor m = null; 044 try { 045 try { 046 m = getXPathEvaluatorConstructor(cn); 047 } catch (Throwable e) { 048 LOG.warn("Invalid " + XPathEvaluator.class.getName() + " implementation: " + cn + ", reason: " + e, e); 049 cn = DEFAULT_EVALUATOR_CLASS_NAME; 050 try { 051 m = getXPathEvaluatorConstructor(cn); 052 } catch (Throwable e2) { 053 LOG.error("Default XPath evaluator could not be loaded", e); 054 } 055 } 056 } finally { 057 EVALUATOR_CONSTRUCTOR = m; 058 } 059 } 060 061 private final String xpath; 062 private final XPathEvaluator evaluator; 063 064 public static interface XPathEvaluator { 065 boolean evaluate(Message message) throws JMSException; 066 } 067 068 XPathExpression(String xpath) { 069 this.xpath = xpath; 070 this.evaluator = createEvaluator(xpath); 071 } 072 073 private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException { 074 Class c = XPathExpression.class.getClassLoader().loadClass(cn); 075 if (!XPathEvaluator.class.isAssignableFrom(c)) { 076 throw new ClassCastException("" + c + " is not an instance of " + XPathEvaluator.class); 077 } 078 return c.getConstructor(new Class[] {String.class}); 079 } 080 081 private XPathEvaluator createEvaluator(String xpath2) { 082 try { 083 return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[] {xpath}); 084 } catch (InvocationTargetException e) { 085 Throwable cause = e.getCause(); 086 if (cause instanceof RuntimeException) { 087 throw (RuntimeException)cause; 088 } 089 throw new RuntimeException("Invalid XPath Expression: " + xpath + " reason: " + e.getMessage(), e); 090 } catch (Throwable e) { 091 throw new RuntimeException("Invalid XPath Expression: " + xpath + " reason: " + e.getMessage(), e); 092 } 093 } 094 095 public Object evaluate(MessageEvaluationContext message) throws JMSException { 096 try { 097 if (message.isDropped()) { 098 return null; 099 } 100 return evaluator.evaluate(message.getMessage()) ? Boolean.TRUE : Boolean.FALSE; 101 } catch (IOException e) { 102 throw JMSExceptionSupport.create(e); 103 } 104 105 } 106 107 public String toString() { 108 return "XPATH " + ConstantExpression.encodeString(xpath); 109 } 110 111 /** 112 * @param message 113 * @return true if the expression evaluates to Boolean.TRUE. 114 * @throws JMSException 115 */ 116 public boolean matches(MessageEvaluationContext message) throws JMSException { 117 Object object = evaluate(message); 118 return object != null && object == Boolean.TRUE; 119 } 120 121}