Bringing the LDIF based ItemReader from Spring LDAP to Spring Batch to break circular dependency
This commit is contained in:
@@ -107,10 +107,6 @@
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency> -->
|
||||
<!-- <groupId>org.easymock</groupId> -->
|
||||
<!-- <artifactId>easymock</artifactId> -->
|
||||
<!-- </dependency> -->
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
@@ -137,6 +133,11 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-ldif-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.core.test.ldif;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/applicationContext-test1.xml"})
|
||||
public class LdifReaderTests {
|
||||
private static Logger log = LoggerFactory.getLogger(LdifReaderTests.class);
|
||||
|
||||
private Resource expected;
|
||||
private Resource actual;
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
private Job job;
|
||||
|
||||
public LdifReaderTests() {
|
||||
try {
|
||||
expected = new UrlResource("file:src/test/resources/expectedOutput.ldif");
|
||||
actual = new UrlResource("file:target/test-outputs/output.ldif");
|
||||
} catch (MalformedURLException e) {
|
||||
log.error("Unexpected error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void checkFiles() {
|
||||
Assert.isTrue(expected.exists(), "Expected does not exist.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidRun() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
|
||||
|
||||
//Ensure job completed successfully.
|
||||
Assert.isTrue(jobExecution.getExitStatus().equals(ExitStatus.COMPLETED), "Step Execution did not complete normally: " + jobExecution.getExitStatus());
|
||||
|
||||
//Check output.
|
||||
Assert.isTrue(actual.exists(), "Actual does not exist.");
|
||||
Assert.isTrue(compareFiles(expected.getFile(), actual.getFile()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceNotExists() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
|
||||
|
||||
Assert.isTrue(jobExecution.getExitStatus().getExitCode().equals("FAILED"), "The job exit status is not FAILED.");
|
||||
Assert.isTrue(jobExecution.getExitStatus().getExitDescription().contains("Failed to initialize the reader"), "The job failed for the wrong reason.");
|
||||
}
|
||||
|
||||
private boolean compareFiles(File expected, File actual) throws Exception {
|
||||
boolean equal = true;
|
||||
|
||||
FileInputStream expectedStream = new FileInputStream(expected);
|
||||
FileInputStream actualStream = new FileInputStream(actual);
|
||||
|
||||
//Construct BufferedReader from InputStreamReader
|
||||
BufferedReader expectedReader = new BufferedReader(new InputStreamReader(expectedStream));
|
||||
BufferedReader actualReader = new BufferedReader(new InputStreamReader(actualStream));
|
||||
|
||||
String line = null;
|
||||
while ((line = expectedReader.readLine()) != null) {
|
||||
if(!line.equals(actualReader.readLine())) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(actualReader.readLine() != null) {
|
||||
equal = false;
|
||||
}
|
||||
|
||||
expectedReader.close();
|
||||
|
||||
return equal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.core.test.ldif;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/applicationContext-test2.xml"})
|
||||
public class MappingLdifReaderTests {
|
||||
private static Logger log = LoggerFactory.getLogger(MappingLdifReaderTests.class);
|
||||
|
||||
private Resource expected;
|
||||
private Resource actual;
|
||||
|
||||
@Autowired
|
||||
private JobLauncher launcher;
|
||||
|
||||
@Autowired
|
||||
private Job job;
|
||||
|
||||
public MappingLdifReaderTests() {
|
||||
try {
|
||||
expected = new UrlResource("file:src/test/resources/expectedOutput.ldif");
|
||||
actual = new UrlResource("file:target/test-outputs/output.ldif");
|
||||
} catch (MalformedURLException e) {
|
||||
log.error("Unexpected error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void checkFiles() {
|
||||
Assert.isTrue(expected.exists(), "Expected does not exist.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidRun() throws Exception {
|
||||
JobExecution jobExecution = launcher.run(job, new JobParameters());
|
||||
|
||||
//Ensure job completed successfully.
|
||||
Assert.isTrue(jobExecution.getExitStatus().equals(ExitStatus.COMPLETED), "Step Execution did not complete normally: " + jobExecution.getExitStatus());
|
||||
|
||||
//Check output.
|
||||
Assert.isTrue(actual.exists(), "Actual does not exist.");
|
||||
Assert.isTrue(compareFiles(expected.getFile(), actual.getFile()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceNotExists() throws Exception {
|
||||
JobExecution jobExecution = launcher.run(job, new JobParameters());
|
||||
|
||||
Assert.isTrue(jobExecution.getExitStatus().getExitCode().equals("FAILED"), "The job exit status is not FAILED.");
|
||||
Assert.isTrue(jobExecution.getExitStatus().getExitDescription().contains("Failed to initialize the reader"), "The job failed for the wrong reason.");
|
||||
}
|
||||
|
||||
|
||||
private boolean compareFiles(File expected, File actual) throws Exception {
|
||||
boolean equal = true;
|
||||
|
||||
FileInputStream expectedStream = new FileInputStream(expected);
|
||||
FileInputStream actualStream = new FileInputStream(actual);
|
||||
|
||||
//Construct BufferedReader from InputStreamReader
|
||||
BufferedReader expectedReader = new BufferedReader(new InputStreamReader(expectedStream));
|
||||
BufferedReader actualReader = new BufferedReader(new InputStreamReader(actualStream));
|
||||
|
||||
String line = null;
|
||||
while ((line = expectedReader.readLine()) != null) {
|
||||
if(!line.equals(actualReader.readLine())) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(actualReader.readLine() != null) {
|
||||
equal = false;
|
||||
}
|
||||
|
||||
expectedReader.close();
|
||||
|
||||
return equal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.core.test.ldif;
|
||||
|
||||
import org.springframework.batch.item.ldif.RecordMapper;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
|
||||
/**
|
||||
* This default implementation simply returns the LdapAttributes object and is only intended for test. As its not required
|
||||
* to return an object of a specific type to make the MappingLdifReader implementation work, this basic setting is sufficient
|
||||
* to demonstrate its function.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class MyMapper implements RecordMapper<LdapAttributes> {
|
||||
|
||||
public LdapAttributes mapRecord(LdapAttributes attributes) {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:batch="http://www.springframework.org/schema/batch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
|
||||
|
||||
<batch:job id="job">
|
||||
<batch:step id="step1" next="step2">
|
||||
<batch:tasklet transaction-manager="transactionManager">
|
||||
<batch:chunk reader="itemReader1" writer="itemWriter" commit-interval="2" skip-limit="1">
|
||||
<batch:skippable-exception-classes>org.springframework.ldap.ldif.InvalidAttributeFormatException</batch:skippable-exception-classes>
|
||||
</batch:chunk>
|
||||
</batch:tasklet>
|
||||
</batch:step>
|
||||
<batch:step id="step2">
|
||||
<batch:tasklet transaction-manager="transactionManager">
|
||||
<batch:chunk reader="itemReader2" writer="itemWriter" commit-interval="2" />
|
||||
</batch:tasklet>
|
||||
</batch:step>
|
||||
</batch:job>
|
||||
|
||||
<bean id="itemReader1" class="org.springframework.ldap.ldif.batch.LdifReader">
|
||||
<property name="resource" value="file:src/test/resources/test.ldif" />
|
||||
<property name="recordsToSkip" value="1" />
|
||||
</bean>
|
||||
|
||||
<bean id="itemReader2" class="org.springframework.ldap.ldif.batch.LdifReader">
|
||||
<property name="resource" value="file:src/test/resources/missing.ldif" />
|
||||
<property name="recordsToSkip" value="1" />
|
||||
</bean>
|
||||
|
||||
<bean id="itemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
|
||||
<property name="resource" value="file:target/test-outputs/output.ldif" />
|
||||
<property name="lineAggregator">
|
||||
<bean class="org.springframework.ldap.ldif.batch.LdifAggregator" />
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:batch="http://www.springframework.org/schema/batch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
|
||||
|
||||
<batch:job id="job">
|
||||
<batch:step id="step1" next="step2">
|
||||
<batch:tasklet transaction-manager="transactionManager">
|
||||
<batch:chunk reader="itemReader1" writer="itemWriter" commit-interval="2" skip-limit="1">
|
||||
<batch:skippable-exception-classes>
|
||||
<batch:include class="org.springframework.ldap.ldif.InvalidAttributeFormatException"/>
|
||||
</batch:skippable-exception-classes>
|
||||
</batch:chunk>
|
||||
</batch:tasklet>
|
||||
</batch:step>
|
||||
<batch:step id="step2">
|
||||
<batch:tasklet transaction-manager="transactionManager">
|
||||
<batch:chunk reader="itemReader2" writer="itemWriter" commit-interval="2" />
|
||||
</batch:tasklet>
|
||||
</batch:step>
|
||||
</batch:job>
|
||||
|
||||
<bean id="itemReader1" class="org.springframework.batch.item.ldif.MappingLdifReader">
|
||||
<property name="resource" value="file:src/test/resources/test.ldif" />
|
||||
<property name="recordsToSkip" value="1" />
|
||||
<property name="recordMapper" ref="recordMapper" />
|
||||
</bean>
|
||||
|
||||
<bean id="itemReader2" class="org.springframework.batch.item.ldif.MappingLdifReader">
|
||||
<property name="resource" value="file:src/test/resources/missing.ldif" />
|
||||
<property name="recordsToSkip" value="1" />
|
||||
<property name="recordMapper" ref="recordMapper" />
|
||||
</bean>
|
||||
|
||||
<bean id="recordMapper" class="org.springframework.batch.core.test.ldif.MyMapper" />
|
||||
|
||||
<bean id="itemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
|
||||
<property name="resource" value="file:target/test-outputs/output.ldif" />
|
||||
<property name="lineAggregator">
|
||||
<bean class="org.springframework.batch.item.ldif.LdifAggregator" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
<property name="taskExecutor" ref="taskExecutor" />
|
||||
</bean>
|
||||
|
||||
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<bean id="taskExecutor" class="org.springframework.core.task.SyncTaskExecutor" />
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,74 @@
|
||||
dn: cn=Bjorn Jensen,ou=Accounting,dc=airius,dc=com
|
||||
telephonenumber: +1 408 555 1212
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
sn: Jensen
|
||||
cn: Bjorn Jensen
|
||||
|
||||
dn: cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com
|
||||
telephonenumber: +1 408 555 1212
|
||||
uid: bjensen
|
||||
description: Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions.
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
title: Product Manager, Rod and Reel Division
|
||||
sn: Jensen
|
||||
cn: Barbara Jensen
|
||||
cn: Barbara J Jensen
|
||||
cn: Babs Jensen
|
||||
|
||||
dn: cn=Gern Jensen,ou=Product Testing,dc=airius,dc=com
|
||||
telephonenumber: +1 408 555 1212
|
||||
uid: gernj
|
||||
description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVlIGlzIGJhc2UtNjQtZW5j
|
||||
b2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdGVyIGluIGl0IChhIENSKS4NICBC
|
||||
eSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQgb3V0IG1vcmUu
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
sn: Jensen
|
||||
cn: Gern Jensen
|
||||
cn: Gern O Jensen
|
||||
|
||||
dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
|
||||
ou:: 5Za25qWt6YOo
|
||||
ou:: 44GI44GE44GO44KH44GG44G2
|
||||
ou: Sales
|
||||
description: Japanese office
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
|
||||
dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
|
||||
givenname:: 44Ot44OJ44OL44O8
|
||||
givenname:: 44KN44Gp44Gr44O8
|
||||
givenname: Rodney
|
||||
sn:: 5bCP56yg5Y6f
|
||||
sn:: 44GK44GM44GV44KP44KJ
|
||||
sn: Ogasawara
|
||||
userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
|
||||
mail: rogasawara@airius.co.jp
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
uid: rogasawara
|
||||
preferredlanguage: ja
|
||||
cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
|
||||
cn:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
|
||||
cn: Rodney Ogasawara
|
||||
title:: 5Za25qWt6YOoIOmDqOmVtw==
|
||||
title:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
|
||||
title: Sales, Director
|
||||
|
||||
dn: cn=Horatio Jensen,ou=Product Testing,dc=airius,dc=com
|
||||
telephonenumber: +1 408 555 1212
|
||||
uid: hjensen
|
||||
jpegphoto:< file:///usr/local/directory/photos/hjensen.jpg
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
sn: Jensen
|
||||
cn: Horatio Jensen
|
||||
cn: Horatio N Jensen
|
||||
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
|
||||
|
||||
<import resource="data-source-context.xml" />
|
||||
|
||||
<bean id="jobLauncher"
|
||||
|
||||
235
spring-batch-core-tests/src/test/resources/test.ldif
Normal file
235
spring-batch-core-tests/src/test/resources/test.ldif
Normal file
@@ -0,0 +1,235 @@
|
||||
version: 1
|
||||
|
||||
#
|
||||
#Examples of LDAP Data Interchange Format
|
||||
#
|
||||
|
||||
#
|
||||
#Example 1: An simple LDAP file with two entries
|
||||
#
|
||||
|
||||
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
cn: Barbara Jensen
|
||||
cn: Barbara J Jensen
|
||||
cn: Babs Jensen
|
||||
sn: Jensen
|
||||
uid: bjensen
|
||||
telephonenumber: +1 408 555 1212
|
||||
description: A big sailing fan.
|
||||
|
||||
dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
cn: Bjorn Jensen
|
||||
sn: Jensen
|
||||
telephonenumber: +1 408 555 1212
|
||||
|
||||
|
||||
#
|
||||
# Example 2: A file containing an entry with a folded attribute value
|
||||
#
|
||||
|
||||
dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
|
||||
objectclass:top
|
||||
objectclass:person
|
||||
objectclass:organizationalPerson
|
||||
cn:Barbara Jensen
|
||||
cn:Barbara J Jensen
|
||||
cn:Babs Jensen
|
||||
sn:Jensen
|
||||
uid:bjensen
|
||||
telephonenumber:+1 408 555 1212
|
||||
description:Babs is a big sailing fan, and travels extensively in sea
|
||||
rch of perfect sailing conditions.
|
||||
title:Product Manager, Rod and Reel Division
|
||||
|
||||
#
|
||||
# Example 3: A file containing a base-64-encoded value
|
||||
#
|
||||
|
||||
dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
cn: Gern Jensen
|
||||
cn: Gern O Jensen
|
||||
sn: Jensen
|
||||
uid: gernj
|
||||
telephonenumber: +1 408 555 1212
|
||||
description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl
|
||||
IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG
|
||||
VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg
|
||||
b3V0IG1vcmUu
|
||||
|
||||
|
||||
#
|
||||
# Example 4: A file containing an entries with UTF-8-encoded attribute
|
||||
# values, including language tags. Comments indicate the contents
|
||||
# of UTF-8-encoded attributes and distinguished names.
|
||||
#
|
||||
|
||||
dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
|
||||
# dn:: ou=<JapaneseOU>,o=Airius
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou:: 5Za25qWt6YOo
|
||||
# ou:: <JapaneseOU>
|
||||
ou;lang-ja:: 5Za25qWt6YOo
|
||||
# ou;lang-ja:: <JapaneseOU>
|
||||
ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2
|
||||
# ou;lang-ja:: <JapaneseOU_in_phonetic_representation>
|
||||
ou;lang-en: Sales
|
||||
description: Japanese office
|
||||
|
||||
dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
|
||||
# dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius
|
||||
userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
uid: rogasawara
|
||||
mail: rogasawara@airius.co.jp
|
||||
givenname;lang-ja:: 44Ot44OJ44OL44O8
|
||||
# givenname;lang-ja:: <JapaneseGivenname>
|
||||
sn;lang-ja:: 5bCP56yg5Y6f
|
||||
# sn;lang-ja:: <JapaneseSn>
|
||||
cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
|
||||
# cn;lang-ja:: <JapaneseCn>
|
||||
title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
|
||||
# title;lang-ja:: <JapaneseTitle>
|
||||
preferredlanguage: ja
|
||||
givenname:: 44Ot44OJ44OL44O8
|
||||
# givenname:: <JapaneseGivenname>
|
||||
sn:: 5bCP56yg5Y6f
|
||||
# sn:: <JapaneseSn>
|
||||
cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
|
||||
# cn:: <JapaneseCn>
|
||||
title:: 5Za25qWt6YOoIOmDqOmVtw==
|
||||
# title:: <JapaneseTitle>
|
||||
givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
|
||||
# givenname;lang-ja;phonetic::
|
||||
# <JapaneseGivenname_in_phonetic_representation_kana>
|
||||
sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
|
||||
# sn;lang-ja;phonetic:: <JapaneseSn_in_phonetic_representation_kana>
|
||||
cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
|
||||
# cn;lang-ja;phonetic:: <JapaneseCn_in_phonetic_representation_kana>
|
||||
title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
|
||||
# title;lang-ja;phonetic::
|
||||
# <JapaneseTitle_in_phonetic_representation_kana>
|
||||
givenname;lang-en: Rodney
|
||||
sn;lang-en: Ogasawara
|
||||
cn;lang-en: Rodney Ogasawara
|
||||
title;lang-en: Sales, Director
|
||||
|
||||
|
||||
#
|
||||
# Example 5: An LDIF file containing an invalid attribute
|
||||
#
|
||||
|
||||
dn: cn=Harry Jacobs, ou=Product Development, dc=airius, dc=com
|
||||
objectClass: top
|
||||
objectClass: person
|
||||
cn: Harry Jacobs
|
||||
description: :A big sailing fan.
|
||||
|
||||
|
||||
#
|
||||
# Example 6: A file containing a reference to an external file
|
||||
#
|
||||
|
||||
dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
cn: Horatio Jensen
|
||||
cn: Horatio N Jensen
|
||||
sn: Jensen
|
||||
uid: hjensen
|
||||
telephonenumber: +1 408 555 1212
|
||||
jpegphoto:< file:///usr/local/directory/photos/hjensen.jpg
|
||||
|
||||
|
||||
#
|
||||
# Example 7: A file containing a series of change records and comments
|
||||
#
|
||||
|
||||
# Add a new entry
|
||||
dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
cn: Fiona Jensen
|
||||
sn: Jensen
|
||||
uid: fiona
|
||||
telephonenumber: +1 408 555 1212
|
||||
jpegphoto:< file:///usr/local/directory/photos/fiona.jpg
|
||||
|
||||
# Delete an existing entry
|
||||
dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
|
||||
changetype: delete
|
||||
|
||||
# Modify an entry's relative distinguished name
|
||||
dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
|
||||
changetype: modrdn
|
||||
newrdn: cn=Paula Jensen
|
||||
deleteoldrdn: 1
|
||||
|
||||
# Rename an entry and move all of its children to a new location in
|
||||
# the directory tree (only implemented by LDAPv3 servers).
|
||||
dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
|
||||
changetype: modrdn
|
||||
newrdn: ou=Product Development Accountants
|
||||
deleteoldrdn: 0
|
||||
newsuperior: ou=Accounting, dc=airius, dc=com
|
||||
|
||||
|
||||
# Modify an entry: add an additional value to the postaladdress
|
||||
# attribute, completely delete the description attribute, replace
|
||||
# the telephonenumber attribute with two values, and delete a specific
|
||||
# value from the facsimiletelephonenumber attribute
|
||||
dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
|
||||
changetype: modify
|
||||
add: postaladdress
|
||||
postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
|
||||
-
|
||||
|
||||
delete: description
|
||||
-
|
||||
replace: telephonenumber
|
||||
telephonenumber: +1 408 555 1234
|
||||
telephonenumber: +1 408 555 5678
|
||||
-
|
||||
delete: facsimiletelephonenumber
|
||||
facsimiletelephonenumber: +1 408 555 9876
|
||||
-
|
||||
|
||||
# Modify an entry: replace the postaladdress attribute with an empty
|
||||
# set of values (which will cause the attribute to be removed), and
|
||||
# delete the entire description attribute. Note that the first will
|
||||
# always succeed, while the second will only succeed if at least
|
||||
# one value for the description attribute is present.
|
||||
dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com
|
||||
changetype: modify
|
||||
replace: postaladdress
|
||||
-
|
||||
delete: description
|
||||
-
|
||||
|
||||
|
||||
#
|
||||
# Example 8: An LDIF file containing a change record with a control
|
||||
#
|
||||
|
||||
# Delete an entry. The operation will attach the LDAPv3
|
||||
# Tree Delete Control defined in [9]. The criticality
|
||||
# field is "true" and the controlValue field is
|
||||
# absent, as required by [9].
|
||||
dn: ou=Product Development, dc=airius, dc=com
|
||||
control: 1.2.840.113556.1.4.805 true
|
||||
changetype: delete
|
||||
@@ -245,7 +245,22 @@
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core-tiger</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-ldif-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<scope>test</scope>
|
||||
|
||||
@@ -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;
|
||||
@@ -763,6 +763,24 @@
|
||||
<version>1.0.3.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core-tiger</artifactId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-ldif-core</artifactId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<distributionManagement>
|
||||
|
||||
Reference in New Issue
Block a user