You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ni...@apache.org on 2010/01/09 15:25:04 UTC

svn commit: r897459 - in /camel/trunk: camel-core/src/main/java/org/apache/camel/ camel-core/src/main/java/org/apache/camel/converter/ camel-core/src/main/java/org/apache/camel/model/dataformat/ camel-core/src/test/java/org/apache/camel/component/file/...

Author: ningjiang
Date: Sat Jan  9 14:25:03 2010
New Revision: 897459

URL: http://svn.apache.org/viewvc?rev=897459&view=rev
Log:
CAMEL-2330 applied the patch of Pavel with thanks

Added:
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java   (with props)
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java.orig
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java   (with props)
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java   (with props)
    camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java   (with props)
    camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java   (with props)
    camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java   (with props)
    camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java   (with props)
Removed:
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbFilterReader.java
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/model/dataformat/JaxbDataFormat.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FromFileMoveFileIfProcessFailsTest.java
    camel/trunk/components/camel-cxf/pom.xml
    camel/trunk/components/camel-jaxb/pom.xml
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
    camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java
    camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbTest.java
    camel/trunk/components/camel-jaxb/src/test/resources/org/apache/camel/jaxb/CamelJaxbTest.xml
    camel/trunk/parent/pom.xml

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java Sat Jan  9 14:25:03 2010
@@ -60,6 +60,8 @@
     String ERRORHANDLER_HANDLED = "CamelErrorHandlerHandled";
     String FAILURE_HANDLED      = "CamelFailureHandled";
     String FAILURE_ENDPOINT     = "CamelFailureEndpoint";
+    
+    String FILTER_NON_XML_CHARS = "CamelFilterNonXmlChars";
 
     String FILE_LOCAL_WORK_PATH = "CamelFileLocalWorkPath";
     String FILE_NAME            = "CamelFileName";

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java Sat Jan  9 14:25:03 2010
@@ -327,7 +327,7 @@
         return new ByteArrayInputStream(os.toByteArray());
     }
 
-    private static String getCharsetName(Exchange exchange) {
+    public static String getCharsetName(Exchange exchange) {
         if (exchange != null) {
             String charsetName = exchange.getProperty(Exchange.CHARSET_NAME, String.class);
             if (charsetName != null) {
@@ -337,7 +337,7 @@
         return getDefaultCharsetName();
     }
     
-    private static String getDefaultCharsetName() {
+    public static String getDefaultCharsetName() {
         return Charset.defaultCharset().toString();
     }
     

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/dataformat/JaxbDataFormat.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/dataformat/JaxbDataFormat.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/model/dataformat/JaxbDataFormat.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/dataformat/JaxbDataFormat.java Sat Jan  9 14:25:03 2010
@@ -40,6 +40,8 @@
     @XmlAttribute(required = false)
     private Boolean ignoreJAXBElement;
     @XmlAttribute(required = false)
+    private Boolean filterNonXmlChars;
+    @XmlAttribute(required = false)
     private String encoding;
 
     public JaxbDataFormat() {
@@ -75,6 +77,14 @@
         this.ignoreJAXBElement = ignoreJAXBElement;
     }
     
+    public Boolean getFilterNonXmlChars() {
+        return filterNonXmlChars;
+    }
+    
+    public void setFilterNonXmlChars(Boolean filterNonXmlChars) {
+        this.filterNonXmlChars = filterNonXmlChars;
+    }
+    
     @Override
     protected void configureDataFormat(DataFormat dataFormat) {
         Boolean answer = ObjectHelper.toBoolean(getPrettyPrint());
@@ -89,6 +99,12 @@
         } else { // the default value is true
             setProperty(dataFormat, "ignoreJAXBElement", Boolean.TRUE);
         }
+        answer = ObjectHelper.toBoolean(getFilterNonXmlChars());
+        if (answer != null && answer) {
+            setProperty(dataFormat, "filterNonXmlChars", Boolean.TRUE);
+        } else { // the default value is false
+            setProperty(dataFormat, "filterNonXmlChars", Boolean.FALSE);
+        }        
         if (encoding != null) {
             setProperty(dataFormat, "encoding", encoding);
         }

Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FromFileMoveFileIfProcessFailsTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FromFileMoveFileIfProcessFailsTest.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FromFileMoveFileIfProcessFailsTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FromFileMoveFileIfProcessFailsTest.java Sat Jan  9 14:25:03 2010
@@ -47,11 +47,12 @@
         return new RouteBuilder() {
             public void configure() throws Exception {
                 from("file://target/movefile?moveFailed=error")
-                        .convertBodyTo(String.class).to("mock:foo").process(new Processor() {
-                    public void process(Exchange exchange) throws Exception {
-                        throw new IllegalArgumentException("Forced by unittest");
-                    }
-                });
+                        .convertBodyTo(String.class).to("mock:foo").process(
+                            new Processor() {
+                                public void process(Exchange exchange) throws Exception {
+                                    throw new IllegalArgumentException("Forced by unittest");
+                                }
+                            });
             }
         };
     }

Modified: camel/trunk/components/camel-cxf/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-cxf/pom.xml?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/components/camel-cxf/pom.xml (original)
+++ camel/trunk/components/camel-cxf/pom.xml Sat Jan  9 14:25:03 2010
@@ -132,7 +132,7 @@
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
     </dependency>
-        
+
     <!--  Test Dependencies -->
     <dependency>
       <groupId>org.apache.camel</groupId>

Modified: camel/trunk/components/camel-jaxb/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/pom.xml?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/components/camel-jaxb/pom.xml (original)
+++ camel/trunk/components/camel-jaxb/pom.xml Sat Jan  9 14:25:03 2010
@@ -93,6 +93,16 @@
             <artifactId>log4j</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+	        <groupId>org.codehaus.woodstox</groupId>
+	        <artifactId>wstx-asl</artifactId>
+	        <version>3.2.9</version>
+        </dependency>        
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

Modified: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java (original)
+++ camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FallbackTypeConverter.java Sat Jan  9 14:25:03 2010
@@ -181,11 +181,11 @@
             if (value instanceof InputStream) {
                 return unmarshaller.unmarshal((InputStream) value);
             } else if (value instanceof Reader) {
-                JaxbFilterReader filterReader;
-                if (value instanceof JaxbFilterReader) {
-                    filterReader = (JaxbFilterReader) value;
+                NonXmlFilterReader filterReader;
+                if (value instanceof NonXmlFilterReader) {
+                    filterReader = (NonXmlFilterReader) value;
                 } else {
-                    filterReader = new JaxbFilterReader((Reader)value);
+                    filterReader = new NonXmlFilterReader((Reader)value);
                 }
                 return unmarshaller.unmarshal(filterReader);
             } else if (value instanceof Source) {

Added: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java (added)
+++ camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,208 @@
+/**
+ * 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.jaxb;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ * {@link XMLStreamWriter} wrapper that filters out non-XML characters, see
+ * {@link NonXmlCharFilterer} for details. Filtering applies to
+ * <ul>
+ * <li>Characters</li>
+ * <li>CData</li>
+ * <li>Attributes</li>
+ * <li>Comments</li>
+ * </ul>
+ * 
+ * @see XMLStreamWriter
+ */
+public class FilteringXmlStreamWriter implements XMLStreamWriter {
+    NonXmlCharFilterer nonXmlCharFilterer = new NonXmlCharFilterer();
+
+    private XMLStreamWriter writer;
+
+    /**
+     * @param writer
+     *            target writer to wrap.
+     */
+    public FilteringXmlStreamWriter(XMLStreamWriter writer) {
+        this.writer = writer;
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeAttribute(String prefix, String namespaceURI, String localName, String value)
+        throws XMLStreamException {
+        String filteredValue = nonXmlCharFilterer.filter(value);
+        writer.writeAttribute(prefix, namespaceURI, localName, filteredValue);
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeAttribute(String namespaceURI, String localName, String value)
+        throws XMLStreamException {
+        String filteredValue = nonXmlCharFilterer.filter(value);
+        writer.writeAttribute(namespaceURI, localName, filteredValue);
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeAttribute(String localName, String value) throws XMLStreamException {
+        String filteredValue = nonXmlCharFilterer.filter(value);
+        writer.writeAttribute(localName, filteredValue);
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeCData(String data) throws XMLStreamException {
+        String filteredData = nonXmlCharFilterer.filter(data);
+        writer.writeCData(filteredData);
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
+        nonXmlCharFilterer.filter(text, start, len);
+        writer.writeCharacters(text, start, len);
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeCharacters(String text) throws XMLStreamException {
+        String filteredText = nonXmlCharFilterer.filter(text);
+        writer.writeCharacters(filteredText);
+    }
+
+    /**
+     * This method applies filtering before delegating call to {@link #writer}.
+     */
+    public void writeComment(String data) throws XMLStreamException {
+        String filteredData = nonXmlCharFilterer.filter(data);
+        writer.writeComment(filteredData);
+    }
+
+    public void close() throws XMLStreamException {
+        writer.close();
+    }
+
+    public void flush() throws XMLStreamException {
+        writer.flush();
+    }
+
+    public NamespaceContext getNamespaceContext() {
+        return writer.getNamespaceContext();
+    }
+
+    public String getPrefix(String uri) throws XMLStreamException {
+        return writer.getPrefix(uri);
+    }
+
+    public Object getProperty(String name) throws IllegalArgumentException {
+        return writer.getProperty(name);
+    }
+
+    public void setDefaultNamespace(String uri) throws XMLStreamException {
+        writer.setDefaultNamespace(uri);
+    }
+
+    public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
+        writer.setNamespaceContext(context);
+    }
+
+    public void setPrefix(String prefix, String uri) throws XMLStreamException {
+        writer.setPrefix(prefix, uri);
+    }
+
+    public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
+        writer.writeDefaultNamespace(namespaceURI);
+    }
+
+    public void writeDTD(String dtd) throws XMLStreamException {
+        writer.writeDTD(dtd);
+    }
+
+    public void writeEmptyElement(String prefix, String localName, String namespaceURI)
+        throws XMLStreamException {
+        writer.writeEmptyElement(prefix, localName, namespaceURI);
+    }
+
+    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+        writer.writeEmptyElement(namespaceURI, localName);
+    }
+
+    public void writeEmptyElement(String localName) throws XMLStreamException {
+        writer.writeEmptyElement(localName);
+    }
+
+    public void writeEndDocument() throws XMLStreamException {
+        writer.writeEndDocument();
+    }
+
+    public void writeEndElement() throws XMLStreamException {
+        writer.writeEndElement();
+    }
+
+    public void writeEntityRef(String name) throws XMLStreamException {
+        writer.writeEntityRef(name);
+    }
+
+    public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
+        writer.writeNamespace(prefix, namespaceURI);
+    }
+
+    public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
+        writer.writeProcessingInstruction(target, data);
+    }
+
+    public void writeProcessingInstruction(String target) throws XMLStreamException {
+        writer.writeProcessingInstruction(target);
+    }
+
+    public void writeStartDocument() throws XMLStreamException {
+        writer.writeStartDocument();
+    }
+
+    public void writeStartDocument(String encoding, String version) throws XMLStreamException {
+        writer.writeStartDocument(encoding, version);
+    }
+
+    public void writeStartDocument(String version) throws XMLStreamException {
+        writer.writeStartDocument(version);
+    }
+
+    public void writeStartElement(String prefix, String localName, String namespaceURI)
+        throws XMLStreamException {
+        writer.writeStartElement(prefix, localName, namespaceURI);
+    }
+
+    public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
+        writer.writeStartElement(namespaceURI, localName);
+    }
+
+    public void writeStartElement(String localName) throws XMLStreamException {
+        writer.writeStartElement(localName);
+    }
+
+}

Propchange: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriter.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java (original)
+++ camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java Sat Jan  9 14:25:03 2010
@@ -18,13 +18,19 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBElement;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.converter.IOConverter;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.util.IOHelper;
 
@@ -35,10 +41,12 @@
  * @version $Revision$
  */
 public class JaxbDataFormat implements DataFormat {
+
     private JAXBContext context;
     private String contextPath;
     private boolean prettyPrint = true;
     private boolean ignoreJAXBElement = true;
+    private boolean filterNonXmlChars;
     private String encoding;
 
     public JaxbDataFormat() {
@@ -59,7 +67,7 @@
             if (isPrettyPrint()) {
                 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
             } 
-            // exchange take precedense over encoding option
+            // exchange take precedence over encoding option
             String charset = exchange.getProperty(Exchange.CHARSET_NAME, String.class);
             if (charset == null) {
                 charset = encoding;
@@ -68,17 +76,37 @@
                 marshaller.setProperty(Marshaller.JAXB_ENCODING, charset);
             }
 
-            marshaller.marshal(graph, stream);
+            marshal(exchange, graph, stream, marshaller);
 
         } catch (JAXBException e) {
             throw IOHelper.createIOException(e);
+        } catch (XMLStreamException e) {
+            throw IOHelper.createIOException(e);
         }
     }
 
+    void marshal(Exchange exchange, Object graph, OutputStream stream, Marshaller marshaller)
+        throws XMLStreamException, JAXBException {
+        if (needFiltering(exchange)) {
+            XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(stream);
+            FilteringXmlStreamWriter filteringWriter = new FilteringXmlStreamWriter(writer);
+            marshaller.marshal(graph, filteringWriter);
+        } else {
+            marshaller.marshal(graph, stream);
+        }
+    }
+    
     public Object unmarshal(Exchange exchange, InputStream stream) throws IOException, ClassNotFoundException {
         try {
             // must create a new instance of unmarshaller as its not thread safe
-            Object answer = getContext().createUnmarshaller().unmarshal(stream);
+            Object answer;
+            Unmarshaller unmarshaller = getContext().createUnmarshaller();
+            if (needFiltering(exchange)) {
+                answer = unmarshaller.unmarshal(new NonXmlFilterReader(new InputStreamReader(stream)));
+            } else  {
+                answer = unmarshaller.unmarshal(stream);
+            }
+
             if (answer instanceof JAXBElement && isIgnoreJAXBElement()) {
                 answer = ((JAXBElement<?>)answer).getValue();
             }
@@ -86,7 +114,12 @@
         } catch (JAXBException e) {
             throw IOHelper.createIOException(e);
         }
-    }    
+    }
+    
+    protected boolean needFiltering(Exchange exchange) {
+        // exchange property takes precedence over data format property
+        return exchange.getProperty(Exchange.FILTER_NON_XML_CHARS, filterNonXmlChars, Boolean.class);
+    }
 
     // Properties
     // -------------------------------------------------------------------------
@@ -125,6 +158,14 @@
         this.prettyPrint = prettyPrint;
     }
 
+    public boolean isFilterNonXmlChars() {
+        return filterNonXmlChars;
+    }
+
+    public void setFilterNonXmlChars(boolean filterNonXmlChars) {
+        this.filterNonXmlChars = filterNonXmlChars;
+    }
+
     public String getEncoding() {
         return encoding;
     }

Added: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java.orig
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java.orig?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java.orig (added)
+++ camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java.orig Sat Jan  9 14:25:03 2010
@@ -0,0 +1,143 @@
+/**
+ * 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.jaxb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.util.IOHelper;
+
+/**
+ * A <a href="http://camel.apache.org/data-format.html">data format</a> ({@link DataFormat})
+ * using JAXB2 to marshal to and from XML
+ *
+ * @version $Revision: 834590 $
+ */
+public class JaxbDataFormat implements DataFormat {
+    private JAXBContext context;
+    private String contextPath;
+    private boolean prettyPrint = true;
+    private boolean ignoreJAXBElement = true;
+    private String encoding;
+
+    public JaxbDataFormat() {
+    }
+
+    public JaxbDataFormat(JAXBContext context) {
+        this.context = context;
+    }
+
+    public JaxbDataFormat(String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    public void marshal(Exchange exchange, Object graph, OutputStream stream) throws IOException {
+        try {            
+            // must create a new instance of marshaller as its not thread safe
+            Marshaller marshaller = getContext().createMarshaller();
+            if (isPrettyPrint()) {
+                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+            } 
+            // exchange take precedense over encoding option
+            String charset = exchange.getProperty(Exchange.CHARSET_NAME, String.class);
+            if (charset == null) {
+                charset = encoding;
+            }
+            if (charset != null) {
+                marshaller.setProperty(Marshaller.JAXB_ENCODING, charset);
+            }
+
+            marshaller.marshal(graph, stream);
+
+        } catch (JAXBException e) {
+            throw IOHelper.createIOException(e);
+        }
+    }
+
+    public Object unmarshal(Exchange exchange, InputStream stream) throws IOException, ClassNotFoundException {
+        try {
+            // must create a new instance of unmarshaller as its not thread safe
+            Object answer = getContext().createUnmarshaller().unmarshal(stream);
+            if (answer instanceof JAXBElement && isIgnoreJAXBElement()) {
+                answer = ((JAXBElement<?>)answer).getValue();
+            }
+            return answer;
+        } catch (JAXBException e) {
+            throw IOHelper.createIOException(e);
+        }
+    }    
+
+    // Properties
+    // -------------------------------------------------------------------------
+    public boolean isIgnoreJAXBElement() {        
+        return ignoreJAXBElement;
+    }
+    
+    public void setIgnoreJAXBElement(boolean flag) {
+        ignoreJAXBElement = flag;
+    }
+    
+    public synchronized JAXBContext getContext() throws JAXBException {
+        if (context == null) {
+            context = createContext();
+        }
+        return context;
+    }
+
+    public void setContext(JAXBContext context) {
+        this.context = context;
+    }
+
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    public void setContextPath(String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    public boolean isPrettyPrint() {
+        return prettyPrint;
+    }
+
+    public void setPrettyPrint(boolean prettyPrint) {
+        this.prettyPrint = prettyPrint;
+    }
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    protected JAXBContext createContext() throws JAXBException {
+        if (contextPath != null) {
+            return JAXBContext.newInstance(contextPath);
+        } else {
+            return JAXBContext.newInstance();
+        }
+    }
+}

Added: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java (added)
+++ camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,96 @@
+/**
+ * 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.jaxb;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Provides filtering of characters that do fall into <a
+ * href="http://www.w3.org/TR/2004/REC-xml-20040204/#NT-Char">range defined by
+ * XML 1.0 spec</a>. <i>Filtering</i> here means replacement with space char.
+ * 
+ * 
+ */
+class NonXmlCharFilterer {
+    private static final transient Log LOG = LogFactory.getLog(FilteringXmlStreamWriter.class);
+    private static final char REPLACEMENT_CHAR = ' ';
+
+    /**
+     * Determines whether specified character needs to be filtered.
+     */
+    boolean isFiltered(char c) {
+        // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
+        // [#x10000-#x10FFFF]
+        // Won't be checking last interval, as it goes beyond 0xFFFF.
+        if (c == 0x9 || c == 0xA || c == 0xD || (c >= 0x20 && c <= 0xD7FF)
+                || (c >= 0xE000 && c <= 0xFFFD)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Filter specified char array by replacing non-XML chars with space. Only
+     * part of array specified by <code>offset</code> and <code>length</code> is
+     * affected.
+     * 
+     * @return <code>true</code> if <code>content</code> was modified,
+     *         <code>false</code> otherwise.
+     */
+    public boolean filter(char[] content, int offset, int length) {
+        if (content == null) {
+            return false;
+        }
+
+        boolean filtered = false;
+        for (int i = offset; i < offset + length; i++) {
+            if (isFiltered(content[i])) {
+                filtered = true;
+                content[i] = REPLACEMENT_CHAR;
+            }
+        }
+
+        if (filtered) {
+            LOG.warn("Identified and replaced non-XML chars");
+        }
+
+        return filtered;
+    }
+
+    /**
+     * Filter specified string by replacing illegal chars with space.
+     * 
+     * @return filtered string
+     */
+    public String filter(String original) {
+        if (original == null) {
+            return null;
+        }
+
+        char[] chars = original.toCharArray();
+        if (!filter(chars, 0, chars.length)) {
+            return original;
+        }
+
+        String filtered = new String(chars);
+        LOG.warn("Illegal characters were filtered; original => \"" + original
+                + "\", filtered => \"" + filtered + "\"");
+        return filtered;
+    }
+
+}

Propchange: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlCharFilterer.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java (added)
+++ camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,48 @@
+/**
+ * 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.jaxb;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This FilterReader will filter out the non-XML characters, see
+ * {@link NonXmlCharFilterer} for details.
+ */
+public class NonXmlFilterReader extends FilterReader {
+    NonXmlCharFilterer nonXmlCharFilterer = new NonXmlCharFilterer();
+
+    protected NonXmlFilterReader(Reader in) {
+        super(in);
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     * 
+     * @exception IOException
+     *                If an I/O error occurs
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        int read = in.read(cbuf, off, len);
+        if (read > 0) {
+            nonXmlCharFilterer.filter(cbuf, off, read);
+        }
+        return read;
+    }
+
+}

Propchange: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/NonXmlFilterReader.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java (added)
+++ camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,116 @@
+/**
+ * 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.jaxb;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.easymock.classextension.EasyMockSupport;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.same;
+
+public class FilteringXmlStreamWriterTest extends EasyMockSupport {
+    private FilteringXmlStreamWriter filteringXmlStreamWriter;
+    private NonXmlCharFilterer nonXmlCharFiltererMock;
+    private XMLStreamWriter xmlStreamWriterMock;
+
+    // only testing non-generated methods, those that do apply filtering
+
+    @Before
+    public void setUp() {
+        xmlStreamWriterMock = createStrictMock(XMLStreamWriter.class);
+        nonXmlCharFiltererMock = createStrictMock(NonXmlCharFilterer.class);
+        filteringXmlStreamWriter = new FilteringXmlStreamWriter(xmlStreamWriterMock);
+        filteringXmlStreamWriter.nonXmlCharFilterer = nonXmlCharFiltererMock;
+    }
+
+    @Test
+    public void testWriteAttribute2Args() throws XMLStreamException {
+        expect(nonXmlCharFiltererMock.filter("value")).andReturn("filteredValue");
+        xmlStreamWriterMock.writeAttribute("localName", "filteredValue");
+        replayAll();
+
+        filteringXmlStreamWriter.writeAttribute("localName", "value");
+        verifyAll();
+    }
+
+    @Test
+    public void testWriteAttribute3Args() throws XMLStreamException {
+        expect(nonXmlCharFiltererMock.filter("value")).andReturn("filteredValue");
+        xmlStreamWriterMock.writeAttribute("namespaceURI", "localName", "filteredValue");
+        replayAll();
+
+        filteringXmlStreamWriter.writeAttribute("namespaceURI", "localName", "value");
+        verifyAll();
+    }
+
+    @Test
+    public void testWriteAttribute4Args() throws XMLStreamException {
+        expect(nonXmlCharFiltererMock.filter("value")).andReturn("filteredValue");
+        xmlStreamWriterMock.writeAttribute("prefix", "namespaceURI", "localName", "filteredValue");
+        replayAll();
+
+        filteringXmlStreamWriter.writeAttribute("prefix", "namespaceURI", "localName", "value");
+        verifyAll();
+    }
+
+    @Test
+    public void testWriteCData() throws XMLStreamException {
+        expect(nonXmlCharFiltererMock.filter("value")).andReturn("filteredValue");
+        xmlStreamWriterMock.writeCData("filteredValue");
+        replayAll();
+
+        filteringXmlStreamWriter.writeCData("value");
+        verifyAll();
+    }
+
+    @Test
+    public void testWriteCharacters1Arg() throws XMLStreamException {
+        expect(nonXmlCharFiltererMock.filter("value")).andReturn("filteredValue");
+        xmlStreamWriterMock.writeCharacters("filteredValue");
+        replayAll();
+
+        filteringXmlStreamWriter.writeCharacters("value");
+        verifyAll();
+    }
+
+    @Test
+    public void testWriteComment() throws XMLStreamException {
+        expect(nonXmlCharFiltererMock.filter("value")).andReturn("filteredValue");
+        xmlStreamWriterMock.writeComment("filteredValue");
+        replayAll();
+
+        filteringXmlStreamWriter.writeComment("value");
+        verifyAll();
+    }
+
+    @Test
+    public void testWriteCharacters3Args() throws XMLStreamException {
+        char[] buffer = new char[] {'a', 'b', 'c'};
+        expect(nonXmlCharFiltererMock.filter(same(buffer), eq(2), eq(3))).andReturn(true);
+        xmlStreamWriterMock.writeCharacters(same(buffer), eq(2), eq(3));
+        replayAll();
+
+        filteringXmlStreamWriter.writeCharacters(buffer, 2, 3);
+        verifyAll();
+    }
+
+}

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/FilteringXmlStreamWriterTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java (added)
+++ camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,120 @@
+/**
+ * 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.jaxb;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.camel.Exchange;
+import org.easymock.classextension.EasyMockSupport;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.same;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class JaxbDataFormatTest extends EasyMockSupport {
+    private JaxbDataFormat jaxbDataFormat;
+    private Exchange exchangeMock;
+    private Marshaller marshallerMock;
+
+    @Before
+    public void setUp() {
+        jaxbDataFormat = new JaxbDataFormat();
+        marshallerMock = createStrictMock(Marshaller.class);
+        exchangeMock = createStrictMock(Exchange.class);
+    }
+
+    @Test
+    public void testNeedFiltering() {
+        // tests combinations of data format option and exchange property
+        expect(
+                exchangeMock.getProperty(Exchange.FILTER_NON_XML_CHARS, false,
+                        Boolean.class)).andReturn(false);
+        replayAll();
+
+        assertFalse("Not expected filtering here", jaxbDataFormat.needFiltering(exchangeMock));
+        verifyAll();
+        resetAll();
+
+        expect(
+                exchangeMock.getProperty(Exchange.FILTER_NON_XML_CHARS, false,
+                        Boolean.class)).andReturn(true);
+        replayAll();
+
+        assertTrue("Expected filtering here", jaxbDataFormat.needFiltering(exchangeMock));
+        verifyAll();
+        resetAll();
+
+        jaxbDataFormat.setFilterNonXmlChars(true);
+        expect(
+                exchangeMock.getProperty(Exchange.FILTER_NON_XML_CHARS, true,
+                        Boolean.class)).andReturn(false);
+        replayAll();
+
+        assertFalse("Not expected filtering here", jaxbDataFormat.needFiltering(exchangeMock));
+        verifyAll();
+        resetAll();
+
+        expect(
+                exchangeMock.getProperty(Exchange.FILTER_NON_XML_CHARS, true,
+                        Boolean.class)).andReturn(true);
+        replayAll();
+
+        assertTrue("Expected filtering here", jaxbDataFormat.needFiltering(exchangeMock));
+        verifyAll();
+        resetAll();
+    }
+
+    @Test
+    public void testMarshalFilteringDisabled() throws XMLStreamException, JAXBException {
+        JaxbDataFormat jaxbDataFormatMock = createMockBuilder(JaxbDataFormat.class)
+                .addMockedMethod("needFiltering").createStrictMock();
+        Object graph = new Object();
+        OutputStream stream = new ByteArrayOutputStream();
+
+        expect(jaxbDataFormatMock.needFiltering(exchangeMock)).andReturn(false);
+        marshallerMock.marshal(same(graph), same(stream));
+        replayAll();
+
+        jaxbDataFormatMock.marshal(exchangeMock, graph, stream, marshallerMock);
+        verifyAll();
+    }
+
+    @Test
+    public void testMarshalFilteringEnabled() throws XMLStreamException, JAXBException {
+        JaxbDataFormat jaxbDataFormatMock = createMockBuilder(JaxbDataFormat.class)
+            .addMockedMethod("needFiltering").createStrictMock();
+
+        Object graph = new Object();
+        OutputStream stream = new ByteArrayOutputStream();
+
+        expect(jaxbDataFormatMock.needFiltering(exchangeMock)).andReturn(true);
+        marshallerMock.marshal(same(graph), isA(FilteringXmlStreamWriter.class));
+        replayAll();
+
+        jaxbDataFormatMock.marshal(exchangeMock, graph, stream, marshallerMock);
+        verifyAll();
+    }
+}

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/JaxbDataFormatTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java (added)
+++ camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,172 @@
+/**
+ * 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.jaxb;
+
+import org.easymock.Capture;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMockSupport;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.and;
+import static org.easymock.EasyMock.aryEq;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+public class NonXmlCharFiltererTest extends EasyMockSupport {
+    private NonXmlCharFilterer nonXmlCharFilterer;
+
+    @Before
+    public void setUp() {
+        nonXmlCharFilterer = new NonXmlCharFilterer();
+    }
+
+    @Test
+    public void testIsFilteredValidChars() {
+        // Per http://www.w3.org/TR/2004/REC-xml-20040204/#NT-Char
+        // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
+        // [#x10000-#x10FFFF]
+        checkSingleValid(0x9);
+        checkSingleValid(0xA);
+        checkSingleValid(0xD);
+        checkRangeValid(0x20, 0xD7FF);
+        checkRangeValid(0xE000, 0xFFFD);
+        // not checking [0x10000, 0x10FFFF], as it goes beyond
+        // Character.MAX_VALUE
+    }
+
+    @Test
+    public void testIsFilteredInvalidChars() {
+        // Per http://www.w3.org/TR/2004/REC-xml-20040204/#NT-Char
+        // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
+        // [#x10000-#x10FFFF]
+        checkRangeInvalid(0x0, 0x8);
+        checkRangeInvalid(0xB, 0xC);
+        checkRangeInvalid(0xE, 0x1F);
+        checkRangeInvalid(0xD800, 0xDFFF);
+        checkRangeInvalid(0xFFFE, 0xFFFF);
+        // no need to check beyond #x10FFFF as this is greater than
+        // Character.MAX_VALUE
+    }
+
+    @Test
+    public void testFilter1ArgNonFiltered() {
+        NonXmlCharFilterer nonXmlCharFiltererMock = createMockBuilder(NonXmlCharFilterer.class)
+                .addMockedMethod("filter", char[].class, int.class, int.class).createStrictMock();
+        String string = "abc";
+
+        expect(nonXmlCharFiltererMock.filter(aryEq(new char[] {'a', 'b', 'c'}), eq(0), eq(3)))
+                .andReturn(false);
+        replayAll();
+
+        String result = nonXmlCharFiltererMock.filter(string);
+        verifyAll();
+
+        assertSame("Should have returned the same string if nothing was filtered", string, result);
+    }
+
+    //@Test
+    //"This test can't be build with JDK 1.5"
+    /*
+    public void testFilter1ArgFiltered() {
+        NonXmlCharFilterer nonXmlCharFiltererMock = createMockBuilder(NonXmlCharFilterer.class)
+            .addMockedMethod("filter", char[].class, int.class, int.class).createStrictMock();
+        final Capture<char[]> bufferCapture = new Capture<char[]>();
+
+        expect(
+               nonXmlCharFiltererMock.filter(and(capture(bufferCapture), aryEq(new char[] {'a', 'b', 'c'})),
+                                             eq(0), eq(3))).andAnswer(new IAnswer<Boolean>() {
+            public Boolean answer() throws Throwable {
+                char[] buffer = bufferCapture.getValue();
+                buffer[0] = 'i';
+                buffer[1] = 'o';
+                return true;
+            }
+        });
+        replayAll();
+
+        String result = nonXmlCharFiltererMock.filter("abc");
+        verifyAll();
+
+        assertEquals("Should have returned filtered string", "ioc", result);
+    }*/
+
+    @Test
+    public void testFilter1ArgNullArg() {
+        NonXmlCharFilterer nonXmlCharFiltererMock = createStrictMock(NonXmlCharFilterer.class);
+        nonXmlCharFiltererMock.filter(null);
+    }
+
+    @Test
+    public void testFilter3Args() {
+        NonXmlCharFilterer nonXmlCharFiltererMock = createMockBuilder(NonXmlCharFilterer.class)
+                .addMockedMethod("isFiltered").createStrictMock();
+        char[] buffer = new char[] {'1', '2', '3', '4', '5', '6'};
+
+        expect(nonXmlCharFiltererMock.isFiltered('3')).andReturn(true);
+        expect(nonXmlCharFiltererMock.isFiltered('4')).andReturn(false);
+        expect(nonXmlCharFiltererMock.isFiltered('5')).andReturn(true);
+        replayAll();
+
+        nonXmlCharFiltererMock.filter(buffer, 2, 3);
+        verifyAll();
+
+        assertArrayEquals("Unexpected buffer contents",
+                new char[] {'1', '2', ' ', '4', ' ', '6'}, buffer);
+    }
+
+    @Test
+    public void testFilter3ArgsNullArg() {
+        NonXmlCharFilterer nonXmlCharFiltererMock = createStrictMock(NonXmlCharFilterer.class);
+        nonXmlCharFiltererMock.filter(null, 2, 3);
+    }
+
+    private void checkSingleValid(int charCode) {
+        checkRangeValid(charCode, charCode);
+    }
+
+    private void checkRangeValid(int startCharCodeInclusive, int endCharCodeInclusive) {
+        for (int charCode = startCharCodeInclusive; charCode <= endCharCodeInclusive; charCode++) {
+            if (nonXmlCharFilterer.isFiltered((char) charCode)) {
+                fail("Character " + asHex(charCode) + " from range ["
+                        + asHex(startCharCodeInclusive) + "-" + asHex(endCharCodeInclusive)
+                        + "] should be valid, but it is not");
+            }
+
+        }
+    }
+
+    private void checkRangeInvalid(int startCharCodeInclusive, int endCharCodeInclusive) {
+        for (int charCode = startCharCodeInclusive; charCode <= endCharCodeInclusive; charCode++) {
+            if (!nonXmlCharFilterer.isFiltered((char) charCode)) {
+                fail("Character " + asHex(charCode) + " from range ["
+                        + asHex(startCharCodeInclusive) + "-" + asHex(endCharCodeInclusive)
+                        + "] should not be valid, but it is");
+            }
+        }
+    }
+
+    private String asHex(int charCode) {
+        return "#x" + Integer.toHexString(charCode);
+    }
+}

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlCharFiltererTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java?rev=897459&view=auto
==============================================================================
--- camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java (added)
+++ camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java Sat Jan  9 14:25:03 2010
@@ -0,0 +1,99 @@
+/**
+ * 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.jaxb;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.easymock.classextension.EasyMockSupport;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.anyInt;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.notNull;
+import static org.easymock.EasyMock.same;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class NonXmlFilterReaderTest extends EasyMockSupport {
+    private NonXmlFilterReader nonXmlFilterReader;
+    private NonXmlCharFilterer nonXmlCharFiltererMock;
+    private Reader readerMock;
+
+    @Before
+    public void setUp() {
+        readerMock = createStrictMock(Reader.class);
+        nonXmlCharFiltererMock = createStrictMock(NonXmlCharFilterer.class);
+        nonXmlFilterReader = new NonXmlFilterReader(readerMock);
+        nonXmlFilterReader.nonXmlCharFilterer = nonXmlCharFiltererMock;
+    }
+
+    @Test
+    public void testRead() throws IOException {
+        char[] buffer = new char[10];
+
+        expect(readerMock.read(same(buffer), eq(3), eq(5))).andDelegateTo(
+                new ConstantReader(new char[] {'a', 'b', 'c'}));
+        expect(nonXmlCharFiltererMock.filter(same(buffer), eq(3), eq(3))).andReturn(false);
+
+        replayAll();
+        int result = nonXmlFilterReader.read(buffer, 3, 5);
+        verifyAll();
+
+        assertEquals("Unexpected number of chars read", 3, result);
+        assertArrayEquals("Wrong buffer contents", new char[] {0, 0, 0, 'a', 'b', 'c', 0, 0, 0, 0},
+                buffer);
+    }
+
+    @Test
+    public void testReadEOS() throws IOException {
+        char[] buffer = new char[10];
+
+        expect(readerMock.read((char[]) notNull(), anyInt(), anyInt())).andReturn(-1);
+
+        replayAll();
+        int result = nonXmlFilterReader.read(buffer, 3, 5);
+        verifyAll();
+
+        assertEquals("Unexpected number of chars read", -1, result);
+        assertArrayEquals("Buffer should not have been affected",
+                          new char[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, buffer);
+
+    }
+
+    static class ConstantReader extends Reader {
+        private char[] constant;
+
+        public ConstantReader(char[] constant) {
+            this.constant = constant;
+        }
+
+        @Override
+        public void close() throws IOException {
+        }
+
+        @Override
+        public int read(char[] cbuf, int off, int len) throws IOException {
+            int length = Math.min(len, constant.length);
+            System.arraycopy(constant, 0, cbuf, off, length);
+            return length;
+        }
+
+    }
+}

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/converter/jaxb/NonXmlFilterReaderTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbTest.java?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbTest.java (original)
+++ camel/trunk/components/camel-jaxb/src/test/java/org/apache/camel/jaxb/CamelJaxbTest.java Sat Jan  9 14:25:03 2010
@@ -21,7 +21,7 @@
 
 import javax.xml.bind.JAXBElement;
 
-
+import org.apache.camel.CamelExecutionException;
 import org.apache.camel.Exchange;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.builder.RouteBuilder;
@@ -46,7 +46,7 @@
     }
     
     @Test
-    public void testFilteringUnmarshal() throws Exception {
+    public void testFilteringConvertorUnmarshal() throws Exception {
         final byte[] buffers = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>".getBytes("UTF-8");
         InputStream is = new ByteArrayInputStream(buffers);
         Exchange exchange = new DefaultExchange(context);
@@ -55,7 +55,58 @@
         PersonType person = converter.convertTo(PersonType.class, exchange, is);
         assertNotNull("Person should not be null ", person);
         assertEquals("Get the wrong first name ", person.getFirstName(), "FOO");
-        assertEquals("Get the wrong second name ", person.getLastName(), "BAR");
+        assertEquals("Get the wrong second name ", person.getLastName(), "BAR ");
+    }
+
+    @Test
+    public void testUnmarshalBadCharsWithFiltering() throws Exception {
+        String xml = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>";
+
+        PersonType expected = new PersonType();
+        expected.setFirstName("FOO");
+        expected.setLastName("BAR ");
+        MockEndpoint resultEndpoint = resolveMandatoryEndpoint("mock:result", MockEndpoint.class);
+        resultEndpoint.expectedBodiesReceived(expected);
+
+        template.sendBody("direct:unmarshalFilteringEnabled", xml);
+        resultEndpoint.assertIsSatisfied();
+    }
+
+    @Test(expected = CamelExecutionException.class)
+    public void testUnmarshalBadCharsNoFiltering() throws Exception {
+        String xml = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>";
+        template.sendBody("direct:getJAXBElementValue", xml);
+    }
+
+    @Test
+    public void testMarshalBadCharsWithFiltering() throws Exception {
+        PersonType person = new PersonType();
+        person.setFirstName("foo\u0004");
+        person.setLastName("bar");
+
+        MockEndpoint resultEndpoint = resolveMandatoryEndpoint("mock:result", MockEndpoint.class);
+        resultEndpoint.expectedMessageCount(1);
+        template.sendBody("direct:marshalFilteringEnabled", person);
+        resultEndpoint.assertIsSatisfied();
+
+        String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+        assertFalse("Non-xml character wasn't replaced", body.contains("\u0004"));
+    }
+
+    @Test
+    public void testMarshalBadCharsNoFiltering() throws Exception {
+        PersonType person = new PersonType();
+        person.setFirstName("foo\u0004");
+        person.setLastName("bar");
+
+        MockEndpoint resultEndpoint = resolveMandatoryEndpoint("mock:result", MockEndpoint.class);
+        resultEndpoint.expectedMessageCount(1);
+        template.sendBody("direct:marshal", person);
+        resultEndpoint.assertIsSatisfied();
+
+        String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+        assertTrue("Non-xml character unexpectedly did not get into marshalled contents", body
+                .contains("\u0004"));
     }
 
     @Test
@@ -84,13 +135,30 @@
             public void configure() throws Exception {
                 JaxbDataFormat dataFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
                 dataFormat.setIgnoreJAXBElement(false);
+
+                JaxbDataFormat filterEnabledFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
+                filterEnabledFormat.setFilterNonXmlChars(true);
+
                 from("direct:getJAXBElementValue")
                     .unmarshal(new JaxbDataFormat("org.apache.camel.foo.bar"))                        
                         .to("mock:result");
                 
                 from("direct:getJAXBElement")
                     .unmarshal(dataFormat)
-                        .to("mock:result");
+                    .to("mock:result");
+
+                from("direct:unmarshalFilteringEnabled")
+                    .unmarshal(filterEnabledFormat)
+                    .to("mock:result");
+
+                from("direct:marshal")
+                    .marshal(dataFormat)
+                    .to("mock:result");
+
+                from("direct:marshalFilteringEnabled")
+                    .marshal(filterEnabledFormat)
+                    .to("mock:result");
+
             }
         };
     }

Modified: camel/trunk/components/camel-jaxb/src/test/resources/org/apache/camel/jaxb/CamelJaxbTest.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-jaxb/src/test/resources/org/apache/camel/jaxb/CamelJaxbTest.xml?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/components/camel-jaxb/src/test/resources/org/apache/camel/jaxb/CamelJaxbTest.xml (original)
+++ camel/trunk/components/camel-jaxb/src/test/resources/org/apache/camel/jaxb/CamelJaxbTest.xml Sat Jan  9 14:25:03 2010
@@ -39,6 +39,27 @@
       </unmarshal>          
       <to uri="mock:result"/>
     </route>
+    <route>
+      <from uri="direct:marshal"/>
+      <marshal>
+        <jaxb contextPath="org.apache.camel.foo.bar"/>
+      </marshal>          
+      <to uri="mock:result"/>
+    </route>
+    <route>
+      <from uri="direct:unmarshalFilteringEnabled"/>
+      <unmarshal>
+        <jaxb filterNonXmlChars="true" contextPath="org.apache.camel.foo.bar"/>
+      </unmarshal>          
+      <to uri="mock:result"/>
+    </route>
+    <route>
+      <from uri="direct:marshalFilteringEnabled"/>
+      <marshal>
+        <jaxb filterNonXmlChars="true"  contextPath="org.apache.camel.foo.bar"/>
+      </marshal>          
+      <to uri="mock:result"/>
+    </route>
   </camelContext>
   <!-- END SNIPPET: example -->
 

Modified: camel/trunk/parent/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/parent/pom.xml?rev=897459&r1=897458&r2=897459&view=diff
==============================================================================
--- camel/trunk/parent/pom.xml (original)
+++ camel/trunk/parent/pom.xml Sat Jan  9 14:25:03 2010
@@ -73,7 +73,7 @@
     <commons-pool-version>1.4</commons-pool-version>
     <commons-dbcp-version>1.2.2</commons-dbcp-version>
     <derby-version>10.4.2.0</derby-version>
-    <easymock-version>2.4</easymock-version>
+    <easymock-version>2.5.2</easymock-version>
     <flatpack-version>3.1.1</flatpack-version>
     <freemarker-version>2.3.15</freemarker-version>
     <hamcrest-version>1.2-dev1</hamcrest-version>