You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2011/10/26 09:24:17 UTC

svn commit: r1189052 - in /camel/branches/camel-2.8.x: ./ components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryFromFileExceptionTest.java

Author: davsclaus
Date: Wed Oct 26 07:24:16 2011
New Revision: 1189052

URL: http://svn.apache.org/viewvc?rev=1189052&view=rev
Log:
CAMEL-4584: Added option allowStAX to xquery component. Fixed issue with not closing underlying input stream if used.

Added:
    camel/branches/camel-2.8.x/components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryFromFileExceptionTest.java
      - copied unchanged from r1188879, camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/component/xquery/XQueryFromFileExceptionTest.java
Modified:
    camel/branches/camel-2.8.x/   (props changed)
    camel/branches/camel-2.8.x/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java

Propchange: camel/branches/camel-2.8.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Oct 26 07:24:16 2011
@@ -1 +1 @@
-/camel/trunk:1186106,1186625,1186772,1187221,1187485,1187882,1187893,1188070-1188085,1188642,1188674
+/camel/trunk:1186106,1186625,1186772,1187221,1187485,1187882,1187893,1188070-1188085,1188642,1188674,1188879

Propchange: camel/branches/camel-2.8.x/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.

Modified: camel/branches/camel-2.8.x/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.8.x/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java?rev=1189052&r1=1189051&r2=1189052&view=diff
==============================================================================
--- camel/branches/camel-2.8.x/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java (original)
+++ camel/branches/camel-2.8.x/components/camel-saxon/src/main/java/org/apache/camel/component/xquery/XQueryBuilder.java Wed Oct 26 07:24:16 2011
@@ -34,8 +34,13 @@ import java.util.concurrent.atomic.Atomi
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
 import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXSource;
 import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
 
+import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
 import net.sf.saxon.Configuration;
@@ -63,6 +68,7 @@ import org.apache.camel.converter.jaxp.B
 import org.apache.camel.converter.jaxp.StringSource;
 import org.apache.camel.converter.jaxp.XmlConverter;
 import org.apache.camel.spi.NamespaceAware;
+import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.MessageHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -89,6 +95,7 @@ public abstract class XQueryBuilder impl
     private final AtomicBoolean initialized = new AtomicBoolean(false);
     private boolean stripsAllWhiteSpace = true;
     private ModuleURIResolver moduleURIResolver;
+    private boolean allowStAX;
 
     @Override
     public String toString() {
@@ -180,8 +187,10 @@ public abstract class XQueryBuilder impl
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
         Result result = new StreamResult(buffer);
         getExpression().pull(createDynamicContext(exchange), result, properties);
-        byte[] bytes = buffer.toByteArray();
-        return bytes;
+
+        byte[] answer = buffer.toByteArray();
+        buffer.close();
+        return answer;
     }
 
     public String evaluateAsString(Exchange exchange) throws Exception {
@@ -192,7 +201,10 @@ public abstract class XQueryBuilder impl
         for (Item item = iter.next(); item != null; item = iter.next()) {
             buffer.append(item.getStringValueCS());
         }
-        return buffer.toString();
+
+        String answer = buffer.toString();
+        buffer.close();
+        return answer;
     }
 
     public boolean matches(Exchange exchange) {
@@ -327,6 +339,16 @@ public abstract class XQueryBuilder impl
         return this;
     }
 
+    /**
+     * Enables to allow using StAX.
+     * <p/>
+     * When enabled StAX is preferred as the first choice as {@link Source}.
+     */
+    public XQueryBuilder allowStAX() {
+        setAllowStAX(true);
+        return this;
+    }
+
     // Properties
     // -------------------------------------------------------------------------
 
@@ -411,6 +433,14 @@ public abstract class XQueryBuilder impl
         this.stripsAllWhiteSpace = stripsAllWhiteSpace;
     }
 
+    public boolean isAllowStAX() {
+        return allowStAX;
+    }
+
+    public void setAllowStAX(boolean allowStAX) {
+        this.allowStAX = allowStAX;
+    }
+
     // Implementation methods
     // -------------------------------------------------------------------------
 
@@ -433,35 +463,32 @@ public abstract class XQueryBuilder impl
         if (item != null) {
             dynamicQueryContext.setContextItem(item);
         } else {
-            Source source = in.getBody(Source.class);
-            if (source == null) {
-                Object body = in.getBody();
-
-                // lets try coerce some common types into something JAXP can deal with
-                if (body instanceof GenericFile) {
-                    // special for files so we can work with them out of the box
-                    InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, body);
-                    source = converter.toDOMSource(is);
-                } else if (body instanceof BeanInvocation) {
-                    // if its a null bean invocation then handle that
-                    BeanInvocation bi = exchange.getContext().getTypeConverter().convertTo(BeanInvocation.class, body);
-                    if (bi.getArgs() != null && bi.getArgs().length == 1 && bi.getArgs()[0] == null) {
-                        // its a null argument from the bean invocation so use null as answer
-                        source = null;
-                    }
-                } else if (body instanceof String) {
-                    source = converter.toDOMSource(body.toString());
+            Object body = in.getBody();
+
+            // the underlying input stream, which we need to close to avoid locking files or other resources
+            InputStream is = null;
+            try {
+                Source source;
+                // only convert to input stream if really needed
+                if (isInputStreamNeeded(exchange)) {
+                    is = exchange.getIn().getBody(InputStream.class);
+                    source = getSource(exchange, is);
                 } else {
-                    // try some of Camels type converters
-                    InputStream is = in.getBody(InputStream.class);
-                    if (is != null) {
+                    source = getSource(exchange, body);
+                }
+
+                // there is a couple of special types we need to check
+                if (source == null) {
+                    if (body instanceof GenericFile) {
+                        // special for files so we can work with them out of the box
+                        is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, body);
                         source = converter.toDOMSource(is);
-                    }
-                    // fallback and use String
-                    if (source == null) {
-                        String s = in.getBody(String.class);
-                        if (s != null) {
-                            source = converter.toDOMSource(s);
+                    } else if (body instanceof BeanInvocation) {
+                        // if its a null bean invocation then handle that
+                        BeanInvocation bi = exchange.getContext().getTypeConverter().convertTo(BeanInvocation.class, body);
+                        if (bi.getArgs() != null && bi.getArgs().length == 1 && bi.getArgs()[0] == null) {
+                            // its a null argument from the bean invocation so use null as answer
+                            source = null;
                         }
                     }
                 }
@@ -470,9 +497,13 @@ public abstract class XQueryBuilder impl
                     // indicate it was not possible to convert to a Source type
                     throw new NoTypeConversionAvailableException(body, Source.class);
                 }
+
+                DocumentInfo doc = getStaticQueryContext().buildDocument(source);
+                dynamicQueryContext.setContextItem(doc);
+            } finally {
+                // can deal if is is null
+                IOHelper.close(is);
             }
-            DocumentInfo doc = getStaticQueryContext().buildDocument(source);
-            dynamicQueryContext.setContextItem(doc);
         }
         
         configureQuery(dynamicQueryContext, exchange);
@@ -482,6 +513,69 @@ public abstract class XQueryBuilder impl
     }
 
     /**
+     * Checks whether we need an {@link InputStream} to access the message body.
+     * <p/>
+     * Depending on the content in the message body, we may not need to convert
+     * to {@link InputStream}.
+     *
+     * @param exchange the current exchange
+     * @return <tt>true</tt> to convert to {@link InputStream} beforehand converting to {@link Source} afterwards.
+     */
+    protected boolean isInputStreamNeeded(Exchange exchange) {
+        Object body = exchange.getIn().getBody();
+        if (body == null) {
+            return false;
+        }
+
+        if (body instanceof Source) {
+            return false;
+        } else if (body instanceof String) {
+            return false;
+        } else if (body instanceof Document) {
+            return false;
+        }
+
+        // yes an input stream is needed
+        return true;
+    }
+
+    /**
+     * Converts the inbound body to a {@link Source}, if the body is <b>not</b> already a {@link Source}.
+     * <p/>
+     * This implementation will prefer to source in the following order:
+     * <ul>
+     *   <li>StAX - Is StAX is allowed</li>
+     *   <li>SAX - SAX as 2nd choice</li>
+     *   <li>Stream - Stream as 3rd choice</li>
+     *   <li>DOM - DOM as 4th choice</li>
+     * </ul>
+     */
+    protected Source getSource(Exchange exchange, Object body) {
+        // body may already be a source
+        if (body instanceof Source) {
+            return (Source) body;
+        }
+
+        Source source = null;
+        if (isAllowStAX()) {
+            source = exchange.getContext().getTypeConverter().convertTo(StAXSource.class, exchange, body);
+        }
+        if (source == null) {
+            // then try SAX
+            source = exchange.getContext().getTypeConverter().convertTo(SAXSource.class, exchange, body);
+        }
+        if (source == null) {
+            // then try stream
+            source = exchange.getContext().getTypeConverter().convertTo(StreamSource.class, exchange, body);
+        }
+        if (source == null) {
+            // and fallback to DOM
+            source = exchange.getContext().getTypeConverter().convertTo(DOMSource.class, exchange, body);
+        }
+        return source;
+    }
+
+    /**
      * Configures the dynamic context with exchange specific parameters
      */
     protected void configureQuery(DynamicQueryContext dynamicQueryContext, Exchange exchange)