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 @XmlAttribute(name = "headerName") 049 private String headerName; 050 051 @XmlTransient 052 private Class<?> resultType; 053 @XmlTransient 054 private XPathFactory xpathFactory; 055 056 057 public XPathExpression() { 058 } 059 060 public XPathExpression(String expression) { 061 super(expression); 062 } 063 064 public XPathExpression(Expression expression) { 065 setExpressionValue(expression); 066 } 067 068 public String getLanguage() { 069 return "xpath"; 070 } 071 072 public Class<?> getResultType() { 073 return resultType; 074 } 075 076 public void setResultType(Class<?> resultType) { 077 this.resultType = resultType; 078 } 079 080 public String getResultTypeName() { 081 return resultTypeName; 082 } 083 084 public void setResultTypeName(String resultTypeName) { 085 this.resultTypeName = resultTypeName; 086 } 087 088 public void setSaxon(Boolean saxon) { 089 this.saxon = saxon; 090 } 091 092 public Boolean getSaxon() { 093 return saxon; 094 } 095 096 public boolean isSaxon() { 097 return saxon != null && saxon; 098 } 099 100 public void setFactoryRef(String factoryRef) { 101 this.factoryRef = factoryRef; 102 } 103 104 public String getFactoryRef() { 105 return factoryRef; 106 } 107 108 public void setObjectModel(String objectModel) { 109 this.objectModel = objectModel; 110 } 111 112 public String getObjectModel() { 113 return objectModel; 114 } 115 116 public void setLogNamespaces(Boolean logNamespaces) { 117 this.logNamespaces = logNamespaces; 118 } 119 120 public Boolean getLogNamespaces() { 121 return logNamespaces; 122 } 123 124 public boolean isLogNamespaces() { 125 return logNamespaces != null && logNamespaces; 126 } 127 128 public String getHeaderName() { 129 return headerName; 130 } 131 132 public void setHeaderName(String headerName) { 133 this.headerName = headerName; 134 } 135 136 @Override 137 public Expression createExpression(CamelContext camelContext) { 138 if (resultType == null && resultTypeName != null) { 139 try { 140 resultType = camelContext.getClassResolver().resolveMandatoryClass(resultTypeName); 141 } catch (ClassNotFoundException e) { 142 throw ObjectHelper.wrapRuntimeCamelException(e); 143 } 144 } 145 resolveXPathFactory(camelContext); 146 return super.createExpression(camelContext); 147 } 148 149 @Override 150 public Predicate createPredicate(CamelContext camelContext) { 151 resolveXPathFactory(camelContext); 152 return super.createPredicate(camelContext); 153 } 154 155 @Override 156 protected void configureExpression(CamelContext camelContext, Expression expression) { 157 if (resultType != null) { 158 setProperty(expression, "resultType", resultType); 159 } 160 if (isSaxon()) { 161 ObjectHelper.cast(XPathBuilder.class, expression).enableSaxon(); 162 } 163 if (xpathFactory != null) { 164 setProperty(expression, "xPathFactory", xpathFactory); 165 } 166 if (objectModel != null) { 167 setProperty(expression, "objectModelUri", objectModel); 168 } 169 if (isLogNamespaces()) { 170 ObjectHelper.cast(XPathBuilder.class, expression).setLogNamespaces(true); 171 } 172 if (ObjectHelper.isNotEmpty(getHeaderName())) { 173 ObjectHelper.cast(XPathBuilder.class, expression).setHeaderName(getHeaderName()); 174 } 175 // moved the super configuration to the bottom so that the namespace init picks up the newly set XPath Factory 176 super.configureExpression(camelContext, expression); 177 178 } 179 180 @Override 181 protected void configurePredicate(CamelContext camelContext, Predicate predicate) { 182 if (resultType != null) { 183 setProperty(predicate, "resultType", resultType); 184 } 185 if (isSaxon()) { 186 ObjectHelper.cast(XPathBuilder.class, predicate).enableSaxon(); 187 } 188 if (xpathFactory != null) { 189 setProperty(predicate, "xPathFactory", xpathFactory); 190 } 191 if (objectModel != null) { 192 setProperty(predicate, "objectModelUri", objectModel); 193 } 194 if (isLogNamespaces()) { 195 ObjectHelper.cast(XPathBuilder.class, predicate).setLogNamespaces(true); 196 } 197 if (ObjectHelper.isNotEmpty(getHeaderName())) { 198 ObjectHelper.cast(XPathBuilder.class, predicate).setHeaderName(getHeaderName()); 199 } 200 // moved the super configuration to the bottom so that the namespace init picks up the newly set XPath Factory 201 super.configurePredicate(camelContext, predicate); 202 } 203 204 private void resolveXPathFactory(CamelContext camelContext) { 205 // Factory and Object Model can be set simultaneously. The underlying XPathBuilder allows for setting Saxon too, as it is simply a shortcut for 206 // 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 207 if ((ObjectHelper.isNotEmpty(factoryRef) || ObjectHelper.isNotEmpty(objectModel)) && (saxon != null)) { 208 throw new IllegalArgumentException("The saxon attribute cannot be set on the xpath element if any of the following is also set: factory, objectModel" + this); 209 } 210 211 // Validate the factory class 212 if (ObjectHelper.isNotEmpty(factoryRef)) { 213 xpathFactory = camelContext.getRegistry().lookupByNameAndType(factoryRef, XPathFactory.class); 214 if (xpathFactory == null) { 215 throw new IllegalArgumentException("The provided XPath Factory is invalid; either it cannot be resolved or it is not an XPathFactory instance"); 216 } 217 } 218 } 219 }