Bringing the LDIF based ItemReader from Spring LDAP to Spring Batch to break circular dependency
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2005-2014 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.item.ldif;
|
||||
|
||||
import org.springframework.batch.item.file.transform.LineAggregator;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
|
||||
/**
|
||||
* The {@link LdifAggregator LdifAggregator} object is an implementation of the {@link org.springframework.batch.item.file.transform.LineAggregator LineAggregator}
|
||||
* interface for use with a {@link org.springframework.batch.item.file.FlatFileItemWriter FlatFileItemWriter} to write LDIF records to a file.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class LdifAggregator implements LineAggregator<LdapAttributes> {
|
||||
|
||||
/**
|
||||
* Returns a {@link java.lang.String String} containing a properly formated LDIF.
|
||||
*
|
||||
* @param item LdapAttributes object to convert to string.
|
||||
* @return string representation of the object LDIF format (in accordance with RFC 2849).
|
||||
*/
|
||||
public String aggregate(LdapAttributes item) {
|
||||
return item.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2005-2014 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.item.ldif;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream;
|
||||
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
import org.springframework.ldap.ldif.parser.LdifParser;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* The {@link LdifReader LdifReader} is an adaptation of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}
|
||||
* built around an {@link LdifParser LdifParser}.
|
||||
* <p>
|
||||
* Unlike the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link LdifReader LdifReader}
|
||||
* does not require a mapper. Instead, this version of the {@link LdifReader LdifReader} simply returns an {@link LdapAttributes LdapAttributes}
|
||||
* object which can be consumed and manipulated as necessary by {@link org.springframework.batch.item.ItemProcessor ItemProcessor} or any
|
||||
* output service. Alternatively, the {@link RecordMapper RecordMapper} interface can be implemented and set in a
|
||||
* {@link MappingLdifReader MappingLdifReader} to map records to objects for return.
|
||||
* <p>
|
||||
* {@link LdifReader LdifReader} usage is mimics that of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}
|
||||
* for all intensive purposes. Adjustments have been made to process records instead of lines, however. As such, the
|
||||
* {@link #recordsToSkip recordsToSkip} attribute indicates the number of records from the top of the file that should not be processed.
|
||||
* Implementations of the {@link RecordCallbackHandler RecordCallbackHandler} interface can be used to execute operations on those skipped records.
|
||||
* <p>
|
||||
* As with the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link #strict strict} option differentiates
|
||||
* between whether or not to require the resource to exist before processing. In the case of a value set to false, a warning is logged instead of
|
||||
* an exception being thrown.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class LdifReader extends AbstractItemCountingItemStreamItemReader<LdapAttributes>
|
||||
implements ResourceAwareItemReaderItemStream<LdapAttributes>, InitializingBean {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LdifReader.class);
|
||||
|
||||
private Resource resource;
|
||||
|
||||
private LdifParser ldifParser;
|
||||
|
||||
private int recordCount = 0;
|
||||
|
||||
private int recordsToSkip = 0;
|
||||
|
||||
private boolean strict = true;
|
||||
|
||||
private RecordCallbackHandler skippedRecordsCallback;
|
||||
|
||||
public LdifReader() {
|
||||
setName(ClassUtils.getShortName(LdifReader.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* In strict mode the reader will throw an exception on
|
||||
* {@link #open(org.springframework.batch.item.ExecutionContext)} if the
|
||||
* input resource does not exist.
|
||||
* @param strict false by default
|
||||
*/
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RecordCallbackHandler RecordCallbackHandler} implementations can be used to take action on skipped records.
|
||||
*
|
||||
* @param skippedRecordsCallback will be called for each one of the initial
|
||||
* skipped lines before any items are read.
|
||||
*/
|
||||
public void setSkippedRecordsCallback(RecordCallbackHandler skippedRecordsCallback) {
|
||||
this.skippedRecordsCallback = skippedRecordsCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the number of lines to skip at the start of a file. Can
|
||||
* be used if the file contains a header without useful (column name)
|
||||
* information, and without a comment delimiter at the beginning of the
|
||||
* lines.
|
||||
*
|
||||
* @param recordsToSkip the number of lines to skip
|
||||
*/
|
||||
public void setRecordsToSkip(int recordsToSkip) {
|
||||
this.recordsToSkip = recordsToSkip;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() throws Exception {
|
||||
if (ldifParser != null) {
|
||||
ldifParser.close();
|
||||
}
|
||||
this.recordCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOpen() throws Exception {
|
||||
if (resource == null)
|
||||
throw new IllegalStateException("A resource has not been set.");
|
||||
|
||||
if (!resource.exists()) {
|
||||
if (strict) {
|
||||
throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): "+resource);
|
||||
} else {
|
||||
LOG.warn("Input resource does not exist " + resource.getDescription());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ldifParser.open();
|
||||
|
||||
for (int i = 0; i < recordsToSkip; i++) {
|
||||
LdapAttributes record = ldifParser.getRecord();
|
||||
if (skippedRecordsCallback != null) {
|
||||
skippedRecordsCallback.handleRecord(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LdapAttributes doRead() throws Exception {
|
||||
LdapAttributes attributes = null;
|
||||
|
||||
try {
|
||||
if (ldifParser != null) {
|
||||
while (attributes == null && ldifParser.hasMoreRecords()) {
|
||||
attributes = ldifParser.getRecord();
|
||||
}
|
||||
recordCount++;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
|
||||
} catch(Exception ex){
|
||||
LOG.error("Parsing error at record " + recordCount + " in resource=" +
|
||||
resource.getDescription() + ", input=[" + attributes + "]", ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public void setResource(Resource resource) {
|
||||
this.resource = resource;
|
||||
this.ldifParser = new LdifParser(resource);
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(resource, "A resource is required to parse.");
|
||||
Assert.notNull(ldifParser);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2005-2014 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.item.ldif;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream;
|
||||
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
import org.springframework.ldap.ldif.parser.LdifParser;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* The {@link MappingLdifReader MappingLdifReader} is an adaptation of the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}
|
||||
* built around an {@link LdifParser LdifParser}. It differs from the standard {@link LdifReader LdifReader} in its ability to map
|
||||
* {@link LdapAttributes LdapAttributes} objects to POJOs.
|
||||
* <p>
|
||||
* The {@link MappingLdifReader MappingLdifReader} <i>requires</i> an {@link RecordMapper RecordMapper} implementation. If mapping
|
||||
* is not required, the {@link LdifReader LdifReader} should be used instead. It simply returns an {@link LdapAttributes LdapAttributes}
|
||||
* object which can be consumed and manipulated as necessary by {@link org.springframework.batch.item.ItemProcessor ItemProcessor} or any
|
||||
* output service.
|
||||
* <p>
|
||||
* {@link LdifReader LdifReader} usage is mimics that of the FlatFileItemReader for all intensive purposes. Adjustments have been made to
|
||||
* process records instead of lines, however. As such, the {@link #recordsToSkip recordsToSkip} attribute indicates the number of records
|
||||
* from the top of the file that should not be processed. Implementations of the {@link RecordCallbackHandler RecordCallbackHandler}
|
||||
* interface can be used to execute operations on those skipped records.
|
||||
* <p>
|
||||
* As with the {@link org.springframework.batch.item.file.FlatFileItemReader FlatFileItemReader}, the {@link #strict strict} option
|
||||
* differentiates between whether or not to require the resource to exist before processing. In the case of a value set to false, a warning
|
||||
* is logged instead of an exception being thrown.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class MappingLdifReader<T> extends AbstractItemCountingItemStreamItemReader<T>
|
||||
implements ResourceAwareItemReaderItemStream<T>, InitializingBean {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MappingLdifReader.class);
|
||||
|
||||
private Resource resource;
|
||||
|
||||
private LdifParser ldifParser;
|
||||
|
||||
private int recordCount = 0;
|
||||
|
||||
private int recordsToSkip = 0;
|
||||
|
||||
private boolean strict = true;
|
||||
|
||||
private RecordCallbackHandler skippedRecordsCallback;
|
||||
|
||||
private RecordMapper<T> recordMapper;
|
||||
|
||||
public MappingLdifReader() {
|
||||
setName(ClassUtils.getShortName(MappingLdifReader.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* In strict mode the reader will throw an exception on
|
||||
* {@link #open(org.springframework.batch.item.ExecutionContext)} if the
|
||||
* input resource does not exist.
|
||||
* @param strict false by default
|
||||
*/
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RecordCallbackHandler RecordCallbackHandler} implementations can be used to take action on skipped records.
|
||||
*
|
||||
* @param skippedRecordsCallback will be called for each one of the initial
|
||||
* skipped lines before any items are read.
|
||||
*/
|
||||
public void setSkippedRecordsCallback(RecordCallbackHandler skippedRecordsCallback) {
|
||||
this.skippedRecordsCallback = skippedRecordsCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the number of lines to skip at the start of a file. Can
|
||||
* be used if the file contains a header without useful (column name)
|
||||
* information, and without a comment delimiter at the beginning of the
|
||||
* lines.
|
||||
*
|
||||
* @param recordsToSkip the number of lines to skip
|
||||
*/
|
||||
public void setRecordsToSkip(int recordsToSkip) {
|
||||
this.recordsToSkip = recordsToSkip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for object mapper. This property is required to be set.
|
||||
* @param recordMapper maps record to an object
|
||||
*/
|
||||
public void setRecordMapper(RecordMapper<T> recordMapper) {
|
||||
this.recordMapper = recordMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() throws Exception {
|
||||
if (ldifParser != null) {
|
||||
ldifParser.close();
|
||||
}
|
||||
this.recordCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOpen() throws Exception {
|
||||
if (resource == null)
|
||||
throw new IllegalStateException("A resource has not been set.");
|
||||
|
||||
if (!resource.exists()) {
|
||||
if (strict) {
|
||||
throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): "+resource);
|
||||
} else {
|
||||
LOG.warn("Input resource does not exist " + resource.getDescription());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ldifParser.open();
|
||||
|
||||
for (int i = 0; i < recordsToSkip; i++) {
|
||||
LdapAttributes record = ldifParser.getRecord();
|
||||
if (skippedRecordsCallback != null) {
|
||||
skippedRecordsCallback.handleRecord(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T doRead() throws Exception {
|
||||
LdapAttributes attributes = null;
|
||||
|
||||
try {
|
||||
if (ldifParser != null) {
|
||||
while (attributes == null && ldifParser.hasMoreRecords()) {
|
||||
attributes = ldifParser.getRecord();
|
||||
}
|
||||
recordCount++;
|
||||
return recordMapper.mapRecord(attributes);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch(Exception ex){
|
||||
LOG.error("Parsing error at record " + recordCount + " in resource=" +
|
||||
resource.getDescription() + ", input=[" + attributes + "]", ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public void setResource(Resource resource) {
|
||||
this.resource = resource;
|
||||
this.ldifParser = new LdifParser(resource);
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(resource, "A resource is required to parse.");
|
||||
Assert.notNull(ldifParser);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2005-2014 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.item.ldif;
|
||||
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
|
||||
/**
|
||||
* This interface can be used to operate on skipped records in the {@link LdifReader LdifReader} and the
|
||||
* {@link MappingLdifReader MappingLdifReader}.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public interface RecordCallbackHandler {
|
||||
|
||||
/**
|
||||
* Execute operations on the supplied record.
|
||||
*
|
||||
* @param attributes
|
||||
*/
|
||||
void handleRecord(LdapAttributes attributes);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2005-2014 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.item.ldif;
|
||||
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
|
||||
/**
|
||||
* This interface should be implemented to map {@link LdapAttributes LdapAttributes} objects to POJOs. The resulting
|
||||
* implementations can be used in the {@link MappingLdifReader MappingLdifReader}.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface RecordMapper<T> {
|
||||
|
||||
/**
|
||||
* Maps an {@link LdapAttributes LdapAttributes} object to the specified type.
|
||||
*
|
||||
* @param attributes
|
||||
* @return object of type T
|
||||
*/
|
||||
T mapRecord(LdapAttributes attributes);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* <p>This package contains the classes required for using the LdifParser in Spring LDAP.</p>
|
||||
*
|
||||
* @author Michael Minella
|
||||
*/
|
||||
package org.springframework.batch.item.ldif;
|
||||
Reference in New Issue
Block a user