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.camel.model.language; 018 019 import javax.xml.bind.annotation.XmlAccessType; 020 import javax.xml.bind.annotation.XmlAccessorType; 021 import javax.xml.bind.annotation.XmlAttribute; 022 import javax.xml.bind.annotation.XmlRootElement; 023 import javax.xml.bind.annotation.XmlTransient; 024 import javax.xml.xpath.XPathFactory; 025 026 import org.apache.camel.CamelContext; 027 import org.apache.camel.Expression; 028 import org.apache.camel.Predicate; 029 import org.apache.camel.builder.xml.XPathBuilder; 030 import org.apache.camel.util.ObjectHelper; 031 032 /** 033 * For XPath expressions and predicates 034 */ 035 @XmlRootElement(name = "xpath") 036 @XmlAccessorType(XmlAccessType.FIELD) 037 public class XPathExpression extends NamespaceAwareExpression { 038 @XmlAttribute(name = "resultType") 039 private String resultTypeName; 040 @XmlAttribute(name = "saxon") 041 private Boolean saxon; 042 @XmlAttribute(name = "factoryRef") 043 private String factoryRef; 044 @XmlAttribute(name = "objectModel") 045 private String objectModel; 046 @XmlAttribute(name = "logNamespaces") 047 private Boolean logNamespaces; 048 049 @XmlTransient 050 private Class<?> resultType; 051 @XmlTransient 052 private XPathFactory xpathFactory; 053 054 public XPathExpression() { 055 } 056 057 public XPathExpression(String expression) { 058 super(expression); 059 } 060 061 public XPathExpression(Expression expression) { 062 setExpressionValue(expression); 063 } 064 065 public String getLanguage() { 066 return "xpath"; 067 } 068 069 public Class<?> getResultType() { 070 return resultType; 071 } 072 073 public void setResultType(Class<?> resultType) { 074 this.resultType = resultType; 075 } 076 077 public String getResultTypeName() { 078 return resultTypeName; 079 } 080 081 public void setResultTypeName(String resultTypeName) { 082 this.resultTypeName = resultTypeName; 083 } 084 085 public void setSaxon(Boolean saxon) { 086 this.saxon = saxon; 087 } 088 089 public Boolean getSaxon() { 090 return saxon; 091 } 092 093 public boolean isSaxon() { 094 return saxon != null && saxon; 095 } 096 097 public void setFactoryRef(String factoryRef) { 098 this.factoryRef = factoryRef; 099 } 100 101 public String getFactoryRef() { 102 return factoryRef; 103 } 104 105 public void setObjectModel(String objectModel) { 106 this.objectModel = objectModel; 107 } 108 109 public String getObjectModel() { 110 return objectModel; 111 } 112 113 public void setLogNamespaces(Boolean logNamespaces) { 114 this.logNamespaces = logNamespaces; 115 } 116 117 public Boolean getLogNamespaces() { 118 return logNamespaces; 119 } 120 121 public boolean isLogNamespaces() { 122 return logNamespaces != null && logNamespaces; 123 } 124 125 @Override 126 public Expression createExpression(CamelContext camelContext) { 127 if (resultType == null && resultTypeName != null) { 128 try { 129 resultType = camelContext.getClassResolver().resolveMandatoryClass(resultTypeName); 130 } catch (ClassNotFoundException e) { 131 throw ObjectHelper.wrapRuntimeCamelException(e); 132 } 133 } 134 resolveXPathFactory(camelContext); 135 return super.createExpression(camelContext); 136 } 137 138 @Override 139 public Predicate createPredicate(CamelContext camelContext) { 140 resolveXPathFactory(camelContext); 141 return super.createPredicate(camelContext); 142 } 143 144 @Override 145 protected void configureExpression(CamelContext camelContext, Expression expression) { 146 if (resultType != null) { 147 setProperty(expression, "resultType", resultType); 148 } 149 if (isSaxon()) { 150 ObjectHelper.cast(XPathBuilder.class, expression).enableSaxon(); 151 } 152 if (xpathFactory != null) { 153 setProperty(expression, "xPathFactory", xpathFactory); 154 } 155 if (objectModel != null) { 156 setProperty(expression, "objectModelUri", objectModel); 157 } 158 if (isLogNamespaces()) { 159 ObjectHelper.cast(XPathBuilder.class, expression).setLogNamespaces(true); 160 } 161 // moved the super configuration to the bottom so that the namespace init picks up the newly set XPath Factory 162 super.configureExpression(camelContext, expression); 163 164 } 165 166 @Override 167 protected void configurePredicate(CamelContext camelContext, Predicate predicate) { 168 if (resultType != null) { 169 setProperty(predicate, "resultType", resultType); 170 } 171 if (isSaxon()) { 172 ObjectHelper.cast(XPathBuilder.class, predicate).enableSaxon(); 173 } 174 if (xpathFactory != null) { 175 setProperty(predicate, "xPathFactory", xpathFactory); 176 } 177 if (objectModel != null) { 178 setProperty(predicate, "objectModelUri", objectModel); 179 } 180 if (isLogNamespaces()) { 181 ObjectHelper.cast(XPathBuilder.class, predicate).setLogNamespaces(true); 182 } 183 // moved the super configuration to the bottom so that the namespace init picks up the newly set XPath Factory 184 super.configurePredicate(camelContext, predicate); 185 } 186 187 private void resolveXPathFactory(CamelContext camelContext) { 188 // Factory and Object Model can be set simultaneously. The underlying XPathBuilder allows for setting Saxon too, as it is simply a shortcut for 189 // setting the appropriate Object Model, it is not wise to allow this in XML because the order of invocation of the setters by JAXB may cause undeterministic behaviour 190 if ((ObjectHelper.isNotEmpty(factoryRef) || ObjectHelper.isNotEmpty(objectModel)) && (saxon != null)) { 191 throw new IllegalArgumentException("The saxon attribute cannot be set on the xpath element if any of the following is also set: factory, objectModel" + this); 192 } 193 194 // Validate the factory class 195 if (ObjectHelper.isNotEmpty(factoryRef)) { 196 xpathFactory = camelContext.getRegistry().lookup(factoryRef, XPathFactory.class); 197 if (xpathFactory == null) { 198 throw new IllegalArgumentException("The provided XPath Factory is invalid; either it cannot be resolved or it is not an XPathFactory instance"); 199 } 200 } 201 } 202 }