OPEN - issue BATCH-113: Mouldy xml class names still in infrastructure

http://opensource.atlassian.com/projects/spring/browse/BATCH-113
This commit is contained in:
lucasward
2007-09-26 15:16:54 +00:00
parent 363631c629
commit 6b4294f503
34 changed files with 0 additions and 7235 deletions

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.IOException;
import org.springframework.batch.io.xml.xstream.XStreamFactory;
/**
* The <code>ObjectInput</code> interface provides method for reading objects
* from input stream and also provides methods for manipulating input stream.
* @author peter.zozom
* @see XStreamFactory.ObjectInputWrapper
*/
public interface ObjectInput {
/**
* Enables input stream postprocess after reading from the stream has been
* restarted.
* @param data
*/
public void afterRestart(Object data);
/**
* Read and return an object. The class that implements this interface
* defines where the object is "read" from.
*
* @return the object read from the stream
* @exception java.lang.ClassNotFoundException If the class of a serialized
* object cannot be found.
* @exception IOException If any of the usual Input/Output related
* exceptions occur.
*/
public Object readObject() throws ClassNotFoundException, IOException;
/**
* Closes the input stream. Must be called to release any resources
* associated with the stream.
*/
public void close();
/**
* Get actual position in the input stream.
* @return actual position in the input stream
*/
public long position();
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import org.springframework.core.io.Resource;
/**
* ObjectInputFactory creates instance of <code>ObjectInput</code>.
* Implementation should be thread-safe.
* @author peter.zozom
*/
public interface ObjectInputFactory {
/**
* Creates instance of {@link ObjectInput}
* @return ObjectInput
*/
public ObjectInput createObjectInput(Resource resource, String encoding);
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.IOException;
import org.springframework.batch.io.xml.xstream.XStreamFactory;
/**
* The <code>ObjectOutput</code> interface provides methods for writing
* objects to output stream and also provides methods for manipulating output
* stream (such as flush, position, truncate, etc.).
* @author peter.zozom
* @see XStreamFactory.ObjectOutputWrapper
*/
public interface ObjectOutput {
/**
* Enables output stream postprocess after writing to the stream has been
* restarted.
* @param data
*/
public void afterRestart(Object data);
/**
* Write an object to the stream. The class that implements this interface
* defines how the object is written.
*
* @param obj the object to be written
* @exception IOException Any of the usual Input/Output related exceptions.
*/
public void writeObject(Object obj) throws IOException;
/**
* Closes the stream. This method must be called to release any resources
* associated with the stream.
*/
public void close();
/**
* Flushes the stream. This will write any buffered output bytes.
*/
public void flush();
/**
* Get actual position in the output stream.
* @return actual position in the output stream
*/
public long position();
/**
* Set a new position in the output stream.
* @param newPosition the new position, a non-negative integer counting the
* number of bytes from the beginning of the file
*/
public void position(long newPosition);
/**
* Truncates the otput file to the given size.
* @param size the new size, a non-negative byte count
*/
public void truncate(long size);
/**
* Returns the current size of the output file
* @return The current size of the output file, measured in bytes
*/
public long size();
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import org.springframework.core.io.Resource;
/**
* ObjectOutputFactory creates instance of <code>ObjectOutput</code>.
* Implementation should be thread-safe.
* @author peter.zozom
*/
public interface ObjectOutputFactory {
/**
* Creates instance of {@link ObjectOutput}
* @return
*/
public ObjectOutput createObjectOutput(Resource resource, String encoding);
}

View File

@@ -1,198 +0,0 @@
package org.springframework.batch.io.xml;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.xml.transform.StaxSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* Unmarshaller adapter allows to use {@link org.springframework.oxm.Unmarshaller} for
* iterative XML record processing.
*
* {@link org.springframework.oxm.Unmarshaller} always processes whole XML
* input at once, but we need to process only one record per one module
* iteration (or per one call of the read() method).
*
* Solution is to cut XML in smaller pieces (each piece contains single record) and call
* the unmarshaller to process only this single piece (record).
*
*/
class UnmarshallerAdapter {
private static final Log log = LogFactory.getLog(UnmarshallerAdapter.class);
private FileChannel fc;
private String encoding;
//original unmarshaller - processes only pieces of XML passed from wrapper
private Unmarshaller u;
//regex matcher - used to cut XML piece holding one record
private final Matcher matcher;
private SourceFactory factory;
/* ***** Constructor ***** */
/**
* @param originalUnmarshaller unmarshaller to be wrapped
*/
public UnmarshallerAdapter(Unmarshaller originalUnmarshaller, String recordElementName, FileChannel fc,
String encoding, boolean useSaxParser) {
this.u = originalUnmarshaller;
this.fc = fc;
this.encoding = encoding;
this.matcher = getMatcher(recordElementName);
this.factory = getSourceFactory(useSaxParser);
}
/**
* Unmarshal next record.
* @see org.springframework.oxm.Unmarshaller#unmarshal(javax.xml.transform.Source)
*/
public Object unmarshal() throws XmlMappingException, IOException {
Object result = null;
String record = readNextRecord();
if (record != null) {
result = u.unmarshal(factory.getSource(record));
}
return result;
}
/**
* Read next piece of XML.
* @return xml string holding one record
*/
private String readNextRecord() {
String result = null;
if (matcher.find()) {
result = matcher.group();
}
if (result != null) {
try {
fc.position(matcher.end());
} catch (IOException e) {
throw new IllegalStateException("Error while adjusting filechannel position");
}
}
return result;
}
/* ***** Private helper methods ***** */
/**
* Get regex matcher, which cuts XML to pieces
* @param elemName name of the element that represents one record
* @return the matcher
*/
private Matcher getMatcher(String elemName) {
CharSequence cs = null;
try {
// Create a read-only CharBuffer on the file
ByteBuffer bbuf = fc.map(FileChannel.MapMode.READ_ONLY, fc.position(), fc.size() - fc.position());
cs = Charset.forName(encoding).newDecoder().decode(bbuf);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to get input stream", ioe);
}
String prefix = (elemName.indexOf(':') < 0) ? "(?:[^:]*?:)?" : "";
String re = "<" + prefix + elemName + "[^/>]*?/>|<" + prefix + elemName + "[\\s>][\\S\\s]*?</" + prefix
+ elemName + ">";
return Pattern.compile(re, Pattern.MULTILINE).matcher(cs);
}
/**
* Get SourceFactory which will create SAX or StAX source (based on useSaxParser flag)
* @param useSaxParser
*/
private SourceFactory getSourceFactory(boolean useSaxParser) {
SourceFactory sf;
if (useSaxParser) {
sf = new SourceFactory() {
public Source getSource(String xml) {
Source source = null;
Reader r = new StringReader(xml);
try {
XMLReader reader;
try {
reader = XMLReaderFactory.createXMLReader();
}
catch (SAXException se) {
reader = XMLReaderFactory.createXMLReader("org.apache.crimson.parser.XMLReaderImpl");
}
source = new SAXSource(reader, new org.xml.sax.InputSource(r));
}
catch (SAXException se) {
log.error(se);
throw new DataAccessResourceFailureException("Unable to get XML reader", se);
}
return source;
}
};
}
else {
sf = new SourceFactory() {
public Source getSource(String xml) {
XMLInputFactory xsf = XMLInputFactory.newInstance();
Source source = null;
try {
Reader r = new StringReader(xml);
source = new StaxSource(xsf.createXMLStreamReader(r));
}
catch (XMLStreamException xse) {
log.error(xse);
throw new DataAccessResourceFailureException("Unable to get XML reader", xse);
}
return source;
}
};
}
return sf;
}
private interface SourceFactory {
public Source getSource(String xml);
}
}

View File

@@ -1,79 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX error handler implementation. This implementation only logs warnings and
* errors and re-throws exceptions.
*
* @author peter.zozom
*/
public class XmlErrorHandler extends DefaultHandler {
private static final Log log = LogFactory.getLog(XmlErrorHandler.class);
/**
* @param e parsing exception
* @throws SAXException re-thrown exception
* @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
*/
public void warning(SAXParseException e) throws SAXException {
log.debug("Warning: \n" + printInfo(e));
throw new SAXException(e);
}
/**
* @param e parsing exception
* @throws SAXException re-thrown exception
* @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
*/
public void error(SAXParseException e) throws SAXException {
log.debug("Warning: \n" + printInfo(e));
throw new SAXException(e);
}
/**
* @param e parsing exception
* @throws SAXException re-thrown exception
* @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
*/
public void fatalError(SAXParseException e) throws SAXException {
log.debug("Warning: \n" + printInfo(e));
throw new SAXException(e);
}
private String printInfo(SAXParseException e) {
StringBuffer sb = new StringBuffer();
sb.append(" Public ID: \n");
sb.append(e.getPublicId());
sb.append(" System ID: \n");
sb.append(e.getSystemId());
sb.append(" Line number: \n");
sb.append(e.getLineNumber());
sb.append(" Column number: \n");
sb.append(e.getColumnNumber());
sb.append(" Message: \n");
sb.append(e.getMessage());
return sb.toString();
}
}

View File

@@ -1,489 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.io.InputSource;
import org.springframework.batch.io.Skippable;
import org.springframework.batch.io.exception.BatchCriticalException;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
import org.springframework.batch.restart.Restartable;
import org.springframework.batch.statistics.StatisticsProvider;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.util.Assert;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* XmlInputTemplate is implementation of {@link InputSource} which
* processes XML input independently of technologies used for parsing XML files
* and mapping XML to value objects. It has references only to interfaces, not
* concrete implementations. It uses {@link ObjectInputFactory} interface for
* getting {@link ObjectInput}, which is interface for retrieving value objects
* from the input stream. So it's easy to plug-in any technology for parsing XML
* and mapping it to value object by implementing these interfaces. See
* implementation of {@link ObjectInputFactory} interface, which uses StAX
* as XML parser and XStream as XML-to-ValueObjects mapper.
* <p>
* Current implementation also allows validation of XML file against XSD schema.
* This validation is realized by using SAXParser. Validation of the whole XML
* file is performed in the {@link #open()} method, because SAXParser does not
* allow to process only part of the XML, then stop and continue later with
* processing. This type of processing can be realized by using any pull-parser
* (e.g. StAX), but StAX API does not provide methods for validation. So be
* careful when using this validation, because it means to parse XML twice: once
* to validate and once to read and map. Validation can be turned on/off by
* {@link #setValidating(boolean)} method. By default is validation turned off.<br/>
* This validation should be refactored in future. Validation should be provided
* either by {@link ObjectInput} or some new interface.
* <p>
* This input template also provides restart, skip, statistics and transaction
* features by implementing corresponding interfaces.
*
* @author peter.zozom
* @see ObjectInput
* @see ObjectInputFactory
*/
public class XmlInputSource implements InputSource, Skippable, Restartable,
TransactionSynchronization, StatisticsProvider, InitializingBean, DisposableBean {
private static final Log log = LogFactory.getLog(XmlInputSource.class);
private static final String DEFAULT_ENCODING = "UTF-8";
/*
* Unique source name used to construct this xml reader input source -
* specified by the configuration file.
*/
private String sourceName = null;
private Resource resource;
private ObjectInputFactory inputFactory;
private boolean validating = false;
private String encoding = DEFAULT_ENCODING;
private Properties statistics = new Properties();
public static final String READ_STATISTICS_NAME = "Read";
public static final String RESTART_DATA_NAME = "xmlinputtemplate.currentRecordCount";
private InputState state = new InputState();
// accessor method for the threadlocal state object
private InputState getState() {
return (InputState) state;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(resource);
Assert.state(resource.exists(), "Input resource does not exist: ["+resource+"]");
}
/**
* Setter for input resource.
*
* @param resource
*/
public void setResource(Resource resource) {
this.resource = resource;
}
/**
* Return current status of the validation flag
*
* @return
*/
public boolean isValidating() {
return validating;
}
/**
* Turn validation on/off for the input source
*
* @param validating
*/
public void setValidating(boolean validating) {
this.validating = validating;
}
/**
* Initialize the input source and validates input XML file if validation is
* turned on. This method should be called for each thread using same
* XmlInputTemplate instance.
*
* @see org.springframework.batch.item.ResourceLifecycle#open()
*/
public void open() {
InputState is = getState();
if (!is.initialized) {
registerSynchronization();
initializeObjectInput();
}
}
/**
* Registers object for transaction synchronization
*/
protected void registerSynchronization() {
BatchTransactionSynchronizationManager.registerSynchronization(this);
}
/**
* Close the input source
*
* @see org.springframework.batch.item.ResourceLifecycle#close()
*/
public void close() {
InputState is = getState();
is.objectInput.close();
is.initialized = false;
}
/**
* Calls close to ensure that bean factories can close and always release
* resources.
*
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
close();
}
/*
* Initializes and obtains the ObjectInput from the ObjectInputFactory and
* validates input XML file if validation is turned on.
*/
private void initializeObjectInput() {
InputState is = getState();
is.initialized = false;
if (isValidating()) {
validateInputFile(resource);
}
is.objectInput = inputFactory.createObjectInput(resource, getEncoding());
is.lastCommitPoint = is.objectInput.position();
is.initialized = true;
}
/*
* Validates input xml file against XSD schema.
*
* @param file File to be validated
*/
private void validateInputFile(Resource resource) {
try {
SAXParserFactory factory = getSaxFactory();
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setFeature("http://apache.org/xml/features/validation/schema", true);
SAXParser parser = factory.newSAXParser();
DefaultHandler handler = getDefaultHandler();
parser.parse(resource.getInputStream(), handler, resource.getURL().toExternalForm());
}
catch (ParserConfigurationException pce) {
log.error(pce);
throw new BatchEnvironmentException("Unable to configure parser.", pce);
}
catch (SAXException se) {
log.error(se);
throw new BatchEnvironmentException("Error during parsing the input file.", se);
}
catch (IOException ioe) {
log.error(ioe);
throw new BatchEnvironmentException("Error reading input file.", ioe);
}
}
/*
* Get default handler for xml validation
*
* @return instance of DefaultHandler
*/
private DefaultHandler getDefaultHandler() {
return new XmlErrorHandler();
}
/*
* Creates instance of SAXParserFactory
*
* @return instance of SAXParserFactory @throws FactoryConfigurationError
*/
protected SAXParserFactory getSaxFactory() throws FactoryConfigurationError {
SAXParserFactory factory = SAXParserFactory.newInstance();
return factory;
}
/**
* Return the next record from the input file and map it to a value object.
*
* @return next record if found or <code>null</code> to signal the end of
* the input data.
* @see org.springframework.batch.io.InputSource
*/
public Object read() {
InputState is = getState();
if (!is.initialized) {
open();
}
Object result = null;
do {
result = readNextRecord();
is.currentRecordCount++;
} while (is.skipLines.contains(new Integer(is.currentRecordCount)));
return result;
}
/*
* Reads next record
*
* @return next record
*/
private Object readNextRecord() {
InputState is = getState();
Object result;
try {
result = is.objectInput.readObject();
}
catch (EOFException eofe) {
log.debug("Parsing of XML finished");
result = null;
}
catch (IOException ioe) {
log.error(ioe);
throw new BatchCriticalException("Unable to read from ObjectInputStream", ioe);
}
catch (ClassNotFoundException cnfe) {
log.error(cnfe);
throw new BatchEnvironmentException("Bad xml mapping", cnfe);
}
return result;
}
/**
* Postprocess after transaction commit/rollback. Called from transaction
* manager.
*
* @param status indicates whether it was a rollback or commit
*/
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
transactionComitted();
}
else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {
transactionRolledback();
}
}
/*
* Postprocess after transaction commit
*/
private void transactionComitted() {
InputState is = getState();
is.skipLines = new ArrayList();
is.lastCommitPoint = is.objectInput.position();
}
/*
* Postprocess after transaction rollback
*/
private void transactionRolledback() {
InputState is = getState();
is.currentRecordCount = 0;
// remember list of skipped lines and last commit point
List sl = is.skipLines;
long cp = is.lastCommitPoint;
// XMLStreamReader is forward only, so we need to start from beginnig
close();
// this will also reset skipLines
open();
// so after init get new InputState and set skipLines and
// lastCommitPoint
is = getState();
is.skipLines = sl;
is.lastCommitPoint = cp;
long currentLocation = is.objectInput.position();
while (currentLocation < is.lastCommitPoint) {
readNextRecord();
is.currentRecordCount++;
currentLocation = is.objectInput.position();
}
}
/**
* Returns name of the input source.
*
* @return input source name
*/
public String getName() {
return sourceName;
}
/**
* Sets name of the input source.
*
*/
public void setName(String newName) {
this.sourceName = newName;
}
/**
* This method returns the restart data for the input source. It returns the
* current record count which can be used to re-initialze the batch job in
* case of restart.
*
* @see org.springframework.batch.container.Restartable#getRestartData()
*/
public RestartData getRestartData() {
Properties restartData = new Properties();
restartData.setProperty(RESTART_DATA_NAME, String.valueOf(getState().currentRecordCount));
return new GenericRestartData(restartData);
}
/**
* This method initializes the input source for restart. It opens the input
* file and position the xml reader according to information provided by the
* restart data.
*
* @param restartData restart data information
* @see org.springframework.batch.container.Restartable#initForRestart(java.lang.Object)
*/
public void restoreFrom(RestartData restartData) {
if (restartData == null || restartData.getProperties() == null ||
restartData.getProperties().getProperty(RESTART_DATA_NAME) == null) {
return;
}
InputState is = getState();
int startAtRecord = Integer.parseInt(restartData.getProperties().getProperty(RESTART_DATA_NAME));
for (int i = 0; i < startAtRecord; i++) {
readNextRecord();
}
is.currentRecordCount = startAtRecord;
}
/**
* Skip the current record.
* @see org.springframework.batch.container.advice.SkipAdvice#skip()
*/
public void skip() {
InputState is = getState();
is.skipLines.add(new Integer(is.currentRecordCount));
}
/**
* Get encoding.
* @return the character encoding of the stream
*/
public String getEncoding() {
return encoding;
}
/**
* Set encoding.
* @param encoding the character encoding of the stream
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* Get statistics for the processed input.
* @return actual statistics for the processed input
* @see org.springframework.batch.container.advice.StatisticsAdvice#getStatistics()
*/
public Properties getStatistics() {
statistics.setProperty(READ_STATISTICS_NAME, String.valueOf(getState().currentRecordCount));
return statistics;
}
/**
* Set the ObjectInputFactory which is used for retrieving ObjectInput
* @param inputFactory the factory to use
*/
public void setInputFactory(ObjectInputFactory inputFactory) {
this.inputFactory = inputFactory;
}
/* *** Intentionally unimplemented methods *** */
public void suspend() {
}
public void resume() {
}
public void beforeCommit(boolean arg0) {
}
public void beforeCompletion() {
}
public void afterCommit() {
}
/**
* Value object holding state of the input source.
*/
private static class InputState {
boolean initialized = false;
int currentRecordCount = 0;
ObjectInput objectInput;
List skipLines = new ArrayList();
long lastCommitPoint;
}
}

View File

@@ -1,397 +0,0 @@
package org.springframework.batch.io.xml;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.io.InputSource;
import org.springframework.batch.io.Skippable;
import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
import org.springframework.batch.restart.Restartable;
import org.springframework.batch.statistics.StatisticsProvider;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.oxm.Unmarshaller;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.util.Assert;
/**
* <p>XmlInputSource2 is {@link InputSource} implementation which processes XML input file
* and maps XML elements to objects. It uses {@link org.springframework.oxm.Unmarshaller}
* for parsing XML and for OXM mapping. This allows to plug-in various OXM frameworks.
* Spring-ws' OXM package provides implementations for Castor, JAXB, JiBX,
* XmlBeans and XStream.</p>
*
* <p>{@link org.springframework.oxm.Unmarshaller} always processes whole XML
* input at once, but we need to process only one record per one module
* iteration. Therefore XmlInputSource2 uses {@link UnmarshallerAdapter} which cuts XML
* into smaller pieces (each piece contains a single record) and calls the unmarshaller
* to process only this single piece (record).</p>
*
* <p><b>XmlInputSource2 configuration</b></p>
* <p>Mandatory bean properties:
* <ul>
* <li><i>resource</i> - resource pointing to XML input file. Currently, only
* {@link FileSystemResource} is supported.</li>
* <li><i>unmarshaller</i> - any implementation of the {@link Unmarshaller}</li>
* <li><i>recordElementName</i> - name of the XML element which represents single record</li>
* </ul>
* </p>
* <p>Optional bean properties (if not set, default value is used):
* <ul>
* <li><i>encoding</i> - input file encoding (default value is UTF-8)</li>
* <li><i>useSaxParser</i> - TRUE forces unmarshaller to use SAX parser instead StAX parser.
* This can be used for performance optimization. Performance of SAX and StAX can vary
* depending on OXM framework used and XML record size. Default value is FALSE</li>
* </ul>
* </p>
*
* <p>Limitations:
* <ul>
* <li>processing of nested records is not supported:</li>
* <pre> &lt;folder&gt;
* &lt;folder&gt;&lt;/folder&gt; &lt;- this is not supported
* &lt;file&gt;&lt;/file&gt;
* &lt;/folder&gt;
* &lt;folder&gt;
* &lt;file&gt;&lt;/file&gt;
* &lt;/folder&gt;</pre>
* <li>References (idref) in XML are not supported</li>
* <li>Validation against XSD schema is not implemented</li>
* </ul>
* </p>
*
* @see org.springframework.oxm.Unmarshaller
* @see org.springframework.batch.io.xml.UnmarshallerAdapter
* @author Peter Zozom
*/
public class XmlInputSource2 implements InputSource, Skippable, Restartable, StatisticsProvider, InitializingBean,
DisposableBean {
//logger
private static final Log log = LogFactory.getLog(XmlInputSource2.class);
//default encoding
private static final String DEFAULT_ENCODING = "UTF-8";
//restart data property name
private static final String RESTART_DATA_NAME = "staxinputsource.position";
//read statistics property name
public static final String READ_STATISTICS_NAME = "Read";
//file system resource
private Resource resource;
//xml unmarshaller (Castor, JAXB, JiBX, XmlBeans or XStream)
private Unmarshaller unmarshaller;
//unmarshaller adapter
private UnmarshallerAdapter unmarshallerAdapter;
//file channel associated with Resource
private FileChannel fc;
//encoding to be used while reading from the resource
private String encoding = DEFAULT_ENCODING;
//name of the element which represents record
private String recordElementName;
//force to use SAX parser. By default StAX parser is used.
private boolean useSaxParser = false;
//signalizes that input source has been initialized
private boolean initialized = false;
//transaction synchronization object
private TransactionSynchronization synchronization = new XmlInputSource2TransactionSychronization();
//current count of processed records
private long currentRecordCount = 0;
//file channel position at last commit point
private long lastCommitPointPosition = 0;
//count of processed records at last commit point
private long lastCommitPointRecordCount = 0;
//list of skipped record numbers
private List skipRecords = new ArrayList();
//statistics
private Properties statistics = new Properties();
/**
* Set the encoding to be used while reading from the Resource
* @param encoding the encoding to be used
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* Set the resource to be read from. Currently is only {@link FileSystemResource} supported.
* @param resource the Resource to be read from
*/
public void setResource(Resource resource) {
this.resource = resource;
}
/**
* Set the {@link Unmarshaller} implementation to be used for Object XML mapping (e.g. JAXB, JiBX, XmlBeans...).
* @see org.springframework.oxm.Unmarshaller
* @param unmarshaller the OXM unmarshaller
*/
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
/**
* Set the name of the element which represents the record.
* @param elementName the element name
*/
public void setRecordElementName(String elementName) {
this.recordElementName = elementName;
}
/**
* Force to use SAX parser instead of StAX parser.
* @param useSaxParser if true SAX parser will be used, else StAX parser will be used
*/
public void setUseSaxParser(boolean useSaxParser) {
this.useSaxParser = useSaxParser;
}
/**
* Verifies bean configuration. Resource, Unmarshaller and record element name are mandatory.
* @throws Exception
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(resource);
Assert.state(resource.exists(), "Input resource does not exist: [" + resource + "]");
Assert.notNull(unmarshaller);
Assert.hasLength(recordElementName);
}
/**
* @throws Exception
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
close();
}
/**
* Registers the input source for transaction synchronization.
*/
private void registerSynchronization() {
BatchTransactionSynchronizationManager.registerSynchronization(synchronization);
}
/**
* Opens the input source.
* @see org.springframework.batch.item.ResourceLifecycle#open()
*/
public void open() {
registerSynchronization();
try {
InputStream is = resource.getInputStream();
if (is instanceof FileInputStream) {
fc = ((FileInputStream) is).getChannel();
}
else {
throw new IllegalArgumentException("Only file input stream is supported");
}
this.unmarshallerAdapter = new UnmarshallerAdapter(unmarshaller, recordElementName, fc, encoding,
useSaxParser);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to get input stream", ioe);
}
initialized = true;
}
/**
* Closes the input source.
* @see org.springframework.batch.item.ResourceLifecycle#close()
*/
public void close() {
initialized = false;
try {
fc.close();
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to close input Source", ioe);
}
}
/**
* Read object from the input.
* @return
* @see org.springframework.batch.io.InputSource#read()
*/
public Object read() {
if (!initialized) {
open();
}
Object o;
do {
currentRecordCount++;
try {
o = unmarshallerAdapter.unmarshal();
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to close XML Input Source", ioe);
}
} while (skipRecords.contains(new Long(currentRecordCount)));
return o;
}
/**
* Mark current record to be skipped.
* @see org.springframework.batch.io.Skippable#skip()
*/
public void skip() {
skipRecords.add(new Long(currentRecordCount));
}
/**
* @return
* @see org.springframework.batch.restart.Restartable#getRestartData()
*/
public RestartData getRestartData() {
Properties restartData = new Properties();
restartData.setProperty(RESTART_DATA_NAME, String.valueOf(getPosition()));
return new GenericRestartData(restartData);
}
/**
* Get current file position.
* @return file position
*/
private long getPosition() {
long pos = 0;
try {
pos = fc.position();
}
catch (IOException ioe) {
throw new DataAccessResourceFailureException("Unable to get file position", ioe);
}
return pos;
}
/**
* @param data
* @see org.springframework.batch.restart.Restartable#restoreFrom(org.springframework.batch.restart.RestartData)
*/
public void restoreFrom(RestartData data) {
if (data == null || data.getProperties() == null || data.getProperties().getProperty(RESTART_DATA_NAME) == null) {
return;
}
if (!initialized) {
open();
}
long startAtPosition = Long.parseLong(data.getProperties().getProperty(RESTART_DATA_NAME));
setPosition(startAtPosition);
this.unmarshallerAdapter = new UnmarshallerAdapter(unmarshaller, recordElementName, fc, encoding, useSaxParser);
}
/**
* @param startAtPosition
*/
private void setPosition(long position) {
try {
fc.position(position);
}
catch (IOException ioe) {
throw new DataAccessResourceFailureException("Unable to set file position", ioe);
}
}
/**
* @return
* @see org.springframework.batch.statistics.StatisticsProvider#getStatistics()
*/
public Properties getStatistics() {
statistics.setProperty(READ_STATISTICS_NAME, String.valueOf(currentRecordCount));
return statistics;
}
/**
* Encapsulates transaction events for the XmlInputSource2.
*/
private class XmlInputSource2TransactionSychronization extends TransactionSynchronizationAdapter {
/**
* @param status
* @see org.springframework.transaction.support.TransactionSynchronizationAdapter#afterCompletion(int)
*/
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
transactionComitted();
}
else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {
transactionRolledback();
}
}
private void transactionComitted() {
lastCommitPointPosition = getPosition();
lastCommitPointRecordCount = currentRecordCount;
skipRecords = new ArrayList();
}
private void transactionRolledback() {
currentRecordCount = lastCommitPointRecordCount;
setPosition(lastCommitPointPosition);
unmarshallerAdapter = new UnmarshallerAdapter(unmarshaller, recordElementName, fc, encoding, useSaxParser);
}
}
//package visibility method necessary to simulate transaction events in tests
TransactionSynchronization getSynchronization() {
return synchronization;
}
}

View File

@@ -1,408 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.io.OutputSource;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
import org.springframework.batch.restart.Restartable;
import org.springframework.batch.statistics.StatisticsProvider;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.util.Assert;
/**
* XmlOutputTemplate is implementation of {@link OutputSource} which processes
* XML output independently of technologies used for serializing value objects
* to XML files. It has references only to interfaces, not concrete
* implementations. It uses {@link ObjectOutputFactory} interface for getting
* {@link ObjectOutput}, which is interface for writing value objects to the
* output stream. So it's easy to plug-in any technology for serializing value
* objects to XML files by implementing these interfaces. See implementations of
* {@link ObjectOutputFactory} interface.
* <p>
* This output template also provides restart, statistics and transaction
* features by implementing corresponding 'advice' interfaces.
*
* @author peter.zozom
* @see ObjectOutput
* @see ObjectOutputFactory
*/
public class XmlOutputSource implements OutputSource, Restartable, StatisticsProvider, TransactionSynchronization,
DisposableBean {
private static final Log log = LogFactory.getLog(XmlOutputSource.class);
private static final String DEFAULT_ENCODING = "UTF-8";
private ObjectOutputFactory outputFactory;
private String encoding = DEFAULT_ENCODING;
private Resource resource;
private Properties statistics = new Properties();
/*
* Unique source name used to construct this xml reader input source -
* specified by the configuration file.
*/
private String sourceName = null;
public static final String WRITTEN_STATISTICS_NAME = "Written";
public static final String RESTART_DATA_NAME = "xmloutputtemplate.currentRecordCount";
private OutputState state;
// Accessor method for the state object
private OutputState getState() {
if (state == null) {
state = new OutputState();
}
return state;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(resource);
Assert.state(resource.getFile().canWrite(), "Resource is not writable");
}
/**
* Setter for resource. Represents a file that can be written.
*
* @param resource
*/
public void setResource(Resource resource) {
this.resource = resource;
}
/**
* Initialize the output source. This method should be called for each
* thread using same XmlOutputTemplate instance.
*
* @see org.springframework.batch.item.ResourceLifecycle#open()
*/
public void open() {
OutputState os = getState();
if (!os.initialized) {
}
}
/**
* Registers object for transaction synchronization
*/
protected void registerSynchronization() {
BatchTransactionSynchronizationManager.registerSynchronization(this);
}
/**
* Just calls {@link #close()} so that bean factories will clean up
* resources correctly.
*
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
close();
}
/**
* Close the output source
*
* @see org.springframework.batch.item.ResourceLifecycle#close()
*/
public void close() {
OutputState os = getState();
try {
if (os != null && os.objectOutput != null) {
os.objectOutput.close();
}
}
finally {
if (os != null) {
os.initialized = false;
os.restarted = false;
}
}
}
/*
* Initializes and obtains a ObjectOutput from ObjectOutputFactory.
*/
private void initializeXmlWriter() {
OutputState os = getState();
os.initialized = false;
File file;
try {
file = resource.getFile();
// If the output source was restarted, keep existing file.
// If the output source was not restarted, check following:
// - if the file should be deleted, delete it if it was exiting and
// create blank file,
// - if the file should not be deleted, if it already exists, throw
// an exception,
// - if the file was not existing, create new.
if (!os.restarted) {
if (file.exists()) {
if (os.shouldDeleteIfExists) {
file.delete();
}
else {
throw new BatchEnvironmentException("Resource already exists: " + resource);
}
}
file.createNewFile();
}
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to write to file resource: [" + resource + "]", ioe);
}
os.objectOutput = outputFactory.createObjectOutput(resource, encoding);
if (os.restarted) {
os.objectOutput.afterRestart(new Long(os.lastMarkedByteOffsetPosition));
checkFileSize();
}
os.initialized = true;
}
/**
* Write the value object to output xml stream.
* @param output the value object
* @see org.springframework.batch.io.OutputSource#write(java.lang.Object)
*/
public void write(Object output) {
OutputState os = getState();
if (!os.initialized) {
open();
initializeXmlWriter();
}
try {
os.objectOutput.writeObject(output);
os.objectsWritten++;
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to write to ObjectOutputStream", ioe);
}
}
/**
* Return the name of the output source.
*/
public void setName(String newName) {
this.sourceName = newName;
}
/**
* Set the name of the output source.
*
* @see org.springframework.batch.restart.Restartable#getName()
*/
public String getName() {
return sourceName;
}
/**
* Postprocess after transaction commit/rollback. Called from transaction
* manager.
*
* @param status indicates whether it was a rollback or commit
*/
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
transactionComitted();
}
else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {
transactionRolledback();
}
}
/*
* Postprocess after transaction commit
*/
private void transactionComitted() {
OutputState os = getState();
os.objectOutput.flush();
os.lastMarkedByteOffsetPosition = this.position();
}
/*
* Postprocess after transaction rollback
*/
private void transactionRolledback() {
checkFileSize();
resetPositionForRestart();
}
/*
* This method removes any information in the file before this reset point.
*
* @param resetByteOffset a long integer representing the byte offset to
* trunction and reposition the file cursor to for restarting.
*/
private void resetPositionForRestart() {
OutputState os = getState();
os.objectOutput.truncate(os.lastMarkedByteOffsetPosition);
os.objectOutput.position(os.lastMarkedByteOffsetPosition);
}
/*
* Checks (on setState) to make sure that the current output file's size is
* not smaller than the last saved commit point. If it is, then the file has
* been damaged in some way and whole task must be started over again from
* the beginning.
*/
private void checkFileSize() {
OutputState os = getState();
long size = -1;
size = os.objectOutput.size();
Assert.state(size >= os.lastMarkedByteOffsetPosition, "Current file size is smaller than size at last commit");
}
/*
* Return the byte offset position of the cursor in the output file as a
* long integer.
*
* @return long integer representing the byte offset position of the cursor
* in the output file.
*/
private long position() {
OutputState os = getState();
return os.objectOutput.position();
}
/**
* Get statistics for the processed output.
* @return actual statistics for the processed output
* @see org.springframework.batch.container.advice.StatisticsAdvice#getStatistics()
*/
public Properties getStatistics() {
statistics.setProperty(WRITTEN_STATISTICS_NAME, new Long(getState().objectsWritten).toString());
return statistics;
}
/**
* Set encoding.
* @param encoding the character encoding of the stream
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* Set the ObjectOutputFactory which is used for retrieving ObjectOutput
* @param outputFactory the factory to use
*/
public void setOutputFactory(ObjectOutputFactory outputFactory) {
this.outputFactory = outputFactory;
}
/* *** Intentionally unimplemented methods *** */
public void suspend() {
}
public void resume() {
}
public void beforeCommit(boolean arg0) {
}
public void beforeCompletion() {
}
public void afterCommit() {
}
/*
* Value object holding state of the output source.
*/
private static class OutputState {
private boolean initialized = false;
private ObjectOutput objectOutput;
private long lastMarkedByteOffsetPosition = 0;
private long objectsWritten = 0;
private boolean shouldDeleteIfExists = true;
private boolean restarted = false;
}
public void restoreFrom(RestartData data) {
if (data == null || data.getProperties() == null ||
data.getProperties().getProperty(RESTART_DATA_NAME) == null) {
return;
}
OutputState os = getState();
os.lastMarkedByteOffsetPosition = Long.parseLong(data.getProperties().getProperty(RESTART_DATA_NAME));
os.restarted = true;
initializeXmlWriter();
}
/**
* This method returns the restart data for the output source. It returns
* the current byte offset position of the cursor in the output file which
* can be used to re-initialze the batch job in case of restart.
*
* @see org.springframework.batch.container.Restartable#getRestartData()
*/
public RestartData getRestartData() {
Properties restartData = new Properties();
restartData.setProperty(RESTART_DATA_NAME, new Long(position()).toString());
return new GenericRestartData(restartData);
}
/**
* This method initializes the output source for restart. It opens the
* output file and position the xml writer according to information provided
* by the restart data.
*
* @param restartData restart data information
* @see org.springframework.batch.container.advice.RestartAdvice#initForRestart(java.lang.Object)
*/
public void initForRestart(Object restartData) {
}
}

View File

@@ -1,7 +0,0 @@
<html>
<body>
<p>
Infrastructure implementations of io xml concerns.
</p>
</body>
</html>

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Represents alias for an attribute.
* @author peter.zozom
*/
public class AttributeAlias {
private String alias;
private String attributeName;
/**
* @return the alias
*/
public String getAlias() {
return alias;
}
/**
* Set alias for attribute
* @param alias the alias itself
*/
public void setAlias(String alias) {
this.alias = alias;
}
/**
* @return the attribute name
*/
public String getAttributeName() {
return attributeName;
}
/**
* Set the attribute name.
* @param attributeName the name of the attribute
*/
public void setAttributeName(String attributeName) {
this.attributeName = attributeName;
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Defines which XML attribute to use for a field or a specific type.
* @author peter.zozom
*/
public class AttributeProperties {
private String type;
private String fieldName;
/**
* @return the field name which will be rendered as XML attribute
*/
public String getFieldName() {
return fieldName;
}
/**
* Set the field to be rendered as XML attribute
* @param fieldName the name of the field
*/
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* Set type to be used for XML attribute.
* @param type the name of the type to be rendered as XML attribute
*/
public void setType(String type) {
this.type = type;
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Represents mapping of a class to a shorter name to be used in XML elements.
* @author peter.zozom
*/
public class ClassAlias {
private String name;
private String type;
private String defaultImplementation;
/**
* @return the default implementation of the type
*/
public String getDefaultImplementation() {
return defaultImplementation;
}
/**
* Set default implementation of type to use.
* @param defaultImplementation Default implementation of type to use if no
* other specified.
*/
public void setDefaultImplementation(String defaultImplementation) {
this.defaultImplementation = defaultImplementation;
}
/**
* @return short name for the type
*/
public String getName() {
return name;
}
/**
* Set short name.
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return aliased type
*/
public String getType() {
return type;
}
/**
* Set aliased type.
* @param type type to be aliased
*/
public void setType(String type) {
this.type = type;
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
import com.thoughtworks.xstream.XStream;
/**
* Represents converter to be registered for parsing. Converter acts as a
* strategy for converting a particular type of class to XML and back again.
*
* @author peter.zozom
*/
public class ConverterProperties {
private String className;
private int priority = XStream.PRIORITY_NORMAL;
/**
* @return converter class name
*/
protected String getClassName() {
return className;
}
/**
* Set converter class name.
* @param className converter class name
*/
protected void setClassName(String className) {
this.className = className;
}
/**
* @return converter priority
*/
protected int getPriority() {
return priority;
}
/**
* @param priority converter priority
*/
protected void setPriority(int priority) {
this.priority = priority;
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Defines default implementation of a class which should associated with an
* object. Whenever XStream encounters an instance of this type, it will use the
* default implementation instead. For example, java.util.ArrayList is the
* default implementation of java.util.List.
* @author peter.zozom
*/
public class DefaultImplementation {
private String defaultImpl;
private String type;
/**
* @return class name of the default implementation
*/
public String getDefaultImpl() {
return defaultImpl;
}
/**
* Set the class name of the default implementation which should be
* associated with ofType.
* @param defaultImpl class name of the default implementation
*/
public void setDefaultImpl(String defaultImpl) {
this.defaultImpl = defaultImpl;
}
/**
* @return type name associated with default implementation
*/
public String getType() {
return type;
}
/**
* Set type name which should be associated with default implementation.
* @param ofType type name
*/
public void setType(String ofType) {
this.type = ofType;
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Represents an alias for a field name.
* @author peter.zozom
*/
public class FieldAlias {
private String aliasName;
private String type;
private String fieldName;
/**
* @return field alias
*/
public String getAliasName() {
return aliasName;
}
/**
* Set field alias name.
* @param aliasName the alias itself
*/
public void setAliasName(String aliasName) {
this.aliasName = aliasName;
}
/**
* @return field name to be aliased
*/
public String getFieldName() {
return fieldName;
}
/**
* Set the name of the field to be aliased.
* @param fieldName the name of the field to be aliased
*/
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
/**
* @return the type that declares the field
*/
public String getType() {
return type;
}
/**
* Set the type that declares the field.
* @param type the type that declares the field
*/
public void setType(String type) {
this.type = type;
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Represents implicit collection definition. Implicit collection is used for:
* <ul>
* <li>any unmapped xml tag</li>
* <li>or all items of the given itemType</li>
* <li>or all items of the given element name defined by itemFieldName</li>
* </ul>
*
* @author peter.zozom
*/
public class ImplicitCollection {
private String ownerType;
private String fieldName;
private String itemFieldName;
private String itemType;
/**
* @return name of the field in the ownerType
*/
protected String getFieldName() {
return fieldName;
}
/**
* Set name of the field in the owner class. This field must be an
* <code>java.util.ArrayList</code>.
* @param fieldName name of the field in the ownerType
*/
protected void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
/**
* @return element name of the implicit collection
*/
protected String getItemFieldName() {
return itemFieldName;
}
/**
* Set element name of the implicit collection.
* @param itemFieldName element name of the implicit collection
*/
protected void setItemFieldName(String itemFieldName) {
this.itemFieldName = itemFieldName;
}
/**
* @return type of the items to be part of this collection
*/
protected String getItemType() {
return itemType;
}
/**
* Set yype of the items to be part of this collection (aliased with
* ItemFieldName, if provided).
* @param itemType type of the items to be part of this collection
*/
protected void setItemType(String itemType) {
this.itemType = itemType;
}
/**
* @return class owning the implicit collection
*/
protected String getOwnerType() {
return ownerType;
}
/**
* Set class that owns implicit collection.
* @param ownerType class owning the implicit collection
*/
protected void setOwnerType(String ownerType) {
this.ownerType = ownerType;
}
}

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Represents a mapping of qualified tag names to Java class names allowing
* class aliases and namespace aware mappings of qualified tag names to class
* names.
* @author peter.zozom
* @see javax.xml.namespace.QName
*/
public class Mapping {
private String namespaceURI;
private String localPart;
private String prefix;
private String className;
/**
* @return class name
*/
public String getClassName() {
return className;
}
/**
* Set Java type which will be mapped.
* @param className type name to be mapped
*/
public void setClassName(String className) {
this.className = className;
}
/**
* @return local part of the qualified name
*/
public String getLocalPart() {
return localPart;
}
/**
* Set local part of the qualified name.
* @param localPart local part of the qualified name
* @see javax.xml.namespace.QName
*/
public void setLocalPart(String localPart) {
this.localPart = localPart;
}
/**
* @return namespace URI of the qualified name
*/
public String getNamespaceURI() {
return namespaceURI;
}
/**
* Set namespace URI of the qualified name.
* @param namespaceURI namespace URI of the qualified name
* @see javax.xml.namespace.QName
*/
public void setNamespaceURI(String namespaceURI) {
this.namespaceURI = namespaceURI;
}
/**
* @return prefix of the qualified name
*/
public String getPrefix() {
return prefix;
}
/**
* Set prefix of the qualified name.
* @param prefix prefix of the qualified name
* @see javax.xml.namespace.QName
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Defines a field which shouldn't be serialized. To omit a field you must
* always provide the declaring type and not necessarily the type that is
* converted.
* @author peter.zozom
*
*/
public class OmmitedField {
private String type;
private String fieldName;
/**
* @return field which should be ommited
*/
protected String getFieldName() {
return fieldName;
}
/**
* Set field which should be ommited.
* @param fieldName field which should be ommited
*/
protected void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
/**
* @return declaring type of the ommited field
*/
protected String getType() {
return type;
}
/**
* Set declaring type of the ommited field.
* @param type declaring type of the ommited field
*/
protected void setType(String type) {
this.type = type;
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
/**
* Represents mapping a type to a shorter name to be used in XML elements. Any
* class that is assignable to this type will be aliased to the same name.
* @author peter.zozom
*/
public class TypeAlias {
private String name;
private String type;
/**
* @return short name for the type
*/
public String getName() {
return name;
}
/**
* Set short name.
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return aliased type
*/
public String getType() {
return type;
}
/**
* Set aliased type.
* @param type type to be aliased
*/
public void setType(String type) {
this.type = type;
}
}

View File

@@ -1,301 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
import java.util.List;
import java.util.Map;
import com.thoughtworks.xstream.XStream;
/**
* Value object, which holds configuration for XStream.
*
* @author peter.zozom
* @author Dave Syer
*
* @see XStreamConfigurationFactoryBean
* @see Mapping
* @see ClassAlias
* @see TypeAlias
* @see FieldAlias
* @see AttributeAlias
* @see AttributeProperties
* @see ConverterProperties
* @see XStream#setMode(int)
* @see ImplicitCollection
* @see OmmitedField
* @see XStream#addImmutableType(Class)
* @see DefaultImplementation
*/
public class XStreamConfiguration {
private List mappings = null;
private String rootElementName = null;
private Map rootElementAttributes;
private List classAliases = null;
private List typeAliases = null;
private List fieldAliases = null;
private List attributeAliases = null;
private List attributes = null;
private List converters = null;
private int mode = XStream.XPATH_RELATIVE_REFERENCES;
private List implicitCollections = null;
private List ommitedFields = null;
private List immutableTypes = null;
private List defaultImplementations = null;
/**
* @return list of the {@link DefaultImplementation} objects
*/
public List getDefaultImplementations() {
return defaultImplementations;
}
/**
* Set list of default implementations.
* @param defaultImplementations list of the {@link DefaultImplementation}
* objects
* @see DefaultImplementation
*/
public void setDefaultImplementations(List defaultImplementations) {
this.defaultImplementations = defaultImplementations;
}
/**
* @return list of the immutable type names
*/
public List getImmutableTypes() {
return immutableTypes;
}
/**
* Set list of immutable types.
* @param immutableTypes list of the immutable type names
* @see XStream#addImmutableType(Class)
*/
public void setImmutableTypes(List immutableTypes) {
this.immutableTypes = immutableTypes;
}
/**
* @return list of the {@link AttributeAlias} objects
*/
public List getAttributeAliases() {
return attributeAliases;
}
/**
* Set list of attribute aliases.
* @param attributeAliases list of the {@link AttributeAlias} objects
* @see AttributeAlias
*/
public void setAttributeAliases(List attributeAliases) {
this.attributeAliases = attributeAliases;
}
/**
* @return list of the {@link AttributeProperties} objects
*/
public List getAttributes() {
return attributes;
}
/**
* Set list of attribute properties.
* @param attributes list of the {@link AttributeProperties}
* objects
* @see AttributeProperties
*/
public void setAttributes(List attributes) {
this.attributes = attributes;
}
/**
* @return the classAliases
*/
public List getClassAliases() {
return classAliases;
}
/**
* Set list of class aliases.
* @param classAliases the classAliases to set
* @see ClassAlias
*/
public void setClassAliases(List classAliases) {
this.classAliases = classAliases;
}
/**
* @return list of the {@link ConverterProperties} objects
*/
public List getConverters() {
return converters;
}
/**
* Set list of custom converters.
* @param converters list of the {@link ConverterProperties} objects
* @see ConverterProperties
*/
public void setConverters(List converters) {
this.converters = converters;
}
/**
* @return the fieldAliases
*/
public List getFieldAliases() {
return fieldAliases;
}
/**
* Set list of field aliases.
* @param fieldAliases the list of fieldAliases to set
* @see FieldAlias
*/
public void setFieldAliases(List fieldAliases) {
this.fieldAliases = fieldAliases;
}
/**
* @return list of the {@link ImplicitCollections} objects
*/
public List getImplicitCollections() {
return implicitCollections;
}
/**
* Set list of implicit collection definitions.
* @param implicitCollections list of the {@link ImplicitCollections}
* objects
* @see ImplicitCollection
*/
public void setImplicitCollections(List implicitCollections) {
this.implicitCollections = implicitCollections;
}
/**
* @return list of the {@link Mapping} objects
*/
public List getMappings() {
return mappings;
}
/**
* Set list of "qualified tag name - to - class name" mappigs.
* @param mappings list of the {@link Mapping} objects
* @see Mapping
*/
public void setMappings(List mappings) {
this.mappings = mappings;
}
/**
* @return the actual mode
*/
public int getMode() {
return mode;
}
/**
* Set mode for dealing with duplicate references. If not provided, default
* value is used ({@link XStream#XPATH_RELATIVE_REFERENCES}).
* @param mode the mode to set
* @see XStream#setMode(int)
*/
public void setMode(int mode) {
this.mode = mode;
}
/**
* @return list of the {@link OmmitedFields} objects
*/
public List getOmmitedFields() {
return ommitedFields;
}
/**
* Set list of ommited fields.
* @param ommitedFields list of the {@link OmmitedFields} objects
* @see OmmitedField
*/
public void setOmmitedFields(List ommitedFields) {
this.ommitedFields = ommitedFields;
}
/**
* @return the root element attributes
*/
public Map getRootElementAttributes() {
return rootElementAttributes;
}
/**
* Set attributes of root element. Each Map entry has key = "attribute name"
* and value = "attribute value".
* @param rootElementAttributes map of the root element attributes
*/
public void setRootElementAttributes(Map rootElementAttributes) {
this.rootElementAttributes = rootElementAttributes;
}
/**
* @return the root element name
*/
public String getRootElementName() {
return rootElementName;
}
/**
* Set name of the root element. Valid only for writing to XML.
* @param rootElementName the root element name
*/
public void setRootElementName(String rootElementName) {
this.rootElementName = rootElementName;
}
/**
* @return the list of the {@link TypeAlias} objects
*/
public List getTypeAliases() {
return typeAliases;
}
/**
* Set list of type aliases.
* @param typeAliases list of the {@link TypeAlias} objects
* @see TypeAlias
*/
public void setTypeAliases(List typeAliases) {
this.typeAliases = typeAliases;
}
}

View File

@@ -1,146 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.core.io.Resource;
import com.thoughtworks.xstream.XStream;
/**
* Factory creates {@link XStreamConfiguration} object, which hold XStream's
* configuration settings. These settings are read from provided configuration
* XML file.
*
* @author peter.zozom
* @author Dave Syer
*/
public class XStreamConfigurationFactoryBean extends AbstractFactoryBean {
private Log log = LogFactory.getLog(XStreamConfigurationFactoryBean.class);
private Resource resource;
/**
* Creates {@link XStreamConfiguration} object from XStream's config file.
* @return XStream's configuration settings.
*/
private XStreamConfiguration getXStreamConfiguration() {
XStream stream = new XStream();
setConfigAliases(stream);
XStreamConfiguration xsc;
try {
InputStream is = resource.getInputStream();
xsc = (XStreamConfiguration) stream.fromXML(is);
is.close();
}
catch (IOException ioe) {
log.debug(ioe);
throw new BatchEnvironmentException("Could not read XStream mapping file.", ioe);
}
return xsc;
}
/*
* Set aliases necessary for parsing configuration file in xstream format.
*/
private void setConfigAliases(XStream stream) {
stream.aliasField("root-element-name", XStreamConfiguration.class, "rootElementName");
stream.aliasField("root-element-attributes", XStreamConfiguration.class, "rootElementAttributes");
stream.alias("class-alias", ClassAlias.class);
stream.aliasField("default-implementation", ClassAlias.class, "defaultImplementation");
stream.aliasField("class-aliases", XStreamConfiguration.class, "classAliases");
stream.alias("type-alias", TypeAlias.class);
stream.aliasField("type-aliases", XStreamConfiguration.class, "typeAliases");
stream.alias("field-alias", FieldAlias.class);
stream.aliasField("alias-name", FieldAlias.class, "aliasName");
stream.aliasField("field-name", FieldAlias.class, "fieldName");
stream.aliasField("field-aliases", XStreamConfiguration.class, "fieldAliases");
stream.alias("attribute-alias", AttributeAlias.class);
stream.aliasField("attribute-name", AttributeAlias.class, "attributeName");
stream.aliasField("attribute-aliases", XStreamConfiguration.class, "attributeAliases");
stream.alias("attribute-properties", AttributeProperties.class);
stream.aliasField("field-name", AttributeProperties.class, "fieldName");
stream.aliasField("attributes", XStreamConfiguration.class, "attributes");
stream.alias("converter-properties", ConverterProperties.class);
stream.aliasField("class-name", ConverterProperties.class, "className");
stream.alias("implicit-collection", ImplicitCollection.class);
stream.aliasField("owner-type", ImplicitCollection.class, "ownerType");
stream.aliasField("item-type", ImplicitCollection.class, "itemType");
stream.aliasField("field-name", ImplicitCollection.class, "fieldName");
stream.aliasField("item-field-name", ImplicitCollection.class, "itemFieldName");
stream.aliasField("implicit-collections", XStreamConfiguration.class, "implicitCollections");
stream.alias("ommited-field", OmmitedField.class);
stream.aliasField("field-name", OmmitedField.class, "fieldName");
stream.aliasField("ommited-fields", XStreamConfiguration.class, "ommitedFields");
stream.alias("default-implementation", DefaultImplementation.class);
stream.aliasField("default-impl", DefaultImplementation.class, "defaultImpl");
stream.aliasField("default-implementations", XStreamConfiguration.class, "defaultImplementations");
stream.aliasField("immutable-types", XStreamConfiguration.class, "immutableTypes");
stream.alias("attribute", Entry.class);
stream.alias("mapping", Mapping.class);
stream.aliasField("class-name", Mapping.class, "className");
stream.alias("configuration", XStreamConfiguration.class);
stream.alias("key", java.lang.String.class);
stream.alias("value", java.lang.String.class);
stream.alias("type", java.lang.String.class);
}
/**
* Set the filename of the configuration XML file.
* @param configFile resource for reading configuration
*/
public void setConfigFile(Resource resource) {
this.resource = resource;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
*/
protected Object createInstance() throws Exception {
return getXStreamConfiguration();
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#getObjectType()
*/
public Class getObjectType() {
return XStreamConfiguration.class;
}
}

View File

@@ -1,853 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.batch.io.xml.ObjectInput;
import org.springframework.batch.io.xml.ObjectInputFactory;
import org.springframework.batch.io.xml.ObjectOutput;
import org.springframework.batch.io.xml.ObjectOutputFactory;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.io.xml.QNameMap;
import com.thoughtworks.xstream.io.xml.StaxReader;
import com.thoughtworks.xstream.io.xml.StaxWriter;
/**
* XStreamFactory class implements both factory interfaces -
* {@link ObjectInputFactory} and {@link ObjectOutputFactory}. Factory methods
* {@link #createObjectInput(Resource, String)} and
* {@link #createObjectOutput(Resource, String)} return implementations of
* {@link ObjectInput} and {@link ObjectOutput} interfaces. These
* implementations (ObjectInputWrapper and ObjecOutputWrapper) are defined as
* factory's inner classes. They are wrapping StAX reader/writer for accessing
* xml streams, XStream mapper for mapping Xml-to-ValueObjects and
* {@link FileChannel} for file manipulation This factory implementation uses
* {@link XStreamConfiguration} as source for XStream configuration settings.
*
* @author peter.zozom
* @see ObjectInputFactory
* @see ObjectOutputFactory
* @see XStreamConfiguration
*/
public class XStreamFactory implements ObjectOutputFactory, ObjectInputFactory {
private static final Log log = LogFactory.getLog(XStreamFactory.class);
private XStreamConfiguration config;
/**
* Set the XStream's configuration.
* @param config value object holding XStream's configuration settings
*/
public void setConfig(XStreamConfiguration config) {
this.config = config;
}
/*
* Set up XStream. Proctected visibility modifier is used to allow easier
* testing of set...() methods.
*/
protected void setUpXStream(XStream stream) {
setClassAliases(stream);
setTypeAliases(stream);
setFieldAliases(stream);
setAttributeAliases(stream);
setAttributes(stream);
registerConverters(stream);
setMode(stream);
addImplicitCollections(stream);
setOmittedFileds(stream);
addImmutableTypes(stream);
addDefaultImplementations(stream);
}
/*
* Iterate over list of DefaultImplementation objects and add default
* implementations to the XStream.
*/
private void addDefaultImplementations(XStream stream) {
// get list of DefaultImplementation objects
List defaultImplementations = config.getDefaultImplementations();
// if not null iterate over list
if (defaultImplementations != null) {
for (Iterator i = defaultImplementations.iterator(); i.hasNext();) {
DefaultImplementation di = (DefaultImplementation) i.next();
// try to create Class object for default implementation class
// name
Class defaultImplementation;
try {
defaultImplementation = Class.forName(di.getDefaultImpl());
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + di.getDefaultImpl(), cnfe);
}
// try to create Class object for ofType class name
Class ofType;
try {
ofType = Class.forName(di.getType());
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + di.getType(), cnfe);
}
// add default implementation
stream.addDefaultImplementation(defaultImplementation, ofType);
}
}
}
/*
* Iterate over list of immutable type names and pass them to the XStream.
*/
private void addImmutableTypes(XStream stream) {
// get list of names of immutable types
List immutableTypes = config.getImmutableTypes();
// if not null iterate over list
if (immutableTypes != null) {
for (Iterator i = immutableTypes.iterator(); i.hasNext();) {
String it = (String) i.next();
// try to create Class object for immutableTypeName
Class immutableType;
try {
immutableType = Class.forName(it);
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + it, cnfe);
}
// add immutable type
stream.addImmutableType(immutableType);
}
}
}
/*
* Iterate over list of OmmitField objects and register ommited fields to
* the XStream.
*/
private void setOmittedFileds(XStream stream) {
// get list of OmmitedField objects
List ommitedFields = config.getOmmitedFields();
// if not null iterate over list
if (ommitedFields != null) {
for (Iterator i = ommitedFields.iterator(); i.hasNext();) {
OmmitedField ommitedField = (OmmitedField) i.next();
// register field to be ommited
try {
stream.omitField(Class.forName(ommitedField.getType()), ommitedField.getFieldName());
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + ommitedField.getType(), cnfe);
}
}
}
}
/*
* Iterate over list of ImplicitCollection objects and add implicit
* collections to the XStream. XStream has 3 methods for adding implicit
* collections. Decision which method to call is based on provided settings.
*/
private void addImplicitCollections(XStream stream) {
// get list of ImplicionCollection object
List implicitCollections = config.getImplicitCollections();
// if not null iterate over list
if (implicitCollections != null) {
for (Iterator i = implicitCollections.iterator(); i.hasNext();) {
ImplicitCollection impCol = (ImplicitCollection) i.next();
String typeName = impCol.getOwnerType();
// create Class object for typeName
try {
Class ownerType = Class.forName(typeName);
// if itemType not provided, add implicit collection for any
// unmapped xml tag
if (impCol.getItemType() == null) {
stream.addImplicitCollection(ownerType, impCol.getFieldName());
}
else {
typeName = impCol.getItemType();
// create Class object for itemType
Class itemType = Class.forName(typeName);
// if itemFieldName not provided, add implicit
// collection for all items of the given itemType
if (impCol.getItemFieldName() == null) {
stream.addImplicitCollection(ownerType, impCol.getFieldName(), itemType);
}
else {
// else add implicit collection for all items of the
// given element name defined by itemFieldName
stream.addImplicitCollection(ownerType, impCol.getFieldName(), impCol.getItemFieldName(),
itemType);
}
}
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + typeName, cnfe);
}
}
}
}
/*
* Set mode for dealing with duplicate references.
*/
private void setMode(XStream stream) {
stream.setMode(config.getMode());
}
/*
* Iterate over list of ConverterProperties objects and register converters
* to XStream.
*/
private void registerConverters(XStream stream) {
// get list of ConverterProperties
List converters = config.getConverters();
// if not null iterate over list
if (converters != null) {
for (Iterator i = converters.iterator(); i.hasNext();) {
ConverterProperties cp = (ConverterProperties) i.next();
// create Class object for converter class name
try {
Class converter = Class.forName(cp.getClassName());
// if converter type is assignable to SingleValueConverter,
// register it as SingleValueConverter
if (SingleValueConverter.class.isAssignableFrom(converter)) {
stream.registerConverter((SingleValueConverter) converter.newInstance(), cp.getPriority());
// if converter type is assignable to Converter,
// register it as Converter
}
else if (Converter.class.isAssignableFrom(converter)) {
stream.registerConverter((Converter) converter.newInstance(), cp.getPriority());
}
else {
throw new BatchEnvironmentException("Unable to register converter for class: "
+ cp.getClassName());
}
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + cp.getClassName(), cnfe);
}
catch (InstantiationException ie) {
log.debug(ie);
throw new BatchEnvironmentException("Unable to instantiate class: " + cp.getClassName(),
ie);
}
catch (IllegalAccessException iae) {
log.debug(iae);
throw new BatchEnvironmentException("Unable to instantiate class: " + cp.getClassName(),
iae);
}
}
}
}
/*
* Iterate over list of AttributeProperties objects and map XML attributes
* to fields or types.
*/
private void setAttributes(XStream stream) {
// get list of AttributeProperties objects
List attributeProperties = config.getAttributes();
// if not null iterate over list
if (attributeProperties != null) {
for (Iterator i = attributeProperties.iterator(); i.hasNext();) {
AttributeProperties ap = (AttributeProperties) i.next();
String fieldName = ap.getFieldName();
// create Class object for type name
try {
Class type = Class.forName(ap.getType());
// if field name is provided, map attribute to the field
if (fieldName != null) {
stream.useAttributeFor(fieldName, type);
}
else {
// else map attribute to the type
stream.useAttributeFor(type);
}
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + ap.getType(), cnfe);
}
}
}
}
/*
* Iterate over list of AttributeAlias objects and configure attribute
* aliases
*/
private void setAttributeAliases(XStream stream) {
// get list of AttributeAlias objects
List attributeAliases = config.getAttributeAliases();
// if not null iterate over list
if (attributeAliases != null) {
for (Iterator i = attributeAliases.iterator(); i.hasNext();) {
AttributeAlias alias = (AttributeAlias) i.next();
stream.aliasAttribute(alias.getAlias(), alias.getAttributeName());
}
}
}
/*
* Iterate over list of FieldAlias objects and configure field aliases
*/
private void setFieldAliases(XStream stream) {
// get list of FieldAlias objects
List fieldAliases = config.getFieldAliases();
// if not null iterate over list
if (fieldAliases != null) {
for (Iterator i = fieldAliases.iterator(); i.hasNext();) {
FieldAlias alias = (FieldAlias) i.next();
try {
stream.aliasField(alias.getAliasName(), Class.forName(alias.getType()), alias.getFieldName());
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + alias.getType(), cnfe);
}
}
}
}
/*
* Iterate over list of TypeAlias objects and configure type aliases
*/
private void setTypeAliases(XStream stream) {
// get list of TypeAlias objects
List typeAliases = config.getTypeAliases();
// if not null iterate over list
if (typeAliases != null) {
for (Iterator i = typeAliases.iterator(); i.hasNext();) {
TypeAlias alias = (TypeAlias) i.next();
try {
stream.aliasType(alias.getName(), Class.forName(alias.getType()));
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + alias.getType(), cnfe);
}
}
}
}
/*
* Iterate over list of ClassAlias objects and configure class aliases
*/
private void setClassAliases(XStream stream) {
// get list of ClassAlias objects
List classAliases = config.getClassAliases();
// if not null iterate over list
if (classAliases != null) {
for (Iterator i = classAliases.iterator(); i.hasNext();) {
ClassAlias alias = (ClassAlias) i.next();
Class type;
try {
type = Class.forName(alias.getType());
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException("Unable to find class: " + alias.getType(), cnfe);
}
if (alias.getDefaultImplementation() != null) {
Class defaultImplementation;
try {
defaultImplementation = Class.forName(alias.getDefaultImplementation());
}
catch (ClassNotFoundException cnfe) {
log.debug(cnfe);
throw new BatchEnvironmentException(
"Unable to find class: " + alias.getDefaultImplementation(), cnfe);
}
stream.alias(alias.getName(), type, defaultImplementation);
}
else {
stream.alias(alias.getName(), type);
}
}
}
}
/*
* Create QNameMap from list of Mapping objects.
*/
private QNameMap getMapping() {
List mappings = config.getMappings();
QNameMap map = new QNameMap();
if (mappings != null) {
for (Iterator i = mappings.iterator(); i.hasNext();) {
Mapping mapping = (Mapping) i.next();
QName qname = new QName(mapping.getNamespaceURI(), mapping.getLocalPart(), mapping.getPrefix());
map.registerMapping(qname, mapping.getClassName());
}
}
return map;
}
/**
* Creates instance of {@link ObjectInput} which is used by
* for deserializing object from XML file.
* @param resource the input XML file
* @param encoding the encoding to use
* @return ObjectInput which will read from the provided file
* @see org.springframework.batch.io.xml.ObjectInputFactory#createObjectInput(Resource,
* java.lang.String)
*/
public ObjectInput createObjectInput(Resource resource, String encoding) {
ObjectInput wrapper;
XStream stream = new XStream();
setUpXStream(stream);
try {
XMLInputFactory xmlif = XMLInputFactory.newInstance();
XMLStreamReader xmlReader = xmlif.createXMLStreamReader(resource.getInputStream(), encoding);
StaxReader reader = new StaxReader(getMapping(), xmlReader);
java.io.ObjectInput input = stream.createObjectInputStream(reader);
wrapper = new ObjectInputWrapper(xmlReader, input);
}
catch (XMLStreamException xse) {
log.error(xse);
throw new DataAccessResourceFailureException("Unable to get XML reader", xse);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to get ObjectInputStream", ioe);
}
return wrapper;
}
/**
* Creates instance of {@link ObjectOutput} which is used by
* for serializing object to XML file.
* @param resource the output XML file
* @param encoding the encoding to use
* @return ObjectOutput which will write to the provided file
* @see org.springframework.batch.io.xml.ObjectOutputFactory#createObjectOutput(Resource,
* java.lang.String)
*/
public ObjectOutput createObjectOutput(Resource resource, String encoding) {
ObjectOutput wrapper;
FileChannel channel;
XStream stream = new XStream();
setUpXStream(stream);
try {
XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
FileOutputStream os;
try {
os = new FileOutputStream(resource.getFile(), true);
channel = os.getChannel();
}
catch (FileNotFoundException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to write to file resource: [" + resource + "]",
ioe);
}
XMLStreamWriter xmlWriter = xmlof.createXMLStreamWriter(os, encoding);
StaxWriter writer = new StaxWriter(getMapping(), xmlWriter);
String rootElementName = config.getRootElementName();
java.io.ObjectOutput output;
if (rootElementName != null) {
output = stream.createObjectOutputStream(writer, rootElementName);
}
else {
output = stream.createObjectOutputStream(writer);
}
writeAttributes(xmlWriter, config.getRootElementAttributes());
wrapper = new ObjectOutputWrapper(xmlWriter, channel, output);
}
catch (XMLStreamException xse) {
log.error(xse);
throw new DataAccessResourceFailureException("Unable to get XML writer", xse);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to get ObjectOutputStream", ioe);
}
return wrapper;
}
/*
* Writes attributes to current xml element
*
* @param attributes map of attributes (key, value) @throws
* XMLStreamException
*/
private void writeAttributes(XMLStreamWriter xmlWriter, Map attributes) throws XMLStreamException {
if ((attributes != null) && !attributes.isEmpty()) {
for (Iterator i = attributes.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
xmlWriter.writeAttribute((String) entry.getKey(), (String) entry.getValue());
}
}
}
/**
* Implementation of {@link ObjectInput} which wraps
* {@link java.io.ObjectInput} and {@link XMLStreamReader} (which is StAX
* parser) objects. Each of these objects handles the same input file on
* different level and provides different set of methods:
* <UL>
* <LI>java.io.ObjectInput object is used for reading mapped objects</LI>
* <LI>XMLStreamReader object is used for getting actual position (line
* number) within xml file</LI>
* </UL>
*/
public static class ObjectInputWrapper implements ObjectInput {
java.io.ObjectInput input;
XMLStreamReader reader;
/**
* Postprocessing after restart. Current implementation does nothing.
* @param data
* @see org.springframework.batch.io.xml.ObjectInput#afterRestart(java.lang.Object)
*/
public void afterRestart(Object data) {
}
/**
* Constructor.
*
* @param reader the xml stream reader
* @param input the object input pointing to same file as reader
*/
public ObjectInputWrapper(XMLStreamReader reader, java.io.ObjectInput input) {
this.input = input;
this.reader = reader;
}
/**
* Close the object input. It closes all wraped input streams
* @see org.springframework.batch.io.xml.ObjectInput#close()
*/
public void close() {
try {
input.close();
reader.close();
}
catch (XMLStreamException xse) {
log.error(xse);
throw new DataAccessResourceFailureException("Unable to close XML Input Source", xse);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to close ObjectInputStream", ioe);
}
}
/**
* Return the current line number in the input stream.
* @return the current line number
* @see org.springframework.batch.io.xml.ObjectInput#position()
*/
public long position() {
Location location = reader.getLocation();
return location.getLineNumber();
}
/**
* Read and return an object.
* @return the object read from the stream
* @throws ClassNotFoundException If the class of a serialized bject
* cannot be found.
* @throws IOException If any of the usual Input/Output related
* exceptions occur.
* @see org.springframework.batch.io.xml.ObjectInput#readObject()
*/
public Object readObject() throws ClassNotFoundException, IOException {
return input.readObject();
}
}
/**
* Implementation of ObjectOutput which wraps java.io.ObjectOutput,
* XMLStreamWriter and FileChannel objects. Each of these objects handles
* the same output file on different level and provides different set of
* methods:
* <UL>
* <LI>java.io.ObjectOutput object is used for writing java objects to xml
* output file</LI>
* <LI>FileChannel object is used for file manipulation (truncate,
* position, size)</LI>
* <LI>XMLStreamWriter object is used for writing XML elements directly to
* XML output stream</LI>
* </UL>
*/
public static class ObjectOutputWrapper implements ObjectOutput {
java.io.ObjectOutput output;
XMLStreamWriter writer;
FileChannel channel;
/**
* Constructor.
*
* @param writer the xml stream writer
* @param channel the file channel pointing to same file as writer
* @param output the object output pointing to same file as writer
*/
public ObjectOutputWrapper(XMLStreamWriter writer, FileChannel channel, java.io.ObjectOutput output) {
this.writer = writer;
this.channel = channel;
this.output = output;
}
/**
* Postprocessing after restart. It removes redundant xml header.
* @param data java.lang.Long restart file position
* @see org.springframework.batch.io.xml.ObjectOutput#afterRestart(java.lang.Object)
*/
public void afterRestart(Object data) {
long offset = ((Long) data).longValue();
// When xmlWriter is initialized, it always writes xml header and
// opening tag of root element
// but this is unwanted, because currently we are restarting job.
// Header and opening
// tag of root element have been already written at the beginning of
// job processing.
// Current output file looks like this:
// 1. <?xml version='1.0' encoding='utf-8'?>
// 2. <root>
// 3-n. .... <someRecords/> ....
// n+1. </root>
// n+2. <?xml version='1.0' encoding='utf-8'?>
// n+3. <root
// Opening tag is not currently finished. We want to remove lines
// n,n+1,n+2,n+3,...
// offset is currently equal to position of beginning of line n+1.
// NOTE: openning tag of root element is always written when output
// is being opened.
// closing tag of root element is always written when output is
// being closed.
try {
// At first we write some element to writer, e.g. empty comment.
// This will change output like this:
// n+3. <root>
// n+4. <!-- -->
writer.writeComment("");
// Now we flush output stream. Lines n+2,n+3,n+4 are now written
// to the file.
output.flush();
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to write to ObjectOutputStream", ioe);
}
catch (XMLStreamException xse) {
log.error(xse);
throw new DataAccessResourceFailureException("Unable to get XML writer", xse);
}
// Finally we truncate file size to lastMarkedByteOffsetPosition.
// This will remove lines n+1 .. n+4.
truncate(offset);
position(offset);
}
/**
* Close the object output, which means to close all wrapped output
* streams.
* @see org.springframework.batch.io.xml.ObjectOutput#close()
*/
public void close() {
try {
output.close();
writer.close();
channel.close();
}
catch (XMLStreamException xse) {
log.error(xse);
throw new DataAccessResourceFailureException("Unable to close XML Output Source", xse);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("Unable to close ObjectOutputStream", ioe);
}
}
/**
* Flush the object output. This will write any buffered output bytes.
* @see org.springframework.batch.io.xml.ObjectOutput#flush()
*/
public void flush() {
try {
output.flush();
}
catch (IOException ioe) {
log.debug(ioe);
throw new DataAccessResourceFailureException("An error occured while writing to XmlOutputSource", ioe);
}
}
/**
* Retrieve file position.
* @return File position, a non-negative integer counting the number of
* bytes from the beginning of the file to the current position
* @see org.springframework.batch.io.xml.ObjectOutput#position()
*/
public long position() {
long position = 0;
// flush buffer before getting position
flush();
try {
position = channel.position();
}
catch (IOException ioe) {
log.debug(ioe);
throw new DataAccessResourceFailureException("An error occured while writing to XmlOutputSource", ioe);
}
return position;
}
/**
* Set the file position.
* @param newPosition The new position, a non-negative integer counting
* the number of bytes from the beginning of the file
* @see org.springframework.batch.io.xml.ObjectOutput#position(long)
*/
public void position(long newPosition) {
try {
channel.position(newPosition);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("An error occured while writing to XmlOutputSource", ioe);
}
}
/**
* Returns the current size of the file.
* @return The current size of the file, measured in bytes
* @see org.springframework.batch.io.xml.ObjectOutput#size()
*/
public long size() {
long size;
try {
size = channel.size();
}
catch (IOException ioe) {
log.debug(ioe);
throw new DataAccessResourceFailureException("An error occured while writing to XmlOutputSource", ioe);
}
return size;
}
/**
* Truncates the file to the given size.
* @param size The new size, a non-negative byte count
* @see org.springframework.batch.io.xml.ObjectOutput#truncate(long)
*/
public void truncate(long size) {
try {
channel.truncate(size);
}
catch (IOException ioe) {
log.error(ioe);
throw new DataAccessResourceFailureException("An error occured while writing to XmlOutputSource", ioe);
}
}
/**
* Write object to the underlying stream.
* @param obj the object to write
* @throws IOException Any of the usual Input/Output related exceptions.
* @see org.springframework.batch.io.xml.ObjectOutput#writeObject(java.lang.Object)
*/
public void writeObject(Object obj) throws IOException {
output.writeObject(obj);
}
}
}

View File

@@ -1,569 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--xtools2_universal_type_manager-->
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.mmi.ui.signatures.diagram" version="7.0.0"><feature description="" name="Rational Modeling Platform (com.ibm.xtools.rmp)" url="" version="7.0.0"/></signature>?>
<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.0/notation" xmlns:uml="http://www.eclipse.org/uml2/2.0.0/UML" xmlns:umlnotation="http://www.ibm.com/xtools/1.5.2/Umlnotation" xmi:id="_zdRLcOgOEdu5GYaBl4l5qw" type="Class" name="XmlInputOutput.dnx">
<children xmi:id="_3S6AQOgOEdu5GYaBl4l5qw">
<children xmi:id="_3S6AQ-gOEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_3S6AROgOEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_3S6ARegOEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_3S6ARugOEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_3S6AR-gOEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_3S6ASOgOEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_3S6ASegOEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_3S6ASugOEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_3S6AS-gOEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_3S6AQegOEdu5GYaBl4l5qw" lineColor="0" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=XmlInputTemplate%5Bjcu%5Ename=XmlInputTemplate.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_3S6AQugOEdu5GYaBl4l5qw" x="8745" y="343"/>
</children>
<children xmi:id="_6ojGYOgOEdu5GYaBl4l5qw">
<children xmi:id="_6ojGY-gOEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_6ojGZOgOEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_6ojGZegOEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_6ojGZugOEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_6ojGZ-gOEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_6ojGaOgOEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_6ojGaegOEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_6ojGaugOEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_6ojGa-gOEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_6ojGYegOEdu5GYaBl4l5qw" lineColor="0" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=XmlOutputTemplate%5Bjcu%5Ename=XmlOutputTemplate.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_6ojGYugOEdu5GYaBl4l5qw" x="15477" y="343"/>
</children>
<children xmi:id="_Az2LA-gPEdu5GYaBl4l5qw">
<children xmi:id="_Az2LBugPEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_Az2LB-gPEdu5GYaBl4l5qw" width="530" height="530"/>
</children>
<children xmi:id="_Az2LCOgPEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_Az2LCegPEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_Az2LCugPEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_Az2LC-gPEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_Az2LDOgPEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_Az2LDegPEdu5GYaBl4l5qw"/>
<layoutConstraint xmi:type="notation:Ratio" xmi:id="_Uio-IOhBEdu5GYaBl4l5qw" value="0.08968058968058969"/>
</children>
<children xmi:id="_Az2LDugPEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_Az2LD-gPEdu5GYaBl4l5qw"/>
<layoutConstraint xmi:type="notation:Ratio" xmi:id="_Uio-IehBEdu5GYaBl4l5qw" value="0.9103194103194103"/>
</children>
<styles xmi:type="umlnotation:UMLClassifierStyle" xmi:id="_Az2LBOgPEdu5GYaBl4l5qw" lineColor="128" showStereotype="Label" useClassifierShape="true"/>
<element xmi:type="uml:Interface" href="mmi:///#jbintype%5Ename=java.io.ObjectInput%5Bproject%5Eid=batch-breeze%5D$uml.Interface"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_Az2LBegPEdu5GYaBl4l5qw" x="1902" y="13314"/>
</children>
<children xmi:id="_kj8xUOgPEdu5GYaBl4l5qw">
<children xmi:id="_kj8xU-gPEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_kj8xVOgPEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_kj8xVegPEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_kj8xVugPEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_kj8xV-gPEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_kj8xWOgPEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_kj8xWegPEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_kj8xWugPEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_kj8xW-gPEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_kj8xUegPEdu5GYaBl4l5qw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jbintype%5Ename=com.thoughtworks.xstream.core.util.CustomObjectInputStream%5Bproject%5Eid=batch-breeze%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_kj8xUugPEdu5GYaBl4l5qw" x="951" y="22507"/>
</children>
<children xmi:id="_sfqDoegPEdu5GYaBl4l5qw">
<children xmi:id="_sfqDpOgPEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_sfqDpegPEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_sfqDpugPEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_sfqDp-gPEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_sfqDqOgPEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_sfqDqegPEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_sfqDqugPEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_sfqDq-gPEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_sfqDrOgPEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_sfqDougPEdu5GYaBl4l5qw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jbintype%5Ename=com.thoughtworks.xstream.core.util.CustomObjectOutputStream%5Bproject%5Eid=batch-breeze%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_sfqDo-gPEdu5GYaBl4l5qw" x="23458" y="22507"/>
</children>
<children xmi:id="_SFOp4OgoEdu5GYaBl4l5qw">
<children xmi:id="_SFOp4-goEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_SFOp5OgoEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_SFOp5egoEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_SFOp5ugoEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_SFOp5-goEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_SFUwgOgoEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_SFUwgegoEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_SFUwgugoEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_SFUwg-goEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_SFOp4egoEdu5GYaBl4l5qw" lineColor="128" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jbintype%5Ename=java.io.ObjectInputStream%5Bproject%5Eid=batch-breeze%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_SFOp4ugoEdu5GYaBl4l5qw" x="1320" y="18703"/>
</children>
<children xmi:id="_5ughMOgoEdu5GYaBl4l5qw" type="Note">
<children xmi:id="_5ughM-goEdu5GYaBl4l5qw" type="DiagramName">
<element xsi:nil="true"/>
</children>
<children xmi:id="_5ughNOgoEdu5GYaBl4l5qw" type="Description">
<element xsi:nil="true"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_5ughMegoEdu5GYaBl4l5qw" fontColor="8388608" description="XStream's implementation of ObjectInputStream" fillColor="13369343" lineColor="12560536"/>
<element xsi:nil="true"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_5ughMugoEdu5GYaBl4l5qw" x="5389" y="20922" width="5051" height="1268"/>
</children>
<children xmi:id="_f0v4cOgpEdu5GYaBl4l5qw">
<children xmi:id="_f0v4c-gpEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_f0v4dOgpEdu5GYaBl4l5qw" width="530" height="530"/>
</children>
<children xmi:id="_f0v4degpEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_f0v4dugpEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_f0v4d-gpEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_f0v4eOgpEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_f0v4eegpEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_f0v4eugpEdu5GYaBl4l5qw"/>
</children>
<children xmi:id="_f0v4e-gpEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_f0v4fOgpEdu5GYaBl4l5qw"/>
</children>
<styles xmi:type="umlnotation:UMLClassifierStyle" xmi:id="_f0v4cegpEdu5GYaBl4l5qw" lineColor="128" showStereotype="Label" useClassifierShape="true"/>
<element xmi:type="uml:Interface" href="mmi:///#jbintype%5Ename=java.io.ObjectOutput%5Bproject%5Eid=batch-breeze%5D$uml.Interface"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_f0v4cugpEdu5GYaBl4l5qw" x="24409" y="13631"/>
</children>
<children xmi:id="_zY50kOgpEdu5GYaBl4l5qw">
<children xmi:id="_zY50k-gpEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_zY50lOgpEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_zY50legpEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_zY50lugpEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_zY50l-gpEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_zY50mOgpEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_zY50megpEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_zY50mugpEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_zY50m-gpEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_zY50kegpEdu5GYaBl4l5qw" lineColor="128" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jbintype%5Ename=java.io.ObjectOutputStream%5Bproject%5Eid=batch-breeze%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_zY50kugpEdu5GYaBl4l5qw" x="23775" y="18703"/>
</children>
<children xmi:id="_2S8j0OgpEdu5GYaBl4l5qw" type="Note">
<children xmi:id="_2S8j0-gpEdu5GYaBl4l5qw" type="DiagramName">
<element xsi:nil="true"/>
</children>
<children xmi:id="_2S8j1OgpEdu5GYaBl4l5qw" type="Description">
<element xsi:nil="true"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_2S8j0egpEdu5GYaBl4l5qw" fontColor="8388608" description="XStream's implementation of ObjectOutputStream" fillColor="13369343" lineColor="12560536"/>
<element xsi:nil="true"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_2S8j0ugpEdu5GYaBl4l5qw" x="20288" y="20922" width="5051" height="1268"/>
</children>
<children xmi:id="_DdzUMOgtEdu5GYaBl4l5qw">
<children xmi:id="_DdzUM-gtEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_DdzUNOgtEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_DdzUNegtEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_DdzUNugtEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_DdzUN-gtEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_DdzUOOgtEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_DdzUOegtEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_DdzUOugtEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_DdzUO-gtEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_DdzUMegtEdu5GYaBl4l5qw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=XStreamConfiguration%5Bjcu%5Ename=XStreamConfiguration.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_DdzUMugtEdu5GYaBl4l5qw" x="12097" y="17778"/>
</children>
<children xmi:id="_2K50kOhJEdu5GYaBl4l5qw">
<children xmi:id="_2K50k-hJEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_2K50lOhJEdu5GYaBl4l5qw" width="530" height="530"/>
</children>
<children xmi:id="_2K50lehJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_2K50luhJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_2K50l-hJEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_2K50mOhJEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_2K50mehJEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_2K50muhJEdu5GYaBl4l5qw"/>
</children>
<children xmi:id="_2K50m-hJEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_2K50nOhJEdu5GYaBl4l5qw"/>
</children>
<styles xmi:type="umlnotation:UMLClassifierStyle" xmi:id="_2K50kehJEdu5GYaBl4l5qw" lineColor="0" showStereotype="Label" useClassifierShape="true"/>
<element xmi:type="uml:Interface" href="mmi:///#jsrctype%5Ename=ObjectInput%5Bjcu%5Ename=ObjectInput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Interface"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_2K50kuhJEdu5GYaBl4l5qw" x="1585" y="3804"/>
</children>
<children xmi:id="_2cYmIOhJEdu5GYaBl4l5qw">
<children xmi:id="_2ceswOhJEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_2ceswehJEdu5GYaBl4l5qw" width="530" height="530"/>
</children>
<children xmi:id="_2ceswuhJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_2cesw-hJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_2cesxOhJEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_2cesxehJEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_2cesxuhJEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_2cesx-hJEdu5GYaBl4l5qw"/>
</children>
<children xmi:id="_2cesyOhJEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_2cesyehJEdu5GYaBl4l5qw"/>
</children>
<styles xmi:type="umlnotation:UMLClassifierStyle" xmi:id="_2cYmIehJEdu5GYaBl4l5qw" lineColor="0" showStereotype="Label" useClassifierShape="true"/>
<element xmi:type="uml:Interface" href="mmi:///#jsrctype%5Ename=ObjectOutput%5Bjcu%5Ename=ObjectOutput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Interface"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_2cYmIuhJEdu5GYaBl4l5qw" x="24092" y="3170"/>
</children>
<children xmi:id="_6EjmsOhJEdu5GYaBl4l5qw">
<children xmi:id="_6Ejms-hJEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_6EjmtOhJEdu5GYaBl4l5qw" width="530" height="530"/>
</children>
<children xmi:id="_6EjmtehJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_6EjmtuhJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_6Ejmt-hJEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_6EjmuOhJEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_6EjmuehJEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_6EjmuuhJEdu5GYaBl4l5qw"/>
</children>
<children xmi:id="_6Ejmu-hJEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_6EjmvOhJEdu5GYaBl4l5qw"/>
</children>
<styles xmi:type="umlnotation:UMLClassifierStyle" xmi:id="_6EjmsehJEdu5GYaBl4l5qw" lineColor="0" showStereotype="Label" useClassifierShape="true"/>
<element xmi:type="uml:Interface" href="mmi:///#jsrctype%5Ename=ObjectInputFactory%5Bjcu%5Ename=ObjectInputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Interface"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_6EjmsuhJEdu5GYaBl4l5qw" x="8559" y="4438"/>
</children>
<children xmi:id="_9tli4OhJEdu5GYaBl4l5qw">
<children xmi:id="_9tli4-hJEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_9tli5OhJEdu5GYaBl4l5qw" width="530" height="530"/>
</children>
<children xmi:id="_9tli5ehJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_9tli5uhJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_9tli5-hJEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_9tli6OhJEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_9tli6ehJEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_9tli6uhJEdu5GYaBl4l5qw"/>
</children>
<children xmi:id="_9tli6-hJEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_9tli7OhJEdu5GYaBl4l5qw"/>
</children>
<styles xmi:type="umlnotation:UMLClassifierStyle" xmi:id="_9tli4ehJEdu5GYaBl4l5qw" lineColor="0" showStereotype="Label" useClassifierShape="true"/>
<element xmi:type="uml:Interface" href="mmi:///#jsrctype%5Ename=ObjectOutputFactory%5Bjcu%5Ename=ObjectOutputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Interface"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_9tli4uhJEdu5GYaBl4l5qw" x="15533" y="4438"/>
</children>
<children xmi:id="_KaIuAOhKEdu5GYaBl4l5qw">
<children xmi:id="_KaIuA-hKEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_KaIuBOhKEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_KaIuBehKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KaIuBuhKEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_KaIuB-hKEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_KaIuCOhKEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_KaIuCehKEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_KaIuCuhKEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_KaIuC-hKEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_KaIuAehKEdu5GYaBl4l5qw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=ObjectInputWrapper%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KaIuAuhKEdu5GYaBl4l5qw" x="8559" y="14582"/>
</children>
<children xmi:id="_KaIuDOhKEdu5GYaBl4l5qw">
<children xmi:id="_KaIuD-hKEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_KaIuEOhKEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_KaIuEehKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KaIuEuhKEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_KaIuE-hKEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_KaIuFOhKEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_KaIuFehKEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_KaIuFuhKEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_KaIuF-hKEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_KaIuDehKEdu5GYaBl4l5qw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=ObjectOutputWrapper%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KaIuDuhKEdu5GYaBl4l5qw" x="15348" y="14634"/>
</children>
<children xmi:id="_KaIuGOhKEdu5GYaBl4l5qw">
<children xmi:id="_KaIuG-hKEdu5GYaBl4l5qw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_KaIuHOhKEdu5GYaBl4l5qw" width="1320" height="1320"/>
</children>
<children xmi:id="_KaIuHehKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KaIuHuhKEdu5GYaBl4l5qw" type="Name"/>
<children xmi:id="_KaIuH-hKEdu5GYaBl4l5qw" type="Parent"/>
<children xmi:id="_KaIuIOhKEdu5GYaBl4l5qw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_KaIuIehKEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<children xmi:id="_KaIuIuhKEdu5GYaBl4l5qw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_KaIuI-hKEdu5GYaBl4l5qw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_KaIuGehKEdu5GYaBl4l5qw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KaIuGuhKEdu5GYaBl4l5qw" x="12626" y="11491"/>
</children>
<children xmi:id="_PFLQoOjVEduS0q4MIMV9Cw">
<children xmi:id="_PFLQo-jVEduS0q4MIMV9Cw" type="ImageCompartment">
<layoutConstraint xmi:type="notation:Size" xmi:id="_PFLQpOjVEduS0q4MIMV9Cw" width="1320" height="1320"/>
</children>
<children xmi:id="_PFRXQOjVEduS0q4MIMV9Cw" type="Stereotype"/>
<children xmi:id="_PFRXQejVEduS0q4MIMV9Cw" type="Name"/>
<children xmi:id="_PFRXQujVEduS0q4MIMV9Cw" type="Parent"/>
<children xmi:id="_PFRXQ-jVEduS0q4MIMV9Cw" type="AttributeCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_PFRXROjVEduS0q4MIMV9Cw" collapsed="true"/>
</children>
<children xmi:id="_PFRXRejVEduS0q4MIMV9Cw" type="OperationCompartment">
<styles xmi:type="umlnotation:UMLListCompartmentStyle" xmi:id="_PFRXRujVEduS0q4MIMV9Cw" collapsed="true"/>
</children>
<styles xmi:type="umlnotation:UMLShapeStyle" xmi:id="_PFLQoejVEduS0q4MIMV9Cw" lineColor="8404992" showStereotype="Label"/>
<element xmi:type="uml:Class" href="mmi:///#jsrctype%5Ename=XStreamConfigurationFactory%5Bjcu%5Ename=XStreamConfigurationFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D$uml.Class"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_PFLQoujVEduS0q4MIMV9Cw" x="11501" y="21239"/>
</children>
<children xmi:id="_zKpaAOv2EduQz8RnORu8xQ" type="Note">
<children xmi:id="_zK7t4Ov2EduQz8RnORu8xQ" type="DiagramName">
<element xsi:nil="true"/>
</children>
<children xmi:id="_zK7t4ev2EduQz8RnORu8xQ" type="Description">
<element xsi:nil="true"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_zKpaAev2EduQz8RnORu8xQ" fontColor="128" description="package java.io" fillColor="13369343" lineColor="10265827"/>
<element xsi:nil="true"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_zKpaAuv2EduQz8RnORu8xQ" x="2219" y="11729" height="794"/>
</children>
<children xmi:id="_3-8PcOv2EduQz8RnORu8xQ" type="Note">
<children xmi:id="_3-8Pcev2EduQz8RnORu8xQ" type="DiagramName">
<element xsi:nil="true"/>
</children>
<children xmi:id="_3-8Pcuv2EduQz8RnORu8xQ" type="Description">
<element xsi:nil="true"/>
</children>
<styles xmi:type="notation:ShapeStyle" xmi:id="_3-8Pc-v2EduQz8RnORu8xQ" fontColor="128" description="package java.io" fillColor="13369343" lineColor="10265827"/>
<element xsi:nil="true"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_3-8PdOv2EduQz8RnORu8xQ" x="24726" y="11729" height="793"/>
</children>
<styles xmi:type="umlnotation:UMLDiagramStyle" xmi:id="_zdRLcegOEdu5GYaBl4l5qw"/>
<element xsi:nil="true"/>
<edges xmi:id="_SKAcNugoEdu5GYaBl4l5qw" source="_kj8xUOgPEdu5GYaBl4l5qw" target="_SFOp4OgoEdu5GYaBl4l5qw">
<children xmi:id="_SKAcOegoEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_SKAcO-goEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_SKAcPOgoEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_SKAcOugoEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_SKAcN-goEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Generalization" href="mmi:///#jgen%5Bjbintype%5Ename=com.thoughtworks.xstream.core.util.CustomObjectInputStream%5Bproject%5Eid=batch-breeze%5D%5D%5Bjbintype%5Ename=java.io.ObjectInputStream%5Bproject%5Eid=batch-breeze%5D%5D$uml.Generalization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_SKAcOOgoEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_SKAcPegoEdu5GYaBl4l5qw" source="_SFOp4OgoEdu5GYaBl4l5qw" target="_Az2LA-gPEdu5GYaBl4l5qw">
<children xmi:id="_SKAcQOgoEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_SKAcQugoEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_SKAcQ-goEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_SKAcQegoEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_SKAcPugoEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:InterfaceRealization" href="mmi:///#jimpl%5Bjbintype%5Ename=java.io.ObjectInputStream%5Bproject%5Eid=batch-breeze%5D%5D%5Bjbintype%5Ename=java.io.ObjectInput%5Bproject%5Eid=batch-breeze%5D%5D$uml.InterfaceRealization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_SKAcP-goEdu5GYaBl4l5qw" points="[-2143, 450, 3810, -767]$[-4312, 900, 1641, -317]"/>
</edges>
<edges xmi:id="_5umn0OgoEdu5GYaBl4l5qw" type="NoteAttachment" source="_kj8xUOgPEdu5GYaBl4l5qw" target="_5ughMOgoEdu5GYaBl4l5qw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_5umn0egoEdu5GYaBl4l5qw"/>
<element xsi:nil="true"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_5umn0ugoEdu5GYaBl4l5qw" points="[-27, -31, 292, 335]$[-319, -366, 0, 0]"/>
</edges>
<edges xmi:id="_zZ89cOgpEdu5GYaBl4l5qw" source="_sfqDoegPEdu5GYaBl4l5qw" target="_zY50kOgpEdu5GYaBl4l5qw">
<children xmi:id="_zZ89c-gpEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_zZ89degpEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_zZ89dugpEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_zZ89dOgpEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_zZ89cegpEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Generalization" href="mmi:///#jgen%5Bjbintype%5Ename=com.thoughtworks.xstream.core.util.CustomObjectOutputStream%5Bproject%5Eid=batch-breeze%5D%5D%5Bjbintype%5Ename=java.io.ObjectOutputStream%5Bproject%5Eid=batch-breeze%5D%5D$uml.Generalization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_zZ89cugpEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_zZ89d-gpEdu5GYaBl4l5qw" source="_zY50kOgpEdu5GYaBl4l5qw" target="_f0v4cOgpEdu5GYaBl4l5qw">
<children xmi:id="_zZ89eugpEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_zZ89fOgpEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_zZ89fegpEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_zZ89e-gpEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_zZ89eOgpEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:InterfaceRealization" href="mmi:///#jimpl%5Bjbintype%5Ename=java.io.ObjectOutputStream%5Bproject%5Eid=batch-breeze%5D%5D%5Bjbintype%5Ename=java.io.ObjectOutput%5Bproject%5Eid=batch-breeze%5D%5D$uml.InterfaceRealization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_zZ89eegpEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_2TCqcOgpEdu5GYaBl4l5qw" type="NoteAttachment" source="_sfqDoegPEdu5GYaBl4l5qw" target="_2S8j0OgpEdu5GYaBl4l5qw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_2TCqcegpEdu5GYaBl4l5qw"/>
<element xsi:nil="true"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_2TCqcugpEdu5GYaBl4l5qw" points="[-73, -31, 766, 323]$[-839, -354, 0, 0]"/>
</edges>
<edges xmi:id="_2LMIcOhJEdu5GYaBl4l5qw" source="_3S6AQOgOEdu5GYaBl4l5qw" target="_2K50kOhJEdu5GYaBl4l5qw">
<children xmi:id="_2LSPEOhJEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_2LSPEuhJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_2LSPFOhJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_2LSPE-hJEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_2LSPEehJEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_2LMIcehJEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=XmlInputTemplate%5Bjcu%5Ename=XmlInputTemplate.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectInput%5Bjcu%5Ename=ObjectInput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_2LMIcuhJEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_2cxAoOhJEdu5GYaBl4l5qw" source="_6ojGYOgOEdu5GYaBl4l5qw" target="_2cYmIOhJEdu5GYaBl4l5qw">
<children xmi:id="_2c3HQOhJEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_2c3HQuhJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_2c3HROhJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_2c3HQ-hJEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_2c3HQehJEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_2cxAoehJEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=XmlOutputTemplate%5Bjcu%5Ename=XmlOutputTemplate.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectOutput%5Bjcu%5Ename=ObjectOutput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_2cxAouhJEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_6E16kOhJEdu5GYaBl4l5qw" source="_3S6AQOgOEdu5GYaBl4l5qw" target="_6EjmsOhJEdu5GYaBl4l5qw">
<children xmi:id="_6E16k-hJEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_6E16lehJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_6E16l-hJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_6E16luhJEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_6E16lOhJEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_6E16kehJEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=XmlInputTemplate%5Bjcu%5Ename=XmlInputTemplate.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectInputFactory%5Bjcu%5Ename=ObjectInputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_6E16kuhJEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_6E16n-hJEdu5GYaBl4l5qw" source="_6EjmsOhJEdu5GYaBl4l5qw" target="_2K50kOhJEdu5GYaBl4l5qw">
<children xmi:id="_6E16ouhJEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_6E8BMOhJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_6E8BMuhJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_6E8BMehJEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_6E16o-hJEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_6E16oOhJEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=ObjectInputFactory%5Bjcu%5Ename=ObjectInputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectInput%5Bjcu%5Ename=ObjectInput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_6E16oehJEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_9t32wOhJEdu5GYaBl4l5qw" source="_6ojGYOgOEdu5GYaBl4l5qw" target="_9tli4OhJEdu5GYaBl4l5qw">
<children xmi:id="_9t32w-hJEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_9t32xehJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_9t32x-hJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_9t32xuhJEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_9t32xOhJEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_9t32wehJEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=XmlOutputTemplate%5Bjcu%5Ename=XmlOutputTemplate.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectOutputFactory%5Bjcu%5Ename=ObjectOutputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_9t32wuhJEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_9t99YOhJEdu5GYaBl4l5qw" source="_9tli4OhJEdu5GYaBl4l5qw" target="_2cYmIOhJEdu5GYaBl4l5qw">
<children xmi:id="_9t99Y-hJEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_9t99ZehJEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_9t99Z-hJEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_9t99ZuhJEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_9t99ZOhJEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_9t99YehJEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=ObjectOutputFactory%5Bjcu%5Ename=ObjectOutputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectOutput%5Bjcu%5Ename=ObjectOutput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_9t99YuhJEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_Ka_poOhKEdu5GYaBl4l5qw" type="OwnedElement" source="_KaIuGOhKEdu5GYaBl4l5qw" target="_KaIuAOhKEdu5GYaBl4l5qw">
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_Ka_poehKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xsi:nil="true"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_Ka_pouhKEdu5GYaBl4l5qw" points="[0, 4366, 3201, -4683]$[-3201, 5953, 0, -3096]"/>
</edges>
<edges xmi:id="_Ka_po-hKEdu5GYaBl4l5qw" source="_KaIuAOhKEdu5GYaBl4l5qw" target="_Az2LA-gPEdu5GYaBl4l5qw">
<children xmi:id="_Ka_ppuhKEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_Ka_pqOhKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_Ka_pquhKEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_Ka_pqehKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_Ka_pp-hKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_Ka_ppOhKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=ObjectInputWrapper%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5D%5Bjbintype%5Ename=java.io.ObjectInput%5Bproject%5Eid=batch-breeze%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_Ka_ppehKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_Ka_ps-hKEdu5GYaBl4l5qw" source="_KaIuAOhKEdu5GYaBl4l5qw" target="_2K50kOhJEdu5GYaBl4l5qw">
<children xmi:id="_Ka_ptuhKEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_Ka_puOhKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_Ka_puehKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_Ka_pt-hKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_Ka_ptOhKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:InterfaceRealization" href="mmi:///#jimpl%5Bjsrctype%5Ename=ObjectInputWrapper%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectInput%5Bjcu%5Ename=ObjectInput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.InterfaceRealization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_Ka_ptehKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_Ka_puuhKEdu5GYaBl4l5qw" type="OwnedElement" source="_KaIuGOhKEdu5GYaBl4l5qw" target="_KaIuDOhKEdu5GYaBl4l5qw">
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_Ka_pu-hKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xsi:nil="true"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_Ka_pvOhKEdu5GYaBl4l5qw" points="[0, 4366, -3228, -4683]$[3228, 5953, 0, -3096]"/>
</edges>
<edges xmi:id="_KbFwSOhKEdu5GYaBl4l5qw" source="_KaIuDOhKEdu5GYaBl4l5qw" target="_2cYmIOhJEdu5GYaBl4l5qw">
<children xmi:id="_KbFwS-hKEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_KbFwTehKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KbL24OhKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KbFwTOhKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_KbFwSehKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:InterfaceRealization" href="mmi:///#jimpl%5Bjsrctype%5Ename=ObjectOutputWrapper%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectOutput%5Bjcu%5Ename=ObjectOutput.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.InterfaceRealization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_KbFwSuhKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_KbL24ehKEdu5GYaBl4l5qw" source="_KaIuDOhKEdu5GYaBl4l5qw" target="_f0v4cOgpEdu5GYaBl4l5qw">
<children xmi:id="_KbL25OhKEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_KbL25uhKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KbL26OhKEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_KbL25-hKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KbL25ehKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_KbL24uhKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=ObjectOutputWrapper%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5D%5Bjbintype%5Ename=java.io.ObjectOutput%5Bproject%5Eid=batch-breeze%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_KbL24-hKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_KbR9g-hKEdu5GYaBl4l5qw" source="_KaIuGOhKEdu5GYaBl4l5qw" target="_9tli4OhJEdu5GYaBl4l5qw">
<children xmi:id="_KbR9huhKEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_KbR9iOhKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KbR9iehKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KbR9h-hKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_KbR9hOhKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:InterfaceRealization" href="mmi:///#jimpl%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectOutputFactory%5Bjcu%5Ename=ObjectOutputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.InterfaceRealization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_KbR9hehKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_KbR9iuhKEdu5GYaBl4l5qw" source="_KaIuGOhKEdu5GYaBl4l5qw" target="_6EjmsOhJEdu5GYaBl4l5qw">
<children xmi:id="_KbR9jehKEdu5GYaBl4l5qw" type="NameLabel">
<children xmi:id="_KbR9j-hKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KbR9kOhKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KbR9juhKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_KbR9i-hKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:InterfaceRealization" href="mmi:///#jimpl%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=ObjectInputFactory%5Bjcu%5Ename=ObjectInputFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.InterfaceRealization"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_KbR9jOhKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_KbYENehKEdu5GYaBl4l5qw" source="_KaIuGOhKEdu5GYaBl4l5qw" target="_DdzUMOgtEdu5GYaBl4l5qw">
<children xmi:id="_KbYEOOhKEdu5GYaBl4l5qw" type="KindLabel">
<children xmi:id="_KbYEOuhKEdu5GYaBl4l5qw" type="Stereotype"/>
<children xmi:id="_KbYEPOhKEdu5GYaBl4l5qw" type="Kind"/>
<children xmi:id="_KbYEO-hKEdu5GYaBl4l5qw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KbYEOehKEdu5GYaBl4l5qw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_KbYENuhKEdu5GYaBl4l5qw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=XStreamFactory%5Bjcu%5Ename=XStreamFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=XStreamConfiguration%5Bjcu%5Ename=XStreamConfiguration.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_KbYEN-hKEdu5GYaBl4l5qw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_PFqY0OjVEduS0q4MIMV9Cw" source="_PFLQoOjVEduS0q4MIMV9Cw" target="_DdzUMOgtEdu5GYaBl4l5qw">
<children xmi:id="_PFqY0-jVEduS0q4MIMV9Cw" type="KindLabel">
<children xmi:id="_PFqY1ejVEduS0q4MIMV9Cw" type="Stereotype"/>
<children xmi:id="_PFqY1-jVEduS0q4MIMV9Cw" type="Kind"/>
<children xmi:id="_PFqY1ujVEduS0q4MIMV9Cw" type="Name"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_PFqY1OjVEduS0q4MIMV9Cw" y="-186"/>
</children>
<styles xmi:type="umlnotation:UMLConnectorStyle" xmi:id="_PFqY0ejVEduS0q4MIMV9Cw" showStereotype="Text"/>
<element xmi:type="uml:Usage" href="mmi:///#jdep%5Bjsrctype%5Ename=XStreamConfigurationFactory%5Bjcu%5Ename=XStreamConfigurationFactory.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D%5Bjsrctype%5Ename=XStreamConfiguration%5Bjcu%5Ename=XStreamConfiguration.java%5Bjpack%5Ename=org.springframework.batch.container.io.file.xml.support%5Bjsrcroot%5Esrcfolder=src/main/java%5Bproject%5Eid=batch-breeze%5D%5D%5D%5D%5D$uml.Usage"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_PFqY0ujVEduS0q4MIMV9Cw" points="[0, 0, 0, 0]$[0, 0, 0, 0]"/>
</edges>
<edges xmi:id="_zPzm0Ov2EduQz8RnORu8xQ" type="NoteAttachment" source="_Az2LA-gPEdu5GYaBl4l5qw" target="_zKpaAOv2EduQz8RnORu8xQ">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_zPzm0ev2EduQz8RnORu8xQ"/>
<element xsi:nil="true"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_zPzm0uv2EduQz8RnORu8xQ" points="[-16, -81, 102, 503]$[-118, -584, 0, 0]"/>
</edges>
<edges xmi:id="_5L6Y4Ov2EduQz8RnORu8xQ" type="NoteAttachment" source="_3-8PcOv2EduQz8RnORu8xQ" target="_f0v4cOgpEdu5GYaBl4l5qw">
<styles xmi:type="notation:ConnectorStyle" xmi:id="_5L6Y4ev2EduQz8RnORu8xQ"/>
<element xsi:nil="true"/>
<bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_5L6Y4uv2EduQz8RnORu8xQ" points="[0, 0, -7, -114]$[0, 41, -7, -73]"/>
<sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_5MAfgOv2EduQz8RnORu8xQ" id="(0.43587843,1.0)"/>
</edges>
</notation:Diagram>

View File

@@ -1,7 +0,0 @@
<html>
<body>
<p>
Infrastructure implementations of io xml xstream concerns.
</p>
</body>
</html>

View File

@@ -1,167 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInput;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.io.xml.xstream.XStreamFactory.ObjectInputWrapper;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Unit tests for {@link ObjectInputWrapper}.
* @author peter.zozom
*/
public class ObjectInputWrapperTests extends TestCase {
private ObjectInputWrapper wrapper;
private MockControl readerControl;
private XMLStreamReader reader;
private MockControl oiControl;
private ObjectInput input;
public void setUp() throws FileNotFoundException, XMLStreamException {
// create mock reader
readerControl = MockControl.createControl(XMLStreamReader.class);
reader = (XMLStreamReader) readerControl.getMock();
// create mock for java.io.ObjectInput
oiControl = MockControl.createControl(ObjectInput.class);
input = (ObjectInput) oiControl.getMock();
// create ObjectInputWrapper
wrapper = new ObjectInputWrapper(reader, input);
}
/**
* Test {@link ObjectInputWrapper#position()}.
*/
public void testPosition() {
// create mock for Location
MockControl locationControl = MockControl.createControl(Location.class);
Location location = (Location) locationControl.getMock();
location.getLineNumber();
locationControl.setReturnValue(104);
locationControl.replay();
// set up reader mock
reader.getLocation();
readerControl.setReturnValue(location);
readerControl.replay();
assertEquals(104, wrapper.position());
readerControl.verify();
locationControl.verify();
}
/**
* Test {@link ObjectInputWrapper#readObject()}
* @throws ClassNotFoundException
* @throws IOException
*/
public void testReadObject() throws ClassNotFoundException, IOException {
// set up objectInput mock
input.readObject();
oiControl.setReturnValue(this);
oiControl.replay();
// read object
assertSame(this, wrapper.readObject());
oiControl.verify();
}
public void testClose() throws XMLStreamException, IOException {
// TEST CLOSE
// set up reader mock
reader.close();
readerControl.replay();
// set up objectInput mock
input.close();
oiControl.replay();
wrapper.close();
readerControl.verify();
oiControl.verify();
// TEST CLOSE WITH XMLStreamException
// set up reader mock
readerControl.reset();
reader.close();
readerControl.setThrowable(new XMLStreamException());
readerControl.replay();
// set up objectInput mock
oiControl.reset();
input.close();
oiControl.replay();
try {
wrapper.close();
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException darfe) {
assertTrue(darfe.getCause() instanceof XMLStreamException);
}
readerControl.verify();
oiControl.verify();
// TEST CLOSE WITH IOException
// set up reader mock
readerControl.reset();
readerControl.replay();
// set up objectInput mock
oiControl.reset();
input.close();
oiControl.setThrowable(new IOException());
oiControl.replay();
try {
wrapper.close();
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException darfe) {
assertTrue(darfe.getCause() instanceof IOException);
}
readerControl.verify();
oiControl.verify();
}
}

View File

@@ -1,398 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.IOException;
import java.io.ObjectOutput;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.io.xml.xstream.XStreamFactory.ObjectOutputWrapper;
import org.springframework.dao.DataAccessResourceFailureException;
/**
* Unit tests for {@link ObjectOutputWrapper}.
* @author peter.zozom
*/
public class ObjectOutputWrapperTests extends TestCase {
private ObjectOutputWrapper wrapper;
private MockControl writerControl;
private XMLStreamWriter writer;
private MockControl ooControl;
private ObjectOutput output;
private MockFileChannel channel;
public void setUp() {
// create mock for xml writer
writerControl = MockControl.createControl(XMLStreamWriter.class);
writer = (XMLStreamWriter) writerControl.getMock();
// create mock for java.io.objectOutput
ooControl = MockControl.createControl(ObjectOutput.class);
output = (ObjectOutput) ooControl.getMock();
// create mock for file channel
channel = new MockFileChannel();
// create wrapper
wrapper = new ObjectOutputWrapper(writer, channel, output);
}
public void testAfterRestart() throws XMLStreamException, IOException {
// set up writer mock
writer.writeComment("");
writerControl.replay();
// set up objectOutput mock
output.flush();
ooControl.replay();
// call after restart
wrapper.afterRestart(new Long(99));
// check size and position
assertEquals(99, channel.size());
assertEquals(99, channel.position());
// TEST EXCEPTION HANDLING
// set up writer mock
writerControl.reset();
writer.writeComment("");
writerControl.setThrowable(new XMLStreamException());
writerControl.replay();
try {
wrapper.afterRestart(new Long(74));
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException bce) {
assertTrue(bce.getCause() instanceof XMLStreamException);
}
// set up writer mock
writerControl.reset();
writer.writeComment("");
writerControl.replay();
// set up objectOutput mock
ooControl.reset();
output.flush();
ooControl.setThrowable(new IOException());
ooControl.replay();
try {
wrapper.afterRestart(new Long(63));
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException bce) {
assertTrue(bce.getCause() instanceof IOException);
}
}
public void testClose() throws IOException, XMLStreamException {
// set up objectOutput mock
output.close();
ooControl.replay();
// set up writer mock
writer.close();
writerControl.replay();
wrapper.close();
// test whether channel, writer and output were closed
assertTrue(channel.isClosed());
ooControl.verify();
writerControl.verify();
// TEST EXCEPTION HANDLING
ooControl.reset();
output.close();
ooControl.setThrowable(new IOException());
ooControl.replay();
try {
wrapper.close();
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException bce) {
assertTrue(bce.getCause() instanceof IOException);
}
ooControl.reset();
output.close();
ooControl.replay();
writerControl.reset();
writer.close();
writerControl.setThrowable(new XMLStreamException());
writerControl.replay();
try {
wrapper.close();
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException bce) {
assertTrue(bce.getCause() instanceof XMLStreamException);
}
}
/**
* Test flush() method.
* @throws IOException
*/
public void testFlush() throws IOException {
// set up objectOutput mock (second call of flush() method will throw an
// IOException)
output.flush();
output.flush();
ooControl.setThrowable(new IOException());
ooControl.replay();
// call flush() twice
wrapper.flush();
try {
wrapper.flush();
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException bce) {
assertTrue(bce.getCause() instanceof IOException);
}
// verify method calls
ooControl.verify();
}
/**
* Test position() and position(int) methods.
* @throws IOException
*/
public void testPosition() throws IOException {
// set up fileChannel mock
channel.position(35);
// test position()
assertEquals(35, wrapper.position());
// test position(int)
wrapper.position(93);
assertEquals(93, channel.position());
// set exception
channel.setThrowable(new IOException());
// test exception handling
try {
wrapper.position();
fail("BatchEnviromentException was expected");
}
catch (DataAccessResourceFailureException bee) {
assertTrue(bee.getCause() instanceof IOException);
}
try {
wrapper.position(33);
fail("BatchEnviromentException was expected");
}
catch (DataAccessResourceFailureException bee) {
assertTrue(bee.getCause() instanceof IOException);
}
}
/**
* Test size() and truncate() methods.
* @throws IOException
*/
public void testSizeAndTruncate() throws IOException {
// set up fileChannel mock
channel.truncate(53);
// test size()
assertEquals(53, wrapper.size());
// test truncate(int)
wrapper.truncate(39);
assertEquals(39, channel.size());
// set exception
channel.setThrowable(new IOException());
// test exception handling
try {
wrapper.size();
fail("BatchEnviromentException was expected");
}
catch (DataAccessResourceFailureException bee) {
assertTrue(bee.getCause() instanceof IOException);
}
try {
wrapper.truncate(66);
fail("BatchEnviromentException was expected");
}
catch (DataAccessResourceFailureException bee) {
assertTrue(bee.getCause() instanceof IOException);
}
}
/**
* Test writeObject() method.
* @throws IOException
*/
public void testWriteObject() throws IOException {
//TODO why is "this" used as argument to writeObject?
// set up objectOutput mock
output.writeObject(this);
ooControl.replay();
// write object
wrapper.writeObject(this);
// verify method calls
ooControl.verify();
}
/*
* Mock for FileChannel
*/
private static class MockFileChannel extends FileChannel {
private long position;
private long size;
private boolean closed = false;
private IOException throwable;
public void setThrowable(IOException throwable) {
this.throwable = throwable;
}
public long position() throws IOException {
if (throwable != null) {
throw throwable;
}
return position;
}
public FileChannel position(long newPosition) throws IOException {
if (throwable != null) {
throw throwable;
}
this.position = newPosition;
return null;
}
public long size() throws IOException {
if (throwable != null) {
throw throwable;
}
return size;
}
public FileChannel truncate(long size) throws IOException {
if (throwable != null) {
throw throwable;
}
this.size = size;
return null;
}
protected void implCloseChannel() throws IOException {
closed = true;
}
public boolean isClosed() {
return closed;
}
public void force(boolean metaData) throws IOException {
}
public FileLock lock(long position, long size, boolean shared) throws IOException {
return null;
}
public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
return null;
}
public int read(ByteBuffer dst) throws IOException {
return 0;
}
public int read(ByteBuffer dst, long position) throws IOException {
return 0;
}
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
return 0;
}
public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {
return 0;
}
public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
return 0;
}
public FileLock tryLock(long position, long size, boolean shared) throws IOException {
return null;
}
public int write(ByteBuffer src) throws IOException {
return 0;
}
public int write(ByteBuffer src, long position) throws IOException {
return 0;
}
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
return 0;
}
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import junit.framework.TestCase;
import org.springframework.batch.io.xml.XmlErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Unit test for XmlErrorHandler
* @author peter.zozom
*/
public class XmlErrorHandlerTests extends TestCase {
XmlErrorHandler handler;
SAXParseException spe;
public void setUp() {
handler = new XmlErrorHandler();
spe = new SAXParseException("test", "pid", "sid", 1, 1);
}
public void testWarning() {
try {
handler.warning(spe);
}
catch (SAXException se) {
assertSame(spe, se.getException());
}
}
public void testError() {
try {
handler.error(spe);
}
catch (SAXException se) {
assertSame(spe, se.getException());
}
}
public void testFatalError() {
try {
handler.fatalError(spe);
}
catch (SAXException se) {
assertSame(spe, se.getException());
}
}
}

View File

@@ -1,124 +0,0 @@
package org.springframework.batch.io.xml;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.restart.RestartData;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.transaction.support.TransactionSynchronization;
/**
* Unit tests for {@link XmlInputSource2}
*
* @author Robert Kasanicky
*/
public class XmlInputSource2Tests extends TestCase {
private XmlInputSource2 inputSource = new XmlInputSource2();
private Resource getInputResource() throws IOException {
return new FileSystemResource("src/test/resources/org/springframework/batch/io/xml/test1.xml");
}
//@Override
protected void setUp() throws Exception {
inputSource.setRecordElementName("book");
inputSource.setResource(getInputResource());
inputSource.setUnmarshaller(new UnmarshallerStub());
inputSource.setUseSaxParser(true);
}
/**
* Regular usage scenario.
* The actual xml-to-object mapping is delegated to the injected unmarshaller.
*/
public void testRead() throws XmlMappingException, IOException {
MockControl umControl = MockControl.createControl(Unmarshaller.class);
Unmarshaller unmarshaller = (Unmarshaller) umControl.getMock();
Object expectedDomainObject = new Object();
unmarshaller.unmarshal(null);
umControl.setDefaultMatcher(MockControl.ALWAYS_MATCHER);
umControl.setDefaultReturnValue(expectedDomainObject);
umControl.replay();
inputSource.setUnmarshaller(unmarshaller);
//there are two records in the input file
assertSame(expectedDomainObject, inputSource.read());
assertSame(expectedDomainObject, inputSource.read());
assertNull(inputSource.read());
}
public void testReadUntilEnd() {
}
/**
* In case of rollback uncommited records are read again.
*/
public void testRollback() {
Object uncommited = inputSource.read();
inputSource.getSynchronization().afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
Object afterRollback = inputSource.read();
assertEquals(uncommited, afterRollback);
}
/**
* Records once marked to be skipped are not returned when read again.
*/
public void testSkip() {
Object first = inputSource.read();
inputSource.skip();
inputSource.getSynchronization().afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
Object second = inputSource.read();
assertFalse(second.equals(first));
}
/**
* In case of restart the input source should continue from the position when restart data was saved.
*/
public void testRestart() {
inputSource.read();
RestartData commitPoint = inputSource.getRestartData();
Object firstAfterCommit = inputSource.read();
inputSource.restoreFrom(commitPoint);
assertEquals(firstAfterCommit, inputSource.read());
}
/**
* Returns a fixed-length prefix of the original xml string instead of mapped object.
*
* @author Robert Kasanicky
*/
private static class UnmarshallerStub implements Unmarshaller {
private static final int PREFIX_LENGTH = 10000;
public boolean supports(Class clazz) {
return true;
}
public Object unmarshal(Source source) throws XmlMappingException, IOException {
char[] input = new char[PREFIX_LENGTH];
SAXSource saxSource = (SAXSource) source;
saxSource.getInputSource().getCharacterStream().read(input);
return String.valueOf(input);
}
}
}

View File

@@ -1,428 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.batch.io.sample.domain.LineItem;
import org.springframework.batch.io.sample.domain.Order;
import org.springframework.batch.io.sample.domain.Shipper;
import org.springframework.batch.io.xml.xstream.FieldAlias;
import org.springframework.batch.io.xml.xstream.Mapping;
import org.springframework.batch.io.xml.xstream.XStreamConfiguration;
import org.springframework.batch.io.xml.xstream.XStreamFactory;
import org.springframework.batch.restart.RestartData;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.util.ClassUtils;
/**
* Integration test for XmlInputTemplate. It tests reading, xml validation, skip
* and restart functionality.
* @author peter.zozom
*/
public class XmlInputSourceIntegrationTests extends TestCase {
private final static String INPUT_NAME = "xmlInputTemplate";
private XmlInputSource xmlInput;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
/**
* Set up XmlInputTemplate: create mock for FileLocator and create
* XStreamConfiguration object.
* @throws Exception
*/
public void setUp() throws Exception {
// create mock for file locator
Resource resource = new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(),
"20070125.testStream.xmlFileStep.xml"));
// Set up XStreamCfg:
XStreamConfiguration streamConfiguration = new XStreamConfiguration();
// Step 1: set field aliases
List aliases = new ArrayList();
FieldAlias alias = new FieldAlias();
alias.setAliasName("org.springframework.batch.io.sample.domain.Customer");
alias.setType("org.springframework.batch.io.sample.domain.Order");
alias.setFieldName("customer");
aliases.add(alias);
alias = new FieldAlias();
alias.setAliasName("org.springframework.batch.io.sample.domain.Shipper");
alias.setType("org.springframework.batch.io.sample.domain.Order");
alias.setFieldName("shipper");
aliases.add(alias);
streamConfiguration.setFieldAliases(aliases);
// Step 2: set mappings
List mappings = new ArrayList();
Mapping mapping = new Mapping();
mapping.setClassName("org.springframework.batch.io.sample.domain.Order");
mapping.setNamespaceURI("http://adsj.accenture.com/purchaseorders");
mapping.setLocalPart("order");
mapping.setPrefix("");
mappings.add(mapping);
mapping = new Mapping();
mapping.setClassName("org.springframework.batch.io.sample.domain.Customer");
mapping.setNamespaceURI("http://adsj.accenture.com/purchaseorders");
mapping.setLocalPart("customer");
mapping.setPrefix("");
mappings.add(mapping);
mapping = new Mapping();
mapping.setClassName("org.springframework.batch.io.sample.domain.LineItem");
mapping.setNamespaceURI("http://adsj.accenture.com/purchaseorders");
mapping.setLocalPart("lineItem");
mapping.setPrefix("");
mappings.add(mapping);
mapping = new Mapping();
mapping.setClassName("org.springframework.batch.io.sample.domain.Shipper");
mapping.setNamespaceURI("http://adsj.accenture.com/purchaseorders");
mapping.setLocalPart("shipper");
mapping.setPrefix("");
mappings.add(mapping);
streamConfiguration.setMappings(mappings);
// Set up input template
xmlInput = new XmlInputSource() {
public void registerSynchronization() {
}
};
xmlInput.setResource(resource);
xmlInput.setEncoding("UTF-8");
xmlInput.setName(INPUT_NAME);
XStreamFactory factory = new XStreamFactory();
factory.setConfig(streamConfiguration);
xmlInput.setInputFactory(factory);
}
public void tearDown() {
}
/**
* Test read functionality.
* @throws ParseException
*/
public void testRead() throws ParseException {
xmlInput.setValidating(false);
xmlInput.open();
// READ FIRST RECORD
Object result = xmlInput.read();
// is it Order?
assertTrue(result instanceof Order);
Order order = (Order) result;
// verify customer
assertNotNull(order.getCustomer());
assertEquals("Gladys Kravitz", order.getCustomer().getName());
assertEquals("Anytown, PA", order.getCustomer().getAddress());
assertEquals(34, order.getCustomer().getAge());
assertEquals(0, order.getCustomer().getMoo());
assertEquals(0, order.getCustomer().getPoo());
// verify date
assertEquals(sdf.parse("2003-01-07 14:16:00 GMT"), order.getDate());
// verify line items
List items = order.getLineItems();
assertEquals(2, items.size());
LineItem item = (LineItem) items.get(0);
assertEquals("Burnham's Celestial Handbook, Vol 1", item.getDescription());
assertEquals(5.0, item.getPerUnitOunces(), 0.0);
assertEquals(21.79, item.getPrice(), 0.0);
assertEquals(2, item.getQuantity());
item = (LineItem) items.get(1);
assertEquals("Burnham's Celestial Handbook, Vol 2", item.getDescription());
assertEquals(5.0, item.getPerUnitOunces(), 0.0);
assertEquals(19.89, item.getPrice(), 0.0);
assertEquals(2, item.getQuantity());
// verify shipper
Shipper shipper = order.getShipper();
assertEquals("ZipShip", shipper.getName());
assertEquals(0.74, shipper.getPerOunceRate(), 0.0);
// READ SECOND RECORD
result = xmlInput.read();
// is it Order?
assertTrue(result instanceof Order);
order = (Order) result;
// verify customer
assertNotNull(order.getCustomer());
assertEquals("John Smith", order.getCustomer().getName());
assertEquals("Chicago, IL", order.getCustomer().getAddress());
assertEquals(46, order.getCustomer().getAge());
assertEquals(0, order.getCustomer().getMoo());
assertEquals(0, order.getCustomer().getPoo());
// verify date
assertEquals(sdf.parse("2003-01-07 14:16:02 GMT"), order.getDate());
// verify line items
items = order.getLineItems();
assertEquals(3, items.size());
item = (LineItem) items.get(0);
assertEquals("XmlBeans in Action", item.getDescription());
assertEquals(3.0, item.getPerUnitOunces(), 0.0);
assertEquals(41.29, item.getPrice(), 0.0);
assertEquals(1, item.getQuantity());
item = (LineItem) items.get(1);
assertEquals("JSR-173", item.getDescription());
assertEquals(1.0, item.getPerUnitOunces(), 0.0);
assertEquals(11.99, item.getPrice(), 0.0);
assertEquals(5, item.getQuantity());
item = (LineItem) items.get(2);
assertEquals("Teach Yourself XML in 21 days", item.getDescription());
assertEquals(1.0, item.getPerUnitOunces(), 0.0);
assertEquals(35.49, item.getPrice(), 0.0);
assertEquals(1, item.getQuantity());
// verify shipper
shipper = order.getShipper();
assertEquals("ZipShip", shipper.getName());
assertEquals(0.74, shipper.getPerOunceRate(), 0.0);
// READ LAST RECORD
result = xmlInput.read();
// is it Order?
assertTrue(result instanceof Order);
order = (Order) result;
// verify customer
assertNotNull(order.getCustomer());
assertEquals("Peter Newman", order.getCustomer().getName());
assertEquals("Cleveland, OH", order.getCustomer().getAddress());
assertEquals(23, order.getCustomer().getAge());
assertEquals(0, order.getCustomer().getMoo());
assertEquals(0, order.getCustomer().getPoo());
// verify date
assertEquals(sdf.parse("2003-01-07 14:16:35 GMT"), order.getDate());
// verify line items
items = order.getLineItems();
assertEquals(1, items.size());
item = (LineItem) items.get(0);
assertEquals("Java 6", item.getDescription());
assertEquals(2.0, item.getPerUnitOunces(), 0.0);
assertEquals(12.79, item.getPrice(), 0.0);
assertEquals(3, item.getQuantity());
// verify shipper
shipper = order.getShipper();
assertEquals("UPS", shipper.getName());
assertEquals(0.69, shipper.getPerOunceRate(), 0.0);
// all records were processed already
assertNull(xmlInput.read());
// verify statistics TODO
// Map statistics = xmlInput.getStatistics();
// assertEquals("4",
// statistics.get(XmlInputTemplate.READ_STATISTICS_NAME));
xmlInput.close();
}
/**
* Test XML validation
*/
public void testValidation() {
// turn on xml validation
xmlInput.setValidating(true);
// TEST 1: parse valid xml
xmlInput.open();
xmlInput.close();
}
public void testInvalidXml() throws Exception {
xmlInput.setValidating(true);
// TEST 2: parse invalid xml
xmlInput.setResource(new ByteArrayResource("<invalid><xml>".getBytes()));
try {
xmlInput.open();
fail("Parsing invalid xml file. Exception should be thrown.");
}
catch (BatchEnvironmentException bee) {
assertTrue(true);
}
}
/**
* Test skip functioanlity.
* @throws ParseException
*/
public void testSkip() throws ParseException {
xmlInput.setValidating(false);
xmlInput.open();
// read first record
xmlInput.read();
// mark it as skipped
xmlInput.skip();
// read second record
xmlInput.read();
// read third record
xmlInput.read();
// mark it as skipped and rollback
xmlInput.skip();
xmlInput.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
// read second record again (first was skipped)
Object result = xmlInput.read();
// is it Order?
assertTrue(result instanceof Order);
Order order = (Order) result;
// verify customer
assertNotNull(order.getCustomer());
assertEquals("John Smith", order.getCustomer().getName());
assertEquals("Chicago, IL", order.getCustomer().getAddress());
assertEquals(46, order.getCustomer().getAge());
assertEquals(0, order.getCustomer().getMoo());
assertEquals(0, order.getCustomer().getPoo());
// verify date
assertEquals(sdf.parse("2003-01-07 14:16:02 GMT"), order.getDate());
// verify line items
List items = order.getLineItems();
assertEquals(3, items.size());
LineItem item = (LineItem) items.get(0);
assertEquals("XmlBeans in Action", item.getDescription());
assertEquals(3.0, item.getPerUnitOunces(), 0.0);
assertEquals(41.29, item.getPrice(), 0.0);
assertEquals(1, item.getQuantity());
item = (LineItem) items.get(1);
assertEquals("JSR-173", item.getDescription());
assertEquals(1.0, item.getPerUnitOunces(), 0.0);
assertEquals(11.99, item.getPrice(), 0.0);
assertEquals(5, item.getQuantity());
item = (LineItem) items.get(2);
assertEquals("Teach Yourself XML in 21 days", item.getDescription());
assertEquals(1.0, item.getPerUnitOunces(), 0.0);
assertEquals(35.49, item.getPrice(), 0.0);
assertEquals(1, item.getQuantity());
// verify shipper
Shipper shipper = order.getShipper();
assertEquals("ZipShip", shipper.getName());
assertEquals(0.74, shipper.getPerOunceRate(), 0.0);
// No records left, third record should be skipped
assertNull(xmlInput.read());
// verify statistics TODO
// Map statistics = xmlInput.getStatistics();
// assertEquals("4",
// statistics.get(XmlInputTemplate.READ_STATISTICS_NAME));
}
/**
* Test restart functionality.
* @throws ParseException
*/
public void testRestart() throws ParseException {
xmlInput.open();
// read first record and commit it
xmlInput.read();
xmlInput.afterCompletion(TransactionSynchronization.STATUS_COMMITTED);
// read second record and commit it
xmlInput.read();
xmlInput.afterCompletion(TransactionSynchronization.STATUS_COMMITTED);
// read third record
xmlInput.read();
xmlInput.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
RestartData restartData = xmlInput.getRestartData();
xmlInput.close();
xmlInput.open();
xmlInput.restoreFrom(restartData);
Object result = xmlInput.read();
// is it Order?
assertTrue(result instanceof Order);
Order order = (Order) result;
// verify customer
assertNotNull(order.getCustomer());
assertEquals("Peter Newman", order.getCustomer().getName());
assertEquals("Cleveland, OH", order.getCustomer().getAddress());
assertEquals(23, order.getCustomer().getAge());
assertEquals(0, order.getCustomer().getMoo());
assertEquals(0, order.getCustomer().getPoo());
// verify date
assertEquals(sdf.parse("2003-01-07 14:16:35 GMT"), order.getDate());
// verify line items
List items = order.getLineItems();
assertEquals(1, items.size());
LineItem item = (LineItem) items.get(0);
assertEquals("Java 6", item.getDescription());
assertEquals(2.0, item.getPerUnitOunces(), 0.0);
assertEquals(12.79, item.getPrice(), 0.0);
assertEquals(3, item.getQuantity());
// verify shipper
Shipper shipper = order.getShipper();
assertEquals("UPS", shipper.getName());
assertEquals(0.69, shipper.getPerOunceRate(), 0.0);
// all records were processed already
assertNull(xmlInput.read());
// verify statistics TODO
// Map statistics = xmlInput.getStatistics();
// assertEquals("4",
// statistics.get(XmlInputTemplate.READ_STATISTICS_NAME));
}
/**
* Tests null resource
* @throws Exception
*/
public void testGetFileLocatorStrategyWithNullParam() throws Exception {
// set file locator strategy to null
xmlInput.setResource(null);
try {
xmlInput.afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected
}
}
}

View File

@@ -1,284 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.batch.io.exception.BatchCriticalException;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.batch.io.xml.ObjectInput;
import org.springframework.batch.io.xml.ObjectInputFactory;
import org.springframework.batch.io.xml.XmlInputSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.util.ClassUtils;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* Additional unit tests, which test feuatores not tested with
* XmlInputTemplateIntegrationTest
* @author peter.zozom
*/
public class XmlInputSourceTests extends TestCase {
private MockControl oifControl;
private MockControl oiControl;
private ObjectInputFactory objectInputFactory;
private ObjectInput objectInput;
private XmlInputSource input;
/**
* Set up XmlInputTemplate: create mock for FileLocator,
* ObjectInputFactory and ObjectInput
*/
public void setUp() {
Resource resource = new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "20070125.testStream.xmlFileStep.xml"));
// create mock for ObjectInput
oiControl = MockControl.createControl(ObjectInput.class);
objectInput = (ObjectInput) oiControl.getMock();
// create mock for ObjectInputFactory
oifControl = MockControl.createControl(ObjectInputFactory.class);
objectInputFactory = (ObjectInputFactory) oifControl.getMock();
objectInputFactory.createObjectInput(resource, "UTF-8");
oifControl.setReturnValue(objectInput, 1);
oifControl.replay();
// create input template
input = new XmlInputSource() {
protected void registerSynchronization() {
}
protected SAXParserFactory getSaxFactory() throws FactoryConfigurationError {
return new MockSAXFactory();
}
};
// set up input template
input.setValidating(false);
input.setName("test_name");
input.setInputFactory(objectInputFactory);
input.setResource(resource);
}
/**
* Test init called twice (2nd call should do nothing)
*/
public void testDoubleInit() {
// set up objectInput mock
objectInput.position();
oiControl.setReturnValue(3, 1);
oiControl.replay();
// call init
input.open();
// call init again - nothing should happen
input.open();
// verify method calls for each mock object
oifControl.verify();
oiControl.verify();
}
/**
* Test exception handling in validateInputFile() method
*/
public void testExceptionsInValidationMethod() {
oifControl.reset();
oifControl.replay();
// set up objectInput mock
oiControl.replay();
input.setValidating(true);
try {
// call init again - nothing should happen
input.open();
fail("ParserConfigurationException was expected");
}
catch (BatchEnvironmentException bee) {
// ParserConfigurationException is expected
assertTrue(bee.getCause() instanceof ParserConfigurationException);
}
FileSystemResource resource = new FileSystemResource("FooDummy.xml");
assertTrue(!resource.exists());
input.setResource(resource);
try {
// call init again - nothing should happen
input.open();
fail("BatchCriticalException was expected");
}
catch (BatchCriticalException bee) {
// IOException is expected
assertTrue(bee.getCause() instanceof IOException);
}
// verify method calls for each mock object
oifControl.verify();
oiControl.verify();
}
/**
* Test exception handling in read() method
* @throws ClassNotFoundException
* @throws IOException
*/
public void testExceptionsInReadMethod() throws ClassNotFoundException, IOException {
// set up objectInput mock
objectInput.position();
oiControl.setReturnValue(3, 1);
objectInput.readObject();
oiControl.setThrowable(new IOException());
objectInput.readObject();
oiControl.setThrowable(new ClassNotFoundException());
oiControl.replay();
// call init
input.open();
try {
input.read();
fail("BatchCriticalException caused by IOException was expected");
}
catch (BatchCriticalException bce) {
assertTrue(bce.getCause() instanceof IOException);
}
try {
input.read();
fail("BatchCriticalException caused by ClassNotFoundException was expected");
}
catch (BatchCriticalException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
// verify method calls for each mock object
oifControl.verify();
oiControl.verify();
}
/**
* Test afterCompletition() method with transaction status "UNKNOWN"
*/
public void testTransactionUnknownStatus() {
// set up ObjectInput mock
objectInput.position();
oiControl.setReturnValue(3, 1);
oiControl.replay();
input.open();
// call afterCompletition method with unknown status - nothing should
// happen
input.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN);
// verify method calls for each mock object
oifControl.verify();
oiControl.verify();
}
/*
* Mock for SAXParserFactory, which either throws
* ParserConfigurationException or returns MockSAXParser
*/
private static class MockSAXFactory extends SAXParserFactory {
private static int counter = 0;
public boolean getFeature(String name) throws ParserConfigurationException, SAXNotRecognizedException,
SAXNotSupportedException {
return false;
}
public SAXParser newSAXParser() throws ParserConfigurationException, SAXException {
counter++;
if (counter % 2 != 0) {
throw new ParserConfigurationException();
}
return new MockSAXParser();
}
public void setFeature(String name, boolean value) throws ParserConfigurationException,
SAXNotRecognizedException, SAXNotSupportedException {
}
}
/*
* Mock for SAXParser, which throws IOException in parse(java.io.File,
* org.xml.sax.helpers.DefaultHandler) method
*/
private static class MockSAXParser extends SAXParser {
public void parse(File f, DefaultHandler dh) throws SAXException, IOException {
throw new IOException();
}
public Parser getParser() throws SAXException {
return null;
}
public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
return null;
}
public XMLReader getXMLReader() throws SAXException {
return null;
}
public boolean isNamespaceAware() {
return false;
}
public boolean isValidating() {
return false;
}
public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
}
}
}

View File

@@ -1,262 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml;
import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.easymock.internal.Range;
import org.springframework.batch.restart.RestartData;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.transaction.support.TransactionSynchronization;
/**
* Unit tests for XmlOutputTemplate
* @author peter.zozom
*
*/
public class XmlOutputSourceTests extends TestCase {
private final static String OUTPUT_NAME = "xmlOutputTemplate";
private XmlOutputSource xmlOutput;
private MockControl ooControl;
private ObjectOutput objectOutput;
private MockControl oofControl;
private ObjectOutputFactory objectOutputFactory;
/**
* Set up XmlOutputTemplate: create mock for FileLocator,
* ObjectOutputFactory and ObjectOutput.
*/
public void setUp() throws Exception {
// create File object
Resource file = new FileSystemResource(File.createTempFile("xml-output-test-", ".xml"));
// Create mock for ObjectOutput
ooControl = MockControl.createControl(ObjectOutput.class);
objectOutput = (ObjectOutput) ooControl.getMock();
// Create mock for ObjectOutputFactory, which will return mock
// ObjectOutput
oofControl = MockControl.createControl(ObjectOutputFactory.class);
objectOutputFactory = (ObjectOutputFactory) oofControl.getMock();
objectOutputFactory.createObjectOutput(file, "UTF-8");
oofControl.setReturnValue(objectOutput, new Range(1,2));
oofControl.replay();
// Create output template
xmlOutput = new XmlOutputSource() {
protected void registerSynchronization() {
}
};
// Set up output template
xmlOutput.setResource(file);
xmlOutput.setEncoding("UTF-8");
xmlOutput.setName(OUTPUT_NAME);
xmlOutput.setOutputFactory(objectOutputFactory);
}
/**
* Tests write and close method. Also tests statistics.
* @throws IOException
*/
public void testWrite() throws IOException {
// initialize xmlOutput
xmlOutput.open();
// set up ObjectOutput mock
objectOutput.writeObject(this);
objectOutput.writeObject(this);
objectOutput.close();
ooControl.replay();
// call write method
xmlOutput.write(this);
// verify statistics TODO
// Map statistics = xmlOutput.getStatistics();
// assertEquals("1", statistics.get(XmlOutputTemplate.WRITTEN_STATISTICS_NAME));
// call write method again
xmlOutput.write(this);
// call close method
xmlOutput.close();
// verify statistics again: count of written objects should be changed TODO
// statistics = xmlOutput.getStatistics();
// assertEquals("2", statistics.get(XmlOutputTemplate.WRITTEN_STATISTICS_NAME));
// verify method calls for each mock
oofControl.verify();
ooControl.verify();
}
/**
* Tests handling IOException raised within write() method
* @throws IOException
*/
public void testWriteWithIOException() throws IOException {
// initialize xmlOutput
xmlOutput.open();
// set up ObjectOutput mock
objectOutput.writeObject(this);
IOException ioe = new IOException("test");
ooControl.setThrowable(ioe);
objectOutput.close();
ooControl.replay();
try {
xmlOutput.write(this);
fail("BatchCriticalException was expected");
}
catch (DataAccessResourceFailureException bce) {
// exceptiow was expected: caused by ioe
assertSame(ioe, bce.getCause());
}
}
/**
* Tests commit and rollback functionality.
* @throws IOException
*/
public void testCommitAndRollback() throws IOException {
// Set up ObjectOutput mock:
objectOutput.writeObject(null);
// STEP1: commit: flush output and remember commit position
objectOutput.flush();
objectOutput.position();
ooControl.setReturnValue(102);
// STEP2: rollback: check size, truncate output and set new position
objectOutput.size();
ooControl.setReturnValue(500); // size(=500) > newSize(=102)
objectOutput.position(102);
objectOutput.truncate(102);
// STEP3: rollback with bad output size
objectOutput.size();
ooControl.setReturnValue(10); // size(=10) < newSize(=102)
ooControl.replay();
// initialize xmlOutput
xmlOutput.open();
xmlOutput.write(null); // because output writer is initialized in write method.
// test commit and rollback
// STEP1: commit
xmlOutput.afterCompletion(TransactionSynchronization.STATUS_COMMITTED);
// STEP2: rollback
xmlOutput.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
// STEP3: rollback with bad output size
try {
xmlOutput.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
fail("Exception was expected because of bad output size");
}
catch (IllegalStateException bce) {
// exception is expected
assertTrue(true);
}
// STEP4: call afterCompletition with status "UNKNOWN" - nothing should
// happen
xmlOutput.afterCompletion(TransactionSynchronization.STATUS_UNKNOWN);
// verify method calls for each mock
oofControl.verify();
ooControl.verify();
}
/**
* Tests restart functionality.
* @throws IOException
*/
public void testRestart() throws IOException {
// Set up ObjectOutput mock:
objectOutput.writeObject(null);
// - set position (=restartData)
objectOutput.position();
ooControl.setReturnValue(23001);
objectOutput.close();
objectOutput.writeObject(null);
// - after restart should be called with restart data
objectOutput.afterRestart(new Long(23001));
// - and finaly set size (it should be verified: size >
// newSize(=restartData))
objectOutput.size();
ooControl.setReturnValue(54301);
ooControl.replay();
// initialize xmlOutput
xmlOutput.open();
xmlOutput.write(null); // because output writer is initialized in write method.
// get restart data
RestartData restartData = xmlOutput.getRestartData();
assertEquals("23001", restartData.getProperties().getProperty(XmlOutputSource.RESTART_DATA_NAME));
xmlOutput.close();
// init for restart
xmlOutput.open();
xmlOutput.restoreFrom(restartData);
xmlOutput.write(null); // because output writer is initialized in write method.
// verify method calls for each mock
oofControl.verify();
ooControl.verify();
}
/**
* Tests getFileLocatorStrategy() with fileLocatorStrategy = null
*/
public void testGetFileLocatorStrategyWithNullParam() throws Exception {
// set file locator strategy to null
xmlOutput.setResource(null);
try {
xmlOutput.afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected
}
}
}

View File

@@ -1,234 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.core.io.ClassPathResource;
/**
* Integration tests for XStreamConfigurationFactory.
* @author peter.zozom
* @author Dave Syer
*/
public class XStreamConfigurationFactoryBeanIntegrationTests extends TestCase {
XStreamConfigurationFactoryBean factory;
public void setUp() {
factory = new XStreamConfigurationFactoryBean();
}
/**
* Test getXStreamCofiguration() method.
* @throws Exception
*/
public void testGetXStreamConfiguration() throws Exception {
// set config file
factory.setConfigFile(new ClassPathResource("xstream-config-test.xml", getClass()));
// get XStreamConfiguration
factory.afterPropertiesSet();
XStreamConfiguration config = (XStreamConfiguration) factory.getObject();
// test mode
assertEquals(1003, config.getMode());
// test root element name
assertEquals("root_test", config.getRootElementName());
// test root element attributes
Map rea = config.getRootElementAttributes();
assertNotNull(rea);
assertEquals(2, rea.size());
assertEquals("root-elementAttr_value1", rea.get("root-elementAttr_key1"));
assertEquals("root-elementAttr_value2", rea.get("root-elementAttr_key2"));
// test class aliases
List aliases = config.getClassAliases();
assertNotNull(aliases);
assertEquals(2, aliases.size());
ClassAlias classAlias = (ClassAlias) aliases.get(0);
assertEquals("class-alias_name1", classAlias.getName());
assertEquals("class-alias_type1", classAlias.getType());
assertEquals("class-alias_di1", classAlias.getDefaultImplementation());
classAlias = (ClassAlias) aliases.get(1);
assertEquals("class-alias_name2", classAlias.getName());
assertEquals("class-alias_type2", classAlias.getType());
assertEquals("class-alias_di2", classAlias.getDefaultImplementation());
// test type aliases
aliases = config.getTypeAliases();
assertNotNull(aliases);
assertEquals(2, aliases.size());
TypeAlias typeAlias = (TypeAlias) aliases.get(0);
assertEquals("type-alias_name1", typeAlias.getName());
assertEquals("type-alias_type1", typeAlias.getType());
typeAlias = (TypeAlias) aliases.get(1);
assertEquals("type-alias_name2", typeAlias.getName());
assertEquals("type-alias_type2", typeAlias.getType());
// test field aliases
aliases = config.getFieldAliases();
assertNotNull(aliases);
assertEquals(2, aliases.size());
FieldAlias fieldAlias = (FieldAlias) aliases.get(0);
assertEquals("field-alias_name1", fieldAlias.getAliasName());
assertEquals("field-alias_type1", fieldAlias.getType());
assertEquals("field1", fieldAlias.getFieldName());
fieldAlias = (FieldAlias) aliases.get(1);
assertEquals("field-alias_name2", fieldAlias.getAliasName());
assertEquals("field-alias_type2", fieldAlias.getType());
assertEquals("field2", fieldAlias.getFieldName());
// test attribute alias
aliases = config.getAttributeAliases();
assertNotNull(aliases);
assertEquals(2, aliases.size());
AttributeAlias attributeAlias = (AttributeAlias) aliases.get(0);
assertEquals("attribute-alias_name1", attributeAlias.getAttributeName());
assertEquals("attribute-alias_alias1", attributeAlias.getAlias());
attributeAlias = (AttributeAlias) aliases.get(1);
assertEquals("attribute-alias_name2", attributeAlias.getAttributeName());
assertEquals("attribute-alias_alias2", attributeAlias.getAlias());
// test attribute properties
List properties = config.getAttributes();
assertNotNull(properties);
assertEquals(2, properties.size());
AttributeProperties attributeProperties = (AttributeProperties) properties.get(0);
assertEquals("attribute-properties_type1", attributeProperties.getType());
assertEquals("attribute-properties_field1", attributeProperties.getFieldName());
attributeProperties = (AttributeProperties) properties.get(1);
assertEquals("attribute-properties_type2", attributeProperties.getType());
assertEquals("attribute-properties_field2", attributeProperties.getFieldName());
// test converters
properties = config.getConverters();
assertNotNull(properties);
assertEquals(2, properties.size());
ConverterProperties converterProperties = (ConverterProperties) properties.get(0);
assertEquals("converter.class-name1", converterProperties.getClassName());
assertEquals(-50, converterProperties.getPriority());
converterProperties = (ConverterProperties) properties.get(1);
assertEquals("converter.class-name2", converterProperties.getClassName());
assertEquals(750, converterProperties.getPriority());
// test implicit collections
List collections = config.getImplicitCollections();
assertNotNull(collections);
assertEquals(2, collections.size());
ImplicitCollection implicitCollection = (ImplicitCollection) collections.get(0);
assertEquals("ic_owner-type1", implicitCollection.getOwnerType());
assertEquals("ic_field-name1", implicitCollection.getFieldName());
assertEquals("ic_itemField-name1", implicitCollection.getItemFieldName());
assertEquals("ic_item-type1", implicitCollection.getItemType());
implicitCollection = (ImplicitCollection) collections.get(1);
assertEquals("ic_owner-type2", implicitCollection.getOwnerType());
assertEquals("ic_field-name2", implicitCollection.getFieldName());
assertNull(implicitCollection.getItemFieldName());
assertEquals("ic_item-type2", implicitCollection.getItemType());
// test ommited fields
List fields = config.getOmmitedFields();
assertNotNull(fields);
assertEquals(2, fields.size());
OmmitedField ommitedField = (OmmitedField) fields.get(0);
assertEquals("ommited-field_type1", ommitedField.getType());
assertEquals("ommited-field_field1", ommitedField.getFieldName());
ommitedField = (OmmitedField) fields.get(1);
assertEquals("ommited-field_type2", ommitedField.getType());
assertEquals("ommited-field_field2", ommitedField.getFieldName());
// test immutable types
List types = config.getImmutableTypes();
assertNotNull(types);
assertEquals(2, types.size());
assertEquals("immutable-type1", types.get(0));
assertEquals("immutable-type2", types.get(1));
// test default implementations
List implementations = config.getDefaultImplementations();
assertNotNull(implementations);
assertEquals(2, implementations.size());
DefaultImplementation defaultImplementation = (DefaultImplementation) implementations.get(0);
assertEquals("default-implementation1", defaultImplementation.getDefaultImpl());
assertEquals("type1", defaultImplementation.getType());
defaultImplementation = (DefaultImplementation) implementations.get(1);
assertEquals("default-implementation2", defaultImplementation.getDefaultImpl());
assertEquals("type2", defaultImplementation.getType());
// test mappings
List mappings = config.getMappings();
assertNotNull(mappings);
assertEquals(2, mappings.size());
Mapping mapping = (Mapping) mappings.get(0);
assertEquals("uri1", mapping.getNamespaceURI());
assertEquals("localpart1", mapping.getLocalPart());
assertEquals("prefix1", mapping.getPrefix());
assertEquals("classname1", mapping.getClassName());
mapping = (Mapping) mappings.get(1);
assertEquals("uri2", mapping.getNamespaceURI());
assertEquals("localpart2", mapping.getLocalPart());
assertEquals("prefix2", mapping.getPrefix());
assertEquals("classname2", mapping.getClassName());
}
/**
* Test getXStreamConfiguration with non-existing config file.
* @throws Exception
*/
public void testNonExistingConfigFile() throws Exception {
// set config file to non-existing file
factory.setConfigFile(new ClassPathResource("nonexisting-xstream-config-file.xml"));
// try to get XStreamConfiguration
try {
factory.afterPropertiesSet();
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(true);
}
}
}

View File

@@ -1,901 +0,0 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed 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.springframework.batch.io.xml.xstream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.io.exception.BatchEnvironmentException;
import org.springframework.batch.io.xml.ObjectInput;
import org.springframework.batch.io.xml.ObjectOutput;
import org.springframework.batch.io.xml.xstream.AttributeAlias;
import org.springframework.batch.io.xml.xstream.AttributeProperties;
import org.springframework.batch.io.xml.xstream.ClassAlias;
import org.springframework.batch.io.xml.xstream.DefaultImplementation;
import org.springframework.batch.io.xml.xstream.FieldAlias;
import org.springframework.batch.io.xml.xstream.ImplicitCollection;
import org.springframework.batch.io.xml.xstream.OmmitedField;
import org.springframework.batch.io.xml.xstream.TypeAlias;
import org.springframework.batch.io.xml.xstream.XStreamConfiguration;
import org.springframework.batch.io.xml.xstream.XStreamFactory;
import org.springframework.core.io.FileSystemResource;
import com.thoughtworks.xstream.XStream;
/**
* Integretion test for XStreamFactory.
*
* @author peter.zozom
*/
public class XStreamFactoryIntegrationTests extends TestCase {
private XStream stream;
private XStreamConfiguration config;
private XStreamFactory factory;
public void testAddDefaultImplementations() throws ClassNotFoundException {
// override tested methods
class XStreamExt extends XStream {
private String diName;
private String otName;
private boolean test = false;
public void init(String diName, String otName) {
test = true;
this.diName = diName;
this.otName = otName;
}
public void addDefaultImplementation(Class defaultImplementation, Class ofType) {
if (test) {
assertEquals(diName, defaultImplementation.getName());
assertEquals(otName, ofType.getName());
}
}
}
// TEST1: test adding default implementation
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("java.util.ArrayList", "java.util.List");
// create DefaultImplemetation object
DefaultImplementation di = new DefaultImplementation();
di.setDefaultImpl("java.util.ArrayList");
di.setType("java.util.List");
// add it to list of defaultImplementations
List defaultImplementations = new ArrayList();
defaultImplementations.add(di);
// create configuration object
config = new XStreamConfiguration();
// set list of defaultImplementations
config.setDefaultImplementations(defaultImplementations);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: ClassNotFoundException for 'defaultImplementation' parameter
// set defaultImplementation class name to some non-existing class name
di.setDefaultImpl("test.some.nonexisting.ClassName");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
// TEST3: ClassNotFoundException for 'ofType' parameter
// set ofType class name to some non-existing class name
di.setType("test.some.nonexisting.ClassName");
di.setDefaultImpl("java.util.List");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testSetClassAliases() {
// override tested methods
class XStreamExt extends XStream {
private String shortName;
private String typeName;
private String diName;
private boolean test;
public void init(String shortName, String typeName, String diName) {
test = true;
this.shortName = shortName;
this.typeName = typeName;
this.diName = diName;
}
public void alias(String name, Class type, Class defaultImplementation) {
if (test) {
assertEquals(shortName, name);
assertEquals(typeName, type.getName());
assertEquals(diName, defaultImplementation.getName());
}
}
public void alias(String name, Class type) {
if (test) {
assertEquals(shortName, name);
assertEquals(typeName, type.getName());
}
}
}
// TEST1: test setting class alias with method alias(String,Class,Class)
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("testAlias", "java.util.List", "java.util.ArrayList");
// create classAlias
ClassAlias classAlias = new ClassAlias();
classAlias.setName("testAlias");
classAlias.setType("java.util.List");
classAlias.setDefaultImplementation("java.util.ArrayList");
// add it to the list of aliases
List classAliases = new ArrayList();
classAliases.add(classAlias);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setClassAliases(classAliases);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: test setting class alias with method alias(String,Class)
classAlias.setDefaultImplementation(null);
factory.setUpXStream(stream);
// TEST3: ClassNotFoundException for 'defaultImplementation' parameter
classAlias.setDefaultImplementation("test.some.nonexisting.ClassName");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
// TEST4: ClassNotFoundException for 'type' parameter
classAlias.setDefaultImplementation(null);
classAlias.setType("test.some.nonexisting.ClassName");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testSetTypeAliases() {
// override tested methods
class XStreamExt extends XStream {
private String shortName;
private String typeName;
private boolean test;
public void init(String shortName, String typeName) {
test = true;
this.shortName = shortName;
this.typeName = typeName;
}
public void aliasType(String name, Class type) {
if (test) {
assertEquals(shortName, name);
assertEquals(typeName, type.getName());
}
}
}
// TEST1: test setting type alias with method alias(String,Class)
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("testAlias", "java.util.List");
// create classAlias
TypeAlias typeAlias = new TypeAlias();
typeAlias.setName("testAlias");
typeAlias.setType("java.util.List");
// add it to the list of aliases
List typeAliases = new ArrayList();
typeAliases.add(typeAlias);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setTypeAliases(typeAliases);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: ClassNotFoundException for 'type' parameter
typeAlias.setType("test.some.nonexisting.ClassName");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testSetFieldAliases() {
// override tested methods
class XStreamExt extends XStream {
private String aliasName;
private String typeName;
private String fieldName;
private boolean test;
public void init(String aliasName, String typeName, String fieldName) {
test = true;
this.aliasName = aliasName;
this.typeName = typeName;
this.fieldName = fieldName;
}
public void aliasField(String aliasName, Class type, String fieldName) {
if (test) {
assertEquals(this.aliasName, aliasName);
assertEquals(typeName, type.getName());
assertEquals(this.fieldName, fieldName);
}
}
}
// TEST1: test setting type alias with method alias(String,Class)
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("testAlias", "java.util.List", "list");
// create classAlias
FieldAlias fieldAlias = new FieldAlias();
fieldAlias.setAliasName("testAlias");
fieldAlias.setType("java.util.List");
fieldAlias.setFieldName("list");
// add it to the list of aliases
List fieldAliases = new ArrayList();
fieldAliases.add(fieldAlias);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setFieldAliases(fieldAliases);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: ClassNotFoundException for 'type' parameter
fieldAlias.setType("test.some.nonexisting.ClassName");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testSetAttributeAliases() {
// override tested methods
class XStreamExt extends XStream {
private String alias;
private String attributeName;
private boolean test = false;
public void init(String alias, String attributeName) {
test = true;
this.alias = alias;
this.attributeName = attributeName;
}
public void aliasAttribute(String alias, String attributeName) {
if (test) {
assertEquals(this.alias, alias);
assertEquals(this.attributeName, attributeName);
}
}
}
// TEST1: test adding attribute aliases
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("alias", "attribute");
AttributeAlias alias = new AttributeAlias();
alias.setAlias("alias");
alias.setAttributeName("attribute");
List aliases = new ArrayList();
aliases.add(alias);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setAttributeAliases(aliases);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
}
public void testSetAttributes() {
// override tested methods
class XStreamExt extends XStream {
private String type;
private String fieldName;
private boolean test = false;
public void init(String type, String fieldName) {
test = true;
this.type = type;
this.fieldName = fieldName;
}
public void useAttributeFor(Class type) {
if (test) {
assertEquals(this.type, type.getName());
}
}
public void useAttributeFor(String fieldName, Class type) {
if (test) {
assertEquals(this.fieldName, fieldName);
assertEquals(this.type, type.getName());
}
}
}
// TEST1: test adding attribute properties with
// useAttributeFor(String,Class)
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("java.util.List", "fieldName");
AttributeProperties props = new AttributeProperties();
props.setFieldName("fieldName");
props.setType("java.util.List");
List properties = new ArrayList();
properties.add(props);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setAttributes(properties);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: test adding attribute properties with useAttributeFor(String)
props.setFieldName(null);
factory.setUpXStream(stream);
// TEST3: ClassNotFoundException for 'type' parameter
props.setType("test.some.nonexisting.ClassName");
// call set-up method for XStream - BatchEnvironmentException is
// expected
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
// TODO different results for JDK1.4 and JDK1.5
// public void testRegisterConverters() {
//
// // override tested methods
// class XStreamExt extends XStream {
//
// private String className;
//
// private int priority;
//
// private boolean test = false;
//
// public void init(String className, int priority) {
// test = true;
// this.className = className;
// this.priority = priority;
// }
//
// public void registerConverter(Converter converter, int priority) {
// if (test) {
// assertEquals(className, converter.getClass().getName());
// assertEquals(this.priority, priority);
// }
// }
//
// public void registerConverter(SingleValueConverter converter, int priority) {
// if (test) {
// assertEquals(className, converter.getClass().getName());
// assertEquals(this.priority, priority);
// }
// }
// }
//
// // TEST1: test registering single value converter
//
// // create new XStream
// stream = new XStreamExt();
// // set expected values
// ((XStreamExt) stream).init("com.thoughtworks.xstream.converters.basic.FloatConverter", 10);
//
// ConverterProperties cp = new ConverterProperties();
// cp.setConverterClassName("com.thoughtworks.xstream.converters.basic.FloatConverter");
// cp.setPriority(10);
//
// List converters = new ArrayList();
// converters.add(cp);
//
// // create configuration object
// config = new XStreamConfiguration();
// // set list of classAliases
// config.setConverters(converters);
//
// // create factory
// factory = new XStreamFactory();
// // set config object
// factory.setConfig(config);
// // call set-up method for XStream
// factory.setUpXStream(stream);
//
// // TEST2: test registering converter
// cp.setConverterClassName("com.thoughtworks.xstream.converters.basic.NullConverter");
// ((XStreamExt) stream).init("com.thoughtworks.xstream.converters.basic.NullConverter", 10);
// factory.setUpXStream(stream);
//
// // TEST3: BatchEnviromentException due to invalid type (not assignable
// // to SingleValueConverter or Converter)
// cp.setConverterClassName("java.util.List");
// try {
// factory.setUpXStream(stream);
// fail("BatchEnvironmentException was expected");
// }
// catch (BatchEnvironmentException bee) {
// assertNull(bee.getCause());
// }
//
// // TEST4: ClassNotFoundException
// cp.setConverterClassName("test.some.nonexisting.ClassName");
// try {
// factory.setUpXStream(stream);
// fail("BatchEnvironmentException was expected");
// }
// catch (BatchEnvironmentException bee) {
// assertTrue(bee.getCause() instanceof ClassNotFoundException);
// }
//
// // TEST5: InstantiationException
// // set interface as className
// cp.setConverterClassName("com.thoughtworks.xstream.converters.Converter");
// try {
// factory.setUpXStream(stream);
// fail("BatchEnvironmentException was expected");
// }
// catch (BatchEnvironmentException bee) {
// assertTrue(bee.getCause() instanceof InstantiationException);
// }
// }
public void testSetMode() {
// override tested methods
class XStreamExt extends XStream {
private int mode;
private boolean test = false;
public void init(int mode) {
test = true;
this.mode = mode;
}
public void setMode(int mode) {
if (test) {
assertEquals(this.mode, mode);
}
}
}
// create new XStream
stream = new XStreamExt();
((XStreamExt) stream).init(1001);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setMode(1001);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
}
public void testAddImplicitCollections() {
// override tested methods
class XStreamExt extends XStream {
private String ownerType;
private String fieldName;
private String itemFieldName;
private String itemType;
private boolean test = false;
/*
* Set expected values
*/
public void init(String ownerType, String fieldName, String itemFieldName, String itemType) {
test = true;
this.ownerType = ownerType;
this.fieldName = fieldName;
this.itemFieldName = itemFieldName;
this.itemType = itemType;
}
public void addImplicitCollection(Class ownerType, String fieldName, Class itemType) {
if (test) {
assertEquals(this.ownerType, ownerType.getName());
assertEquals(this.fieldName, fieldName);
assertEquals(this.itemType, itemType.getName());
}
}
public void addImplicitCollection(Class ownerType, String fieldName, String itemFieldName, Class itemType) {
if (test) {
assertEquals(this.ownerType, ownerType.getName());
assertEquals(this.fieldName, fieldName);
assertEquals(this.itemFieldName, itemFieldName);
assertEquals(this.itemType, itemType.getName());
}
}
public void addImplicitCollection(Class ownerType, String fieldName) {
if (test) {
assertEquals(this.ownerType, ownerType.getName());
assertEquals(this.fieldName, fieldName);
}
}
}
// create new XStream
stream = new XStreamExt();
((XStreamExt) stream).init("java.util.List", "fieldName", "itemFieldName", "java.util.Map");
// TEST1: test adding implicit collection with
// addImplicitCollection(Class, String)
ImplicitCollection implicitCollection = new ImplicitCollection();
implicitCollection.setOwnerType("java.util.List");
implicitCollection.setFieldName("fieldName");
List implicitCollections = new ArrayList();
implicitCollections.add(implicitCollection);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setImplicitCollections(implicitCollections);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: test adding implicit collection with
// addImplicitCollection(Class, String, String)
implicitCollection.setItemType("java.util.Map");
factory.setUpXStream(stream);
// TEST3: test adding implicit collection with
// addImplicitCollection(Class, String, String, String)
implicitCollection.setItemFieldName("itemFieldName");
factory.setUpXStream(stream);
// TEST4: ClassNotFoundException due to non-existing class name in
// itemType
implicitCollection.setItemType("test.some.nonexisting.ClassName");
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
// TEST5: ClassNotFoundException due to non-existing class name in
// ownerType
implicitCollection.setOwnerType("test.some.nonexisting.ClassName");
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testSetOmittedFields() {
// override tested methods
class XStreamExt extends XStream {
private String type;
private String fieldName;
private boolean test = false;
public void init(String type, String fieldName) {
test = true;
this.type = type;
this.fieldName = fieldName;
}
public void omitField(Class type, String fieldName) {
if (test) {
assertEquals(this.type, type.getName());
assertEquals(this.fieldName, fieldName);
}
}
}
// TEST1: test adding ommited fields
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("java.util.List", "fieldName");
OmmitedField ommitedField = new OmmitedField();
ommitedField.setType("java.util.List");
ommitedField.setFieldName("fieldName");
List ommitedFields = new ArrayList();
ommitedFields.add(ommitedField);
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setOmmitedFields(ommitedFields);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: ClassNotFoundException
ommitedField.setType("test.some.nonexisting.ClassName");
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testAddImmutableTypes() {
// override tested methods
class XStreamExt extends XStream {
private String type;
private boolean test = false;
public void init(String type) {
test = true;
this.type = type;
}
public void addImmutableType(Class type) {
if (test) {
assertEquals(this.type, type.getName());
}
}
}
// create new XStream
stream = new XStreamExt();
// set expected values
((XStreamExt) stream).init("java.util.List");
List immutableTypes = new ArrayList();
immutableTypes.add("java.util.List");
// create configuration object
config = new XStreamConfiguration();
// set list of classAliases
config.setImmutableTypes(immutableTypes);
// create factory
factory = new XStreamFactory();
// set config object
factory.setConfig(config);
// call set-up method for XStream
factory.setUpXStream(stream);
// TEST2: ClassNotFoundException
immutableTypes.clear();
immutableTypes.add("test.some.nonexisting.ClassName");
try {
factory.setUpXStream(stream);
fail("BatchEnvironmentException was expected");
}
catch (BatchEnvironmentException bee) {
assertTrue(bee.getCause() instanceof ClassNotFoundException);
}
}
public void testWriteAndRead() throws IOException, ClassNotFoundException {
// create file
File file = File.createTempFile("test", ".xml");
// create factory and set empty configuration
XStreamFactory factory = new XStreamFactory();
factory.setConfig(new XStreamConfiguration());
// define test class
class TestValueObject {
String param1;
int param2;
Long param3;
}
TestValueObject valueObject = new TestValueObject();
valueObject.param1 = "test";
valueObject.param2 = 392;
valueObject.param3 = new Long(632);
// just a simple test for object output and input: write object to XML
// and read it back
ObjectOutput output = factory.createObjectOutput(new FileSystemResource(file), "UTF-8");
output.writeObject(valueObject);
output.close();
ObjectInput input = factory.createObjectInput(new FileSystemResource(file), "UTF-8");
Object result = input.readObject();
input.close();
file.delete();
// is result instance of TestValueObject?
assertTrue(result instanceof TestValueObject);
// is result equal to written object?
assertEquals(valueObject.param1, ((TestValueObject) result).param1);
assertEquals(valueObject.param2, ((TestValueObject) result).param2);
assertEquals(valueObject.param3, ((TestValueObject) result).param3);
}
}