Repository: camel
Updated Branches:
  refs/heads/camel-2.17.x 82716bc5a -> 33048a86a


CAMEL-10070: Add XMLStreamReader to InputStream/Reader converter


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/47c3f909
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/47c3f909
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/47c3f909

Branch: refs/heads/camel-2.17.x
Commit: 47c3f909dafeaafdb1ee729bdba90b527807fcac
Parents: 82716bc
Author: Akitoshi Yoshida <a...@apache.org>
Authored: Sat Jun 18 00:26:33 2016 +0200
Committer: Akitoshi Yoshida <a...@apache.org>
Committed: Mon Jun 20 09:50:20 2016 +0200

----------------------------------------------------------------------
 .../camel/converter/jaxp/StaxConverter.java     |  21 +++
 .../jaxp/XMLStreamReaderInputStream.java        | 170 +++++++++++++++++++
 .../converter/jaxp/XMLStreamReaderReader.java   | 162 ++++++++++++++++++
 .../camel/converter/jaxp/StaxConverterTest.java |  91 +++++++++-
 4 files changed, 442 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/47c3f909/camel-core/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java 
b/camel-core/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
index 6a908e6..d41ee7b 100644
--- 
a/camel-core/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
+++ 
b/camel-core/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
@@ -284,6 +284,27 @@ public class StaxConverter {
         }
     }
 
+    @Converter
+    public InputStream createInputStream(XMLStreamReader reader, Exchange 
exchange) {
+        XMLOutputFactory factory = getOutputFactory();
+        try {
+            String charsetName = IOHelper.getCharsetName(exchange, false);
+            return new XMLStreamReaderInputStream(reader, charsetName, 
factory);
+        } finally {
+            returnXMLOutputFactory(factory);
+        }
+    }
+
+    @Converter
+    public Reader createReader(XMLStreamReader reader, Exchange exchange) {
+        XMLOutputFactory factory = getOutputFactory();
+        try {
+            return new XMLStreamReaderReader(reader, factory);
+        } finally {
+            returnXMLOutputFactory(factory);
+        }
+    }
+
     private static boolean isWoodstox(Object factory) {
         return 
factory.getClass().getPackage().getName().startsWith("com.ctc.wstx");
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/47c3f909/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
 
b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
new file mode 100644
index 0000000..1e3158f
--- /dev/null
+++ 
b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
@@ -0,0 +1,170 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.jaxp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ *
+ */
+class XMLStreamReaderInputStream extends InputStream {
+    private static final int BUFFER_SIZE = 4096;
+    private XMLStreamReader reader;
+    private XMLStreamWriter writer;
+    private TrimmableByteArrayOutputStream chunk;
+    private byte[] buffer;
+    private String charset;
+    private int bpos;
+
+    public XMLStreamReaderInputStream(XMLStreamReader reader, String charset, 
XMLOutputFactory outfactory) {
+        this.reader = reader;
+        this.buffer = new byte[BUFFER_SIZE];
+        this.chunk = new TrimmableByteArrayOutputStream();
+        this.charset = charset == null ? "utf-8" : charset;
+        try {
+            this.writer = outfactory.createXMLStreamWriter(chunk, charset);
+        } catch (XMLStreamException e) {
+            //ignore
+        }
+    }
+
+    public XMLStreamReaderInputStream(XMLStreamReader reader, XMLOutputFactory 
outfactory) {
+        this(reader, "utf-8", outfactory);
+    }
+
+    @Override
+    public int read() throws IOException {
+        byte[] ba = new byte[1];
+        return read(ba, 0, 1) == 1 ? ba[0] : -1;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int tlen = 0;
+        while (len > 0) {
+            int n = ensureBuffering(len);
+            if (n < 0) {
+                break;
+            }
+            int clen = len > n ? n : len;
+            System.arraycopy(buffer, 0, b, off, clen);
+            System.arraycopy(buffer, clen, buffer, 0, buffer.length - clen);
+            bpos -= clen;
+            len -= clen;
+            off += clen;
+            tlen += clen;
+        }
+
+        return tlen > 0 ? tlen : -1;
+    }
+
+    private int ensureBuffering(int size) throws IOException {
+        if (size < bpos) {
+            return bpos;
+        }
+        // refill the buffer as more buffering is requested than the current 
buffer status
+        try {
+
+            // very first event
+            if (XMLStreamConstants.START_DOCUMENT == reader.getEventType()) {
+                writer.writeStartDocument(charset, "1.0");
+            }
+            if (chunk.size() < buffer.length) {
+                while (reader.hasNext()) {
+                    int code = reader.next();
+                    switch (code) {
+                    case XMLStreamConstants.END_DOCUMENT:
+                        writer.writeEndDocument();
+                        break;
+                    case XMLStreamConstants.START_ELEMENT:
+                        QName qname = reader.getName();
+                        writer.writeStartElement(qname.getPrefix(), 
qname.getLocalPart(), qname.getNamespaceURI());
+                        for (int i = 0; i < reader.getAttributeCount(); i++) {
+                            writer.writeAttribute(
+                                    reader.getAttributePrefix(i), 
reader.getAttributeNamespace(i), reader.getAttributeLocalName(i),
+                                    reader.getAttributeValue(i));
+                        }
+                        for (int i = 0; i < reader.getNamespaceCount(); i++) {
+                            
writer.writeNamespace(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
+                        }
+                        break;
+                    case XMLStreamConstants.END_ELEMENT:
+                        writer.writeEndElement();
+                        break;
+                    case XMLStreamConstants.CHARACTERS:
+                        writer.writeCharacters(reader.getText());
+                        break;
+                    case XMLStreamConstants.COMMENT:
+                        writer.writeComment(reader.getText());
+                        break;
+                    case XMLStreamConstants.CDATA:
+                        writer.writeCData(reader.getText());
+                        break;
+                    default:
+                        break;
+                    }
+
+                    // check if the chunk is full
+                    final int csize = buffer.length - bpos;
+                    if (chunk.size() > csize) {
+                        System.arraycopy(chunk.getByteArray(), 0, buffer, 
bpos, csize);
+                        bpos = buffer.length;
+                        chunk.trim(csize, 0);
+                        return buffer.length;
+                    }
+                }
+            }
+            final int csize = chunk.size() < buffer.length - bpos ? 
chunk.size() : buffer.length - bpos;
+            if (csize > 0) {
+                System.arraycopy(chunk.getByteArray(), 0, buffer, bpos, csize);
+                bpos += csize;
+                chunk.trim(csize, 0);
+                return bpos;
+            } else {
+                return bpos > 0 ? bpos : -1;
+            }
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    static class TrimmableByteArrayOutputStream extends ByteArrayOutputStream {
+        public void trim(int head, int tail) {
+            System.arraycopy(buf, head, buf, 0, count - head - tail);
+            count -= head + tail;
+        }
+
+        public byte[] toByteArray(int len) {
+            byte[] b = new byte[len];
+            System.arraycopy(buf, 0, b, 0, len);
+            return b;
+        }
+
+        byte[] getByteArray() {
+            return buf;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/47c3f909/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
 
b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
new file mode 100644
index 0000000..571c21b
--- /dev/null
+++ 
b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
@@ -0,0 +1,162 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.jaxp;
+
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ *
+ */
+class XMLStreamReaderReader extends Reader {
+    private static final int BUFFER_SIZE = 4096;
+    private XMLStreamReader reader;
+    private XMLStreamWriter writer;
+    private TrimmableCharArrayWriter chunk;
+    private char[] buffer;
+    private int bpos;
+
+    public XMLStreamReaderReader(XMLStreamReader reader, XMLOutputFactory 
outfactory) {
+        this.reader = reader;
+        this.buffer = new char[BUFFER_SIZE];
+        this.chunk = new TrimmableCharArrayWriter();
+        try {
+            this.writer = outfactory.createXMLStreamWriter(chunk);
+        } catch (XMLStreamException e) {
+            //ignore
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        
+    }
+
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        int tlen = 0;
+        while (len > 0) {
+            int n = ensureBuffering(len);
+            if (n < 0) {
+                break;
+            }
+            int clen = len > n ? n : len;
+            System.arraycopy(buffer, 0, cbuf, off, clen);
+            System.arraycopy(buffer, clen, buffer, 0, buffer.length - clen);
+            bpos -= clen;
+            len -= clen;
+            off += clen;
+            tlen += clen;
+        }
+        return tlen > 0 ? tlen : -1;
+    }
+
+    private int ensureBuffering(int size) throws IOException {
+        if (size < bpos) {
+            return bpos;
+        }
+        // refill the buffer as more buffering is requested than the current 
buffer status
+        try {
+
+            // very first event
+            if (XMLStreamConstants.START_DOCUMENT == reader.getEventType()) {
+                writer.writeStartDocument("utf-8", "1.0");
+            }
+            if (chunk.size() < buffer.length) {
+                while (reader.hasNext()) {
+                    int code = reader.next();
+                    switch (code) {
+                    case XMLStreamConstants.END_DOCUMENT:
+                        writer.writeEndDocument();
+                        break;
+                    case XMLStreamConstants.START_ELEMENT:
+                        QName qname = reader.getName();
+                        writer.writeStartElement(qname.getPrefix(), 
qname.getLocalPart(), qname.getNamespaceURI());
+                        for (int i = 0; i < reader.getAttributeCount(); i++) {
+                            writer.writeAttribute(
+                                    reader.getAttributePrefix(i), 
reader.getAttributeNamespace(i), reader.getAttributeLocalName(i), 
+                                    reader.getAttributeValue(i));
+                        }
+                        for (int i = 0; i < reader.getNamespaceCount(); i++) {
+                            
writer.writeNamespace(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
+                        }
+                        break;
+                    case XMLStreamConstants.END_ELEMENT:
+                        writer.writeEndElement();
+                        break;
+                    case XMLStreamConstants.CHARACTERS:
+                        writer.writeCharacters(reader.getText());
+                        break;
+                    case XMLStreamConstants.COMMENT:
+                        writer.writeComment(reader.getText());
+                        break;
+                    case XMLStreamConstants.CDATA:
+                        writer.writeCData(reader.getText());
+                        break;
+                    default:
+                        break;
+                    }
+                    
+                    // check if the chunk is full
+                    final int csize = buffer.length - bpos;
+                    if (chunk.size() > csize) {
+                        System.arraycopy(chunk.getCharArray(), 0, buffer, 
bpos, csize);
+                        bpos = buffer.length;
+                        chunk.trim(csize, 0);
+                        return buffer.length;
+                    }
+                }
+            }
+            final int csize = chunk.size() < buffer.length - bpos ? 
chunk.size() : buffer.length - bpos; 
+            if (csize > 0) {
+                System.arraycopy(chunk.getCharArray(), 0, buffer, bpos, csize);
+                bpos += csize;
+                chunk.trim(csize, 0);
+                return bpos;
+            } else {
+                return bpos > 0 ? bpos : -1;
+            }
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    static class TrimmableCharArrayWriter extends CharArrayWriter {
+        public void trim(int head, int tail) {
+            System.arraycopy(buf, head, buf, 0, count - head - tail);
+            count -= head + tail;
+        }
+
+        public char[] toCharArray(int len) {
+            char[] c = new char[len];
+            System.arraycopy(buf, 0, c, 0, len);
+            return c;
+        }
+
+        char[] getCharArray() {
+            return buf;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/47c3f909/camel-core/src/test/java/org/apache/camel/converter/jaxp/StaxConverterTest.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/converter/jaxp/StaxConverterTest.java
 
b/camel-core/src/test/java/org/apache/camel/converter/jaxp/StaxConverterTest.java
index d6d37e0..10e916e 100644
--- 
a/camel-core/src/test/java/org/apache/camel/converter/jaxp/StaxConverterTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/converter/jaxp/StaxConverterTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.converter.jaxp;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
+import java.io.*;
 import java.nio.charset.Charset;
+import java.util.Arrays;
 
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.XMLEventWriter;
@@ -45,6 +45,21 @@ public class StaxConverterTest extends ContextTestSupport {
 
     private static final String TEST_XML_WITH_XML_HEADER = "<?xml 
version=\"1.0\"?>" + TEST_XML;
 
+    private static final String TEST_XML_7000;
+
+    static {
+        StringBuilder sb = new StringBuilder(7000);
+        sb.append("<?xml version=\"1.0\" 
encoding=\"utf-8\"?>").append("<list>");
+        int n = 6963 - TEST_XML.length();
+        while (n > 0) {
+            sb.append(TEST_XML);
+            n -= TEST_XML.length();
+        }
+        sb.append("</list>");
+
+        TEST_XML_7000 = sb.toString();
+    }
+
     public void testEncodingXmlEventReader() throws Exception {
         TEST_XML_WITH_XML_HEADER_ISO_8859_1_AS_BYTE_ARRAY_STREAM.reset();
         XMLEventReader reader = null;
@@ -136,4 +151,76 @@ public class StaxConverterTest extends ContextTestSupport {
         assertEquals(TEST_XML, result);
     }
 
+    public void testToReaderByXmlStreamReader() throws Exception {
+        StringReader src = new StringReader(TEST_XML_7000);
+        XMLStreamReader xreader = null;
+        Reader reader = null;
+        try {
+            xreader = 
context.getTypeConverter().mandatoryConvertTo(XMLStreamReader.class, src);
+            reader = 
context.getTypeConverter().mandatoryConvertTo(Reader.class, xreader);
+
+            // verify
+            StringReader expected = new StringReader(TEST_XML_7000);
+            char[] tmp1 = new char[512];
+            char[] tmp2 = new char[512];
+            for (;;) {
+                int n1 = 0;
+                int n2 = 0;
+                try {
+                    n1 = expected.read(tmp1, 0, tmp1.length);
+                    n2 = reader.read(tmp2, 0, tmp2.length);
+                } catch (IOException e) {
+                    fail("unable to read data");
+                }
+                assertEquals(n1, n2);
+                if (n2 < 0) {
+                    break;
+                }
+                assertTrue(Arrays.equals(tmp1,  tmp2));
+            }
+        } finally {
+            if (xreader != null) {
+                xreader.close();
+            }
+            if (reader != null) {
+                reader.close();
+            }
+        }
+    }
+    public void testToInputSreamByXmlStreamReader() throws Exception {
+        StringReader src = new StringReader(TEST_XML_7000);
+        XMLStreamReader xreader = null;
+        InputStream in = null;
+        try {
+            xreader = 
context.getTypeConverter().mandatoryConvertTo(XMLStreamReader.class, src);
+            in = 
context.getTypeConverter().mandatoryConvertTo(InputStream.class, xreader);
+
+            // verify
+            InputStream expected = new 
ByteArrayInputStream(TEST_XML_7000.getBytes("utf-8"));
+            byte[] tmp1 = new byte[512];
+            byte[] tmp2 = new byte[512];
+            for (;;) {
+                int n1 = 0;
+                int n2 = 0;
+                try {
+                    n1 = expected.read(tmp1, 0, tmp1.length);
+                    n2 = in.read(tmp2, 0, tmp2.length);
+                } catch (IOException e) {
+                    fail("unable to read data");
+                }
+                assertEquals(n1, n2);
+                if (n2 < 0) {
+                    break;
+                }
+                assertTrue(Arrays.equals(tmp1,  tmp2));
+            }
+        } finally {
+            if (xreader != null) {
+                xreader.close();
+            }
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
 }

Reply via email to