001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.camel.builder.saxon; 019 020 import net.sf.saxon.Configuration; 021 import net.sf.saxon.om.DocumentInfo; 022 import net.sf.saxon.query.DynamicQueryContext; 023 import net.sf.saxon.query.StaticQueryContext; 024 import net.sf.saxon.query.XQueryExpression; 025 import net.sf.saxon.trans.XPathException; 026 import org.apache.camel.Exchange; 027 import org.apache.camel.Expression; 028 import org.apache.camel.Predicate; 029 import org.apache.camel.RuntimeExpressionException; 030 import org.apache.camel.util.ObjectHelper; 031 import org.apache.camel.converter.jaxp.BytesSource; 032 import org.apache.camel.converter.jaxp.XmlConverter; 033 import org.apache.camel.converter.jaxp.StringSource; 034 import org.w3c.dom.Node; 035 036 import javax.xml.transform.Result; 037 import javax.xml.transform.Source; 038 import javax.xml.transform.dom.DOMResult; 039 import javax.xml.transform.stream.StreamResult; 040 import java.io.ByteArrayOutputStream; 041 import java.io.IOException; 042 import java.io.InputStream; 043 import java.io.Reader; 044 import java.io.StringWriter; 045 import java.util.HashMap; 046 import java.util.List; 047 import java.util.Map; 048 import java.util.Properties; 049 import java.util.Set; 050 051 /** 052 * Creates an XQuery builder 053 * 054 * @version $Revision: 534053 $ 055 */ 056 public abstract class XQueryBuilder<E extends Exchange> implements Expression<E>, Predicate<E> { 057 private Configuration configuration; 058 private XQueryExpression expression; 059 private StaticQueryContext staticQueryContext; 060 private Map<String, Object> parameters = new HashMap<String, Object>(); 061 private XmlConverter converter = new XmlConverter(); 062 private ResultFormat resultsFormat = ResultFormat.DOM; 063 private Properties properties = new Properties(); 064 065 @Override 066 public String toString() { 067 return "XQuery[" + expression + "]"; 068 } 069 070 public Object evaluate(E exchange) { 071 try { 072 switch (resultsFormat) { 073 case Bytes: 074 return evaluateAsBytes(exchange); 075 case BytesSource: 076 return evaluateAsBytesSource(exchange); 077 case DOM: 078 return evaluateAsDOM(exchange); 079 case List: 080 return evaluateAsList(exchange); 081 case StringSource: 082 return evaluateAsStringSource(exchange); 083 case String: 084 default: 085 return evaluateAsString(exchange); 086 } 087 } 088 catch (Exception e) { 089 throw new RuntimeExpressionException(e); 090 } 091 } 092 093 public List evaluateAsList(E exchange) throws Exception { 094 return getExpression().evaluate(createDynamicContext(exchange)); 095 } 096 097 public Object evaluateAsStringSource(E exchange) throws Exception { 098 String text = evaluateAsString(exchange); 099 return new StringSource(text); 100 } 101 102 public Object evaluateAsBytesSource(E exchange) throws Exception { 103 byte[] bytes = evaluateAsBytes(exchange); 104 return new BytesSource(bytes); 105 } 106 107 public Node evaluateAsDOM(E exchange) throws Exception { 108 DOMResult result = new DOMResult(); 109 getExpression().pull(createDynamicContext(exchange), result, properties); 110 return result.getNode(); 111 } 112 113 public byte[] evaluateAsBytes(E exchange) throws Exception { 114 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 115 Result result = new StreamResult(buffer); 116 getExpression().pull(createDynamicContext(exchange), result, properties); 117 byte[] bytes = buffer.toByteArray(); 118 return bytes; 119 } 120 121 public String evaluateAsString(E exchange) throws Exception { 122 StringWriter buffer = new StringWriter(); 123 Result result = new StreamResult(buffer); 124 getExpression().pull(createDynamicContext(exchange), result, properties); 125 String text = buffer.toString(); 126 return text; 127 } 128 129 public boolean matches(E exchange) { 130 try { 131 List list = evaluateAsList(exchange); 132 return matches(exchange, list); 133 } 134 catch (Exception e) { 135 throw new RuntimeExpressionException(e); 136 } 137 } 138 139 public void assertMatches(String text, E exchange) throws AssertionError { 140 try { 141 List list = evaluateAsList(exchange); 142 if (!matches(exchange, list)) { 143 throw new AssertionError(this + " failed on " + exchange + " as evaluated: " + list); 144 } 145 } 146 catch (Exception e) { 147 throw new AssertionError(e); 148 } 149 } 150 151 // Builder methods 152 //------------------------------------------------------------------------- 153 public static <E extends Exchange> XQueryBuilder<E> xquery(final String queryText) { 154 return new XQueryBuilder<E>() { 155 protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) throws XPathException { 156 return staticQueryContext.compileQuery(queryText); 157 } 158 }; 159 } 160 161 public static <E extends Exchange> XQueryBuilder<E> xquery(final Reader reader) { 162 return new XQueryBuilder<E>() { 163 protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) throws XPathException, IOException { 164 return staticQueryContext.compileQuery(reader); 165 } 166 }; 167 } 168 169 public static <E extends Exchange> XQueryBuilder<E> xquery(final InputStream in, final String characterSet) { 170 return new XQueryBuilder<E>() { 171 protected XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) throws XPathException, IOException { 172 return staticQueryContext.compileQuery(in, characterSet); 173 } 174 }; 175 } 176 177 public XQueryBuilder<E> asBytes() { 178 setResultsFormat(ResultFormat.Bytes); 179 return this; 180 } 181 182 public XQueryBuilder<E> asBytesSource() { 183 setResultsFormat(ResultFormat.BytesSource); 184 return this; 185 } 186 187 public XQueryBuilder<E> asDOM() { 188 setResultsFormat(ResultFormat.DOM); 189 return this; 190 } 191 192 public XQueryBuilder<E> asDOMSource() { 193 setResultsFormat(ResultFormat.DOMSource); 194 return this; 195 } 196 197 public XQueryBuilder<E> asList() { 198 setResultsFormat(ResultFormat.List); 199 return this; 200 } 201 202 public XQueryBuilder<E> asString() { 203 setResultsFormat(ResultFormat.String); 204 return this; 205 } 206 207 public XQueryBuilder<E> asStringSource() { 208 setResultsFormat(ResultFormat.StringSource); 209 return this; 210 } 211 212 public XQueryBuilder<E> parameter(String name, Object value) { 213 parameters.put(name, value); 214 return this; 215 } 216 217 // Properties 218 //------------------------------------------------------------------------- 219 220 public XQueryExpression getExpression() throws IOException, XPathException { 221 if (expression == null) { 222 expression = createQueryExpression(getStaticQueryContext()); 223 clearBuilderReferences(); 224 } 225 return expression; 226 } 227 228 public Configuration getConfiguration() { 229 if (configuration == null) { 230 configuration = new Configuration(); 231 configuration.setHostLanguage(Configuration.XQUERY); 232 } 233 return configuration; 234 } 235 236 public void setConfiguration(Configuration configuration) { 237 this.configuration = configuration; 238 } 239 240 public StaticQueryContext getStaticQueryContext() { 241 if (staticQueryContext == null) { 242 staticQueryContext = new StaticQueryContext(getConfiguration()); 243 } 244 return staticQueryContext; 245 } 246 247 public void setStaticQueryContext(StaticQueryContext staticQueryContext) { 248 this.staticQueryContext = staticQueryContext; 249 } 250 251 public Map<String, Object> getParameters() { 252 return parameters; 253 } 254 255 public void setParameters(Map<String, Object> parameters) { 256 this.parameters = parameters; 257 } 258 259 public Properties getProperties() { 260 return properties; 261 } 262 263 public void setProperties(Properties properties) { 264 this.properties = properties; 265 } 266 267 public ResultFormat getResultsFormat() { 268 return resultsFormat; 269 } 270 271 public void setResultsFormat(ResultFormat resultsFormat) { 272 this.resultsFormat = resultsFormat; 273 } 274 275 // Implementation methods 276 // ------------------------------------------------------------------------- 277 278 /** 279 * A factory method to create the XQuery expression 280 */ 281 protected abstract XQueryExpression createQueryExpression(StaticQueryContext staticQueryContext) throws XPathException, IOException; 282 283 /** 284 * Creates a dynamic context for the given exchange 285 */ 286 protected DynamicQueryContext createDynamicContext(E exchange) throws Exception { 287 Configuration config = getConfiguration(); 288 DynamicQueryContext dynamicQueryContext = new DynamicQueryContext(config); 289 290 Source source = exchange.getIn().getBody(Source.class); 291 if (source == null) { 292 source = converter.toSource(converter.createDocument()); 293 } 294 295 DocumentInfo doc = getStaticQueryContext().buildDocument(source); 296 dynamicQueryContext.setContextItem(doc); 297 configureQuery(dynamicQueryContext, exchange); 298 return dynamicQueryContext; 299 } 300 301 /** 302 * Configures the dynamic context with exchange specific parameters 303 * 304 * @param dynamicQueryContext 305 * @param exchange 306 * @throws Exception 307 */ 308 protected void configureQuery(DynamicQueryContext dynamicQueryContext, Exchange exchange) throws Exception { 309 addParameters(dynamicQueryContext, exchange.getProperties()); 310 addParameters(dynamicQueryContext, exchange.getIn().getHeaders()); 311 addParameters(dynamicQueryContext, getParameters()); 312 313 dynamicQueryContext.setParameter("exchange", exchange); 314 dynamicQueryContext.setParameter("in", exchange.getIn()); 315 dynamicQueryContext.setParameter("out", exchange.getOut()); 316 } 317 318 protected void addParameters(DynamicQueryContext dynamicQueryContext, Map<String, Object> map) { 319 Set<Map.Entry<String, Object>> propertyEntries = map.entrySet(); 320 for (Map.Entry<String, Object> entry : propertyEntries) { 321 dynamicQueryContext.setParameter(entry.getKey(), entry.getValue()); 322 } 323 } 324 325 /** 326 * To avoid keeping around any unnecessary objects after the expresion has been created lets 327 * nullify references here 328 */ 329 protected void clearBuilderReferences() { 330 staticQueryContext = null; 331 configuration = null; 332 } 333 334 protected boolean matches(E exchange, List results) { 335 return ObjectHelper.matches(results); 336 } 337 }