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 }