diff --git a/infrastructure/src/main/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializer.java b/infrastructure/src/main/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializer.java index c42c8fd36..8ee8b5444 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializer.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializer.java @@ -8,7 +8,6 @@ import javax.xml.transform.Result; import org.springframework.batch.io.stax.ObjectToXmlSerializer; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.oxm.Marshaller; -import org.springframework.util.Assert; import org.springframework.xml.transform.StaxResult; /** diff --git a/infrastructure/src/main/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializer.java b/infrastructure/src/main/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializer.java index 9079f2559..6f025419f 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializer.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializer.java @@ -7,21 +7,21 @@ import javax.xml.stream.XMLEventReader; import org.springframework.batch.io.stax.FragmentDeserializer; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.oxm.Unmarshaller; -import org.springframework.oxm.UnmarshallingFailureException; -import org.springframework.oxm.XmlMappingException; +import org.springframework.util.Assert; import org.springframework.xml.transform.StaxSource; /** * Delegates deserializing to Spring-WS {@link Unmarshaller}. * * @author Robert Kasanicky - * @authoer Lucas Ward + * @author Lucas Ward */ public class UnmarshallingFragmentDeserializer implements FragmentDeserializer { private Unmarshaller unmarshaller; public UnmarshallingFragmentDeserializer(Unmarshaller unmarshaller){ + Assert.notNull(unmarshaller); this.unmarshaller = unmarshaller; } @@ -30,9 +30,6 @@ public class UnmarshallingFragmentDeserializer implements FragmentDeserializer { try { item = unmarshaller.unmarshal(new StaxSource(eventReader)); } - catch (XmlMappingException e) { - throw new UnmarshallingFailureException("Mapping failure during unmarshalling", e); - } catch (IOException e) { throw new DataAccessResourceFailureException("IO error during unmarshalling", e); } diff --git a/infrastructure/src/main/java/org/springframework/batch/io/stax/AbstractEventWriterWrapper.java b/infrastructure/src/main/java/org/springframework/batch/io/stax/AbstractEventWriterWrapper.java new file mode 100644 index 000000000..ddad90987 --- /dev/null +++ b/infrastructure/src/main/java/org/springframework/batch/io/stax/AbstractEventWriterWrapper.java @@ -0,0 +1,58 @@ +package org.springframework.batch.io.stax; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +/** + * Delegates all functionality to the wrapped writer allowing + * subclasses to override only the methods they want to change. + * + * @author Robert Kasanicky + */ +abstract class AbstractEventWriterWrapper implements XMLEventWriter { + + protected XMLEventWriter wrappedEventWriter; + + public AbstractEventWriterWrapper(XMLEventWriter wrappedEventWriter) { + this.wrappedEventWriter = wrappedEventWriter; + } + + public void add(XMLEvent event) throws XMLStreamException { + wrappedEventWriter.add(event); + } + + public void add(XMLEventReader reader) throws XMLStreamException { + wrappedEventWriter.add(reader); + } + + public void close() throws XMLStreamException { + wrappedEventWriter.close(); + } + + public void flush() throws XMLStreamException { + wrappedEventWriter.flush(); + } + + public NamespaceContext getNamespaceContext() { + return wrappedEventWriter.getNamespaceContext(); + } + + public String getPrefix(String uri) throws XMLStreamException { + return wrappedEventWriter.getPrefix(uri); + } + + public void setDefaultNamespace(String uri) throws XMLStreamException { + wrappedEventWriter.setDefaultNamespace(uri); + } + + public void setNamespaceContext(NamespaceContext context) throws XMLStreamException { + wrappedEventWriter.setNamespaceContext(context); + } + + public void setPrefix(String prefix, String uri) throws XMLStreamException { + wrappedEventWriter.setPrefix(prefix, uri); + } +} diff --git a/infrastructure/src/main/java/org/springframework/batch/io/stax/DefaultTransactionalEventReader.java b/infrastructure/src/main/java/org/springframework/batch/io/stax/DefaultTransactionalEventReader.java index 80fb169f1..c4bbf9531 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/stax/DefaultTransactionalEventReader.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/stax/DefaultTransactionalEventReader.java @@ -1,8 +1,9 @@ package org.springframework.batch.io.stax; +import java.util.NoSuchElementException; + import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Characters; import javax.xml.stream.events.XMLEvent; import org.springframework.beans.factory.InitializingBean; @@ -11,27 +12,26 @@ import org.springframework.util.Assert; /** * Class used to wrap XMLEventReader. Events from wrapped reader are stored in * {@link EventSequence} to support transactions. - * - * @author tomas.slanina + * + * @author Tomas Slanina + * @author Robert Kasanicky */ -class DefaultTransactionalEventReader implements TransactionalEventReader, InitializingBean { +class DefaultTransactionalEventReader extends AbstractEventReaderWrapper implements TransactionalEventReader, InitializingBean { private EventSequence recorder = new EventSequence(); - private XMLEventReader parent; - /** * Creates instance of this class and wraps XMLEventReader. - * + * * @param parent event reader to be wrapped. */ - public DefaultTransactionalEventReader(XMLEventReader parent) { - setParent(parent); + public DefaultTransactionalEventReader(XMLEventReader wrappedReader) { + super(wrappedReader); } public void afterPropertiesSet() throws Exception { - Assert.notNull(parent); + Assert.notNull(wrappedEventReader); } /** @@ -43,178 +43,54 @@ class DefaultTransactionalEventReader implements TransactionalEventReader, Initi /** * Callback on transacion commit. - * + * */ public void onCommit() { recorder.clear(); } - /** - * @return the parent - */ - public XMLEventReader getParent() { - return parent; - } - - /** - * @param parent the parent to set - */ - public void setParent(XMLEventReader parent) { - this.parent = parent; - } - - /** - * @param recorder the recorder to set - */ - public void setRecorder(EventSequence recorder) { - this.recorder = recorder; - } - - /** - * Returns the xml event recorder - * @return the xml event recorder - */ - public EventSequence getRecorder() { - return recorder; - } - - /** - * Frees any resources associated with this Reader. This method does not - * close the underlying input source. - * - * @throws XMLStreamException if there are errors freeing associated - * resources - */ - public void close() throws XMLStreamException { - parent.close(); - - } - - /** - * Reads the content of a text-only element. Precondition: the current event - * is START_ELEMENT. Postcondition: The current event is the corresponding - * END_ELEMENT. - * - * @throws XMLStreamException if the current event is not a START_ELEMENT or - * if a non text element is encountered - */ - public String getElementText() throws XMLStreamException { - StringBuffer buf = new StringBuffer(); - XMLEvent e = nextEvent(); - if (!e.isStartElement()) { - throw new XMLStreamException( - "Precondition for readText is nextEvent().getEventType() == START_ELEMENT (got " + e.getEventType() - + ")"); - } - - while (hasNext()) { - e = peek(); - if (e.isStartElement()) { - throw new XMLStreamException("Unexpected Element start"); - } - if (e.isCharacters()) { - buf.append(((Characters) e).getData()); - } - if (e.isEndElement()) { - return buf.toString(); - } - nextEvent(); - } - - throw new XMLStreamException("Unexpected end of Document"); - } - - /** - * Get the value of a feature/property from the underlying implementation - * - * @param name The name of the property - * @return The value of the property - * @throws IllegalArgumentException if the property is not supported - */ - public Object getProperty(String name) throws IllegalArgumentException { - return parent.getProperty(name); - } /** * Check if there are more events. Returns true if there are more events and * false otherwise. - * + * * @return true if the event reader has more events, false otherwise */ public boolean hasNext() { - return recorder.hasNext() || parent.hasNext(); + return recorder.hasNext() || wrappedEventReader.hasNext(); } /** * Get the next XMLEvent - * + * * @see XMLEvent * @throws XMLStreamException if there is an error with the underlying XML. * @throws NoSuchElementException iteration has no more elements. */ public XMLEvent nextEvent() throws XMLStreamException { if (!recorder.hasNext()) { - recorder.addEvent(parent.nextEvent()); + recorder.addEvent(wrappedEventReader.nextEvent()); } return recorder.nextEvent(); } - /** - * Skips any insignificant space events until a START_ELEMENT or END_ELEMENT - * is reached. If anything other than space characters are encountered, an - * exception is thrown. This method should be used when processing - * element-only content because the parser is not able to recognize - * ignorable whitespace if the DTD is missing or not interpreted. - * - * @throws XMLStreamException if anything other than space characters are - * encountered - */ - public XMLEvent nextTag() throws XMLStreamException { - while (hasNext()) { - XMLEvent e = nextEvent(); - if (e.isCharacters() && !((Characters) e).isWhiteSpace()) { - throw new XMLStreamException("Unexpected text"); - } - if (e.isStartElement() || e.isEndElement()) { - return e; - } - } - throw new XMLStreamException("Unexpected end of Document"); - } - /** * Check the next XMLEvent without reading it from the stream. Returns null * if the stream is at EOF or has no more XMLEvents. A call to peek() will * be equal to the next return of next(). - * + * * @see XMLEvent * @throws XMLStreamException */ public XMLEvent peek() throws XMLStreamException { - return (recorder.hasNext()) ? recorder.peek() : parent.peek(); + return (recorder.hasNext()) ? recorder.peek() : wrappedEventReader.peek(); } - /** - * Returns the next element in the iteration. Calling this method repeatedly - * until the {@link #hasNext()} method returns false will return each - * element in the underlying collection exactly once. - * - * @return the next element in the iteration. - * @exception NoSuchElementException iteration has no more elements. - */ - public Object next() { - try { - return nextEvent(); - } - catch (XMLStreamException e) { - return null; - } - } /** * In this implementation throws UnsupportedOperationException. */ public void remove() { - throw new java.lang.UnsupportedOperationException(); + throw new UnsupportedOperationException(); } } diff --git a/infrastructure/src/main/java/org/springframework/batch/io/stax/NoStartEndDocumentStreamWriter.java b/infrastructure/src/main/java/org/springframework/batch/io/stax/NoStartEndDocumentStreamWriter.java index a522c2291..cea4cd6d0 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/stax/NoStartEndDocumentStreamWriter.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/stax/NoStartEndDocumentStreamWriter.java @@ -1,7 +1,5 @@ package org.springframework.batch.io.stax; -import javax.xml.namespace.NamespaceContext; -import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventWriter; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; @@ -11,52 +9,17 @@ import javax.xml.stream.events.XMLEvent; * but passes through everything else. * * @author peter.zozom + * @author Robert Kasanicky */ -class NoStartEndDocumentStreamWriter implements XMLEventWriter { - - private XMLEventWriter delegate; +class NoStartEndDocumentStreamWriter extends AbstractEventWriterWrapper { - public NoStartEndDocumentStreamWriter(XMLEventWriter delegate) { - this.delegate = delegate; + public NoStartEndDocumentStreamWriter(XMLEventWriter wrappedEventWriter) { + super(wrappedEventWriter); } public void add(XMLEvent event) throws XMLStreamException { if ((!event.isStartDocument()) && (!event.isEndDocument())) { - delegate.add(event); + wrappedEventWriter.add(event); } } - - public void add(XMLEventReader reader) throws XMLStreamException { - delegate.add(reader); - } - - public void close() throws XMLStreamException { - delegate.close(); - } - - public void flush() throws XMLStreamException { - delegate.flush(); - } - - public NamespaceContext getNamespaceContext() { - return delegate.getNamespaceContext(); - } - - public String getPrefix(String uri) throws XMLStreamException { - return delegate.getPrefix(uri); - } - - public void setDefaultNamespace(String uri) throws XMLStreamException { - delegate.setDefaultNamespace(uri); - } - - public void setNamespaceContext(NamespaceContext context) - throws XMLStreamException { - delegate.setNamespaceContext(context); - } - - public void setPrefix(String prefix, String uri) throws XMLStreamException { - delegate.setPrefix(prefix, uri); - } - } diff --git a/infrastructure/src/main/java/org/springframework/batch/io/support/FileUtils.java b/infrastructure/src/main/java/org/springframework/batch/io/support/FileUtils.java index 7d8deda65..fbd5b8391 100644 --- a/infrastructure/src/main/java/org/springframework/batch/io/support/FileUtils.java +++ b/infrastructure/src/main/java/org/springframework/batch/io/support/FileUtils.java @@ -8,25 +8,28 @@ import org.springframework.util.Assert; /** * Utility methods for files used in batch processing. - * - * @author peter.zozom + * + * @author Peter Zozom */ public class FileUtils { + // forbids instantiation + private FileUtils() {} + /** - * Set up output file for batch processing. This method implements common logic for + * Set up output file for batch processing. This method implements common logic for * handling output files when starting or restarting job/step. - *
When starting output file processing, method creates/overwrites new file.
- * When restaring output file processing, method checks whether file is writable.
- *
+ * When starting output file processing, method creates/overwrites new file.
+ * When restarting output file processing, method checks whether file is writable.
+ *
* @param file file to be set up
* @param restarted TRUE signalizes that we are restarting output file processing
- * @param overwriteOutputFile If set to TRUE, output file will be overwritten
+ * @param overwriteOutputFile If set to TRUE, output file will be overwritten
* (this flag is ignored when processing is restart)
- *
+ *
* @throws IllegalArgumentException when file is NULL
- * @throws IllegalStateException when staring output file processing, file exists and
- * flag "shouldDeleteExisting" is set to FALSE
+ * @throws IllegalStateException when staring output file processing, file exists and
+ * flag "shouldDeleteExisting" is set to FALSE
* @throws DataAccessResourceFailureException when unable to create file or file is not writable
*/
public static void setUpOutputFile(File file, boolean restarted,
@@ -37,8 +40,10 @@ public class FileUtils {
try {
if (!restarted) {
if (file.exists()) {
- Assert.state(overwriteOutputFile, "File already exists: ["
- + file.getAbsolutePath() + "]");
+ if(!overwriteOutputFile){
+ throw new DataAccessResourceFailureException("File already exists: ["
+ + file.getAbsolutePath() + "]");
+ }
file.delete();
}
diff --git a/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java b/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java
index 450c73ac1..a8b60aea5 100644
--- a/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java
+++ b/infrastructure/src/test/java/org/springframework/batch/io/oxm/MarshallingObjectToXmlSerializerTests.java
@@ -61,6 +61,7 @@ public class MarshallingObjectToXmlSerializerTests extends TestCase {
mockMarshaller.setThrowException(true);
try{
xmlSerializer.serializeObject(new Object());
+ fail("Exception expected");
}catch(DataAccessResourceFailureException ex){
//expected
}
diff --git a/infrastructure/src/test/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializerTests.java b/infrastructure/src/test/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializerTests.java
new file mode 100644
index 000000000..f1a92ba36
--- /dev/null
+++ b/infrastructure/src/test/java/org/springframework/batch/io/oxm/UnmarshallingFragmentDeserializerTests.java
@@ -0,0 +1,91 @@
+package org.springframework.batch.io.oxm;
+
+import java.io.IOException;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+
+import junit.framework.TestCase;
+
+import org.easymock.MockControl;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.core.io.Resource;
+import org.springframework.dao.DataAccessException;
+import org.springframework.oxm.Unmarshaller;
+
+/**
+ * Tests for {@link UnmarshallingFragmentDeserializer}
+ *
+ * @author Robert Kasanicky
+ */
+public class UnmarshallingFragmentDeserializerTests extends TestCase {
+
+ // object under test
+ private UnmarshallingFragmentDeserializer deserializer;
+
+ private XMLEventReader eventReader;
+ private String xml = "