Added Keith Barlow's LDIF parsing framework, including Spring Batch integration.
This commit is contained in:
13
ldif/ldif-batch/.springBeans
Normal file
13
ldif/ldif-batch/.springBeans
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[2.2.6.200908051215-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[false]]></enableImports>
|
||||
<configs>
|
||||
</configs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
</beansProjectDescription>
|
||||
46
ldif/ldif-batch/pom.xml
Normal file
46
ldif/ldif-batch/pom.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-parent-tiger</artifactId>
|
||||
<version>1.3.1.CI-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-ldap-ldif-batch</artifactId>
|
||||
<name>Spring LDAP LDIF Batch</name>
|
||||
<description>Classes for integration with the Spring Batch Framework</description>
|
||||
<properties>
|
||||
<spring-batch.version>2.0.2.RELEASE</spring-batch.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.batch</groupId>
|
||||
<artifactId>spring-batch-core</artifactId>
|
||||
<version>${spring-batch.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.batch</groupId>
|
||||
<artifactId>spring-batch-infrastructure</artifactId>
|
||||
<version>${spring-batch.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.batch</groupId>
|
||||
<artifactId>spring-batch-test</artifactId>
|
||||
<version>${spring-batch.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-ldif-core</artifactId>
|
||||
<version>${version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
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,152 @@
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
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 Log log = LogFactory.getLog(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,162 @@
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
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 Log log = LogFactory.getLog(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,24 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
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,23 @@
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
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,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This package contains the classes required for using the LdifParser with the Spring Batch framework.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.test.AbstractJobTests;
|
||||
import org.springframework.batch.test.AssertFile;
|
||||
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;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations={"classpath*:applicationContext-test1.xml"})
|
||||
public class LdifReaderTest extends AbstractJobTests {
|
||||
private static Log log = LogFactory.getLog(LdifReaderTest.class);
|
||||
|
||||
private Resource expected;
|
||||
private Resource actual;
|
||||
|
||||
public LdifReaderTest() {
|
||||
try {
|
||||
expected = new UrlResource("file:src/test/resources/expectedOutput.ldif");
|
||||
actual = new UrlResource("file:target/test-outputs/output.ldif");
|
||||
} catch (MalformedURLException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void checkFiles() {
|
||||
Assert.isTrue(expected.exists(), "Expected does not exist.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidRun() {
|
||||
try {
|
||||
JobExecution jobExecution = this.launchStep("step1");
|
||||
|
||||
//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.");
|
||||
AssertFile.assertFileEquals(expected.getFile(), actual.getFile());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceNotExists() {
|
||||
JobExecution jobExecution = this.launchStep("step2");
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.test.AbstractJobTests;
|
||||
import org.springframework.batch.test.AssertFile;
|
||||
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;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations={"classpath*:applicationContext-test2.xml"})
|
||||
public class MappingLdifReaderTest extends AbstractJobTests {
|
||||
private static Log log = LogFactory.getLog(MappingLdifReaderTest.class);
|
||||
|
||||
private Resource expected;
|
||||
private Resource actual;
|
||||
|
||||
public MappingLdifReaderTest() {
|
||||
try {
|
||||
expected = new UrlResource("file:src/test/resources/expectedOutput.ldif");
|
||||
actual = new UrlResource("file:target/test-outputs/output.ldif");
|
||||
} catch (MalformedURLException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void checkFiles() {
|
||||
Assert.isTrue(expected.exists(), "Expected does not exist.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidRun() {
|
||||
try {
|
||||
JobExecution jobExecution = this.launchStep("step1");
|
||||
|
||||
//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.");
|
||||
AssertFile.assertFileEquals(expected.getFile(), actual.getFile());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceNotExists() {
|
||||
JobExecution jobExecution = this.launchStep("step2");
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.springframework.ldap.ldif.batch;
|
||||
|
||||
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,53 @@
|
||||
<?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-2.0.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.0.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>
|
||||
|
||||
<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,57 @@
|
||||
<?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-2.0.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.0.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.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.ldap.ldif.batch.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.ldap.ldif.batch.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.ldap.ldif.batch.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>
|
||||
75
ldif/ldif-batch/src/test/resources/expectedOutput.ldif
Normal file
75
ldif/ldif-batch/src/test/resources/expectedOutput.ldif
Normal file
@@ -0,0 +1,75 @@
|
||||
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
|
||||
|
||||
12
ldif/ldif-batch/src/test/resources/log4j.properties
Normal file
12
ldif/ldif-batch/src/test/resources/log4j.properties
Normal file
@@ -0,0 +1,12 @@
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
|
||||
log4j.appender.console.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
|
||||
|
||||
log4j.logger.org.springframework.test=INFO, console
|
||||
log4j.logger.org.springframework.beans=INFO, console
|
||||
log4j.logger.org.springframework.context=INFO, console
|
||||
log4j.logger.org.springframework.transaction=INFO, console
|
||||
log4j.logger.org.springframework.aop=INFO, console
|
||||
log4j.logger.org.springframework.batch=INFO, console
|
||||
log4j.logger.org.springframework.ldap.ldif=DEBUG, console
|
||||
236
ldif/ldif-batch/src/test/resources/test.ldif
Normal file
236
ldif/ldif-batch/src/test/resources/test.ldif
Normal file
@@ -0,0 +1,236 @@
|
||||
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
|
||||
|
||||
13
ldif/ldif-core/.springBeans
Normal file
13
ldif/ldif-core/.springBeans
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[2.2.6.200908051215-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[false]]></enableImports>
|
||||
<configs>
|
||||
</configs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
</beansProjectDescription>
|
||||
40
ldif/ldif-core/pom.xml
Normal file
40
ldif/ldif-core/pom.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-parent-tiger</artifactId>
|
||||
<version>1.3.1.CI-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-ldap-ldif-core</artifactId>
|
||||
<name>Spring LDAP LDIF Core</name>
|
||||
<description>LDIFParser and supporting classes.</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
<version>${version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
|
||||
/**
|
||||
* Extends {@link javax.naming.directory.BasicAttribute} to add support for
|
||||
* options as defined in RFC2849.
|
||||
* <p>
|
||||
* While uncommon, options can be used to specify additional descriptors for
|
||||
* the attribute. Options are backed by a {@link java.util.HashSet} of
|
||||
* {@link java.lang.String}.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class LdapAttribute extends BasicAttribute {
|
||||
|
||||
private static final long serialVersionUID = -5263905906016179429L;
|
||||
|
||||
/**
|
||||
* Holds the attributes options.
|
||||
*/
|
||||
protected Set<String> options = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Creates an unordered attribute with the specified ID.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
*/
|
||||
public LdapAttribute(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unordered attribute with the specified ID and value.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
* @param value Attribute value.
|
||||
*/
|
||||
public LdapAttribute(String id, Object value) {
|
||||
super(id, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unordered attribute with the specified ID, value, and options.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
* @param value Attribute value.
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} attribute options.
|
||||
*/
|
||||
public LdapAttribute(String id, Object value, Collection<String> options) {
|
||||
super(id, value);
|
||||
this.options.addAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an attribute with the specified ID whose values may be ordered.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
* @param ordered boolean indicating whether or not the attributes values are ordered.
|
||||
*/
|
||||
public LdapAttribute(String id, boolean ordered) {
|
||||
super(id, ordered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an attribute with the specified ID and options whose values may be ordered.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} attribute options.
|
||||
* @param ordered boolean indicating whether or not the attributes values are ordered.
|
||||
*/
|
||||
public LdapAttribute(String id, Collection<String> options, boolean ordered) {
|
||||
super(id, ordered);
|
||||
this.options.addAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an attribute with the specified ID and value whose values may be ordered.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
* @param value Attribute value.
|
||||
* @param ordered boolean indicating whether or not the attributes values are ordered.
|
||||
*/
|
||||
public LdapAttribute(String id, Object value, boolean ordered) {
|
||||
super(id, value, ordered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an attribute with the specified ID, value, and options whose values may be ordered.
|
||||
*
|
||||
* @param id {@link java.lang.String} ID of the attribute.
|
||||
* @param value Attribute value.
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} attribute options.
|
||||
* @param ordered boolean indicating whether or not the attributes values are ordered.
|
||||
*/
|
||||
public LdapAttribute(String id, Object value, Collection<String> options, boolean ordered) {
|
||||
super(id, value, ordered);
|
||||
this.options.addAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options.
|
||||
*
|
||||
* @return returns a {@link java.util.Set} of {@link java.lang.String}
|
||||
*/
|
||||
public Set<String> getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options.
|
||||
*
|
||||
* @param options {@link java.util.Set} of {@link java.lang.String}
|
||||
*/
|
||||
public void setOptions(Set<String> options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an option.
|
||||
*
|
||||
* @param option {@link java.lang.String} option.
|
||||
* @return boolean indication successful addition of option.
|
||||
*/
|
||||
public boolean addOption(String option) {
|
||||
return this.options.add(option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all values in the collection to the options.
|
||||
*
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} values.
|
||||
* @return boolean indication successful addition of options.
|
||||
*/
|
||||
public boolean addAllOptions(Collection<String> options) {
|
||||
return this.options.addAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all stored options.
|
||||
*/
|
||||
public void clearOptions() {
|
||||
this.options.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for existence of a particular option on the set.
|
||||
*
|
||||
* @param option {@link java.lang.String} option.
|
||||
* @return boolean indicating result.
|
||||
*/
|
||||
public boolean contains(String option) {
|
||||
return this.options.contains(option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for existence of a series of options on the set.
|
||||
*
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} options.
|
||||
* @return boolean indicating result.
|
||||
*/
|
||||
public boolean containsAll(Collection<String> options) {
|
||||
return this.options.containsAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the presence of options.
|
||||
*
|
||||
* @return boolean indicating result.
|
||||
*/
|
||||
public boolean hasOptions() {
|
||||
return !options.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an option from the the set.
|
||||
*
|
||||
* @param option {@link java.lang.String} option.
|
||||
* @return boolean indicating successful removal of option.
|
||||
*/
|
||||
public boolean removeOption(String option) {
|
||||
return this.options.remove(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all options listed in the supplied set.
|
||||
*
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} options.
|
||||
* @return boolean indicating successful removal of options.
|
||||
*/
|
||||
public boolean removeAllOptions(Collection<String> options) {
|
||||
return this.options.removeAll(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any options not on the set of supplied options.
|
||||
*
|
||||
* @param options {@link java.util.Collection} of {@link java.lang.String} options.
|
||||
* @return boolean indicating successful retention of options.
|
||||
*/
|
||||
public boolean retainAllOptions(Collection<String> options) {
|
||||
return this.options.retainAll(options);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.core;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
/**
|
||||
* Extends {@link javax.naming.directory.BasicAttributes} to add specialized support
|
||||
* for DNs.
|
||||
* <p>
|
||||
* While DNs appear to be and can be treated as attributes, they have a special
|
||||
* meaning in that they define the address to which the object is bound. DNs must
|
||||
* conform to special formating rules and are typically required to be handled
|
||||
* separately from other attributes.
|
||||
* <p>
|
||||
* This class makes this distinction between the DN and other
|
||||
* attributes prominent and apparent.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class LdapAttributes extends BasicAttributes {
|
||||
|
||||
private static final long serialVersionUID = 97903297123869138L;
|
||||
|
||||
private static Log log = LogFactory.getLog(LdapAttributes.class);
|
||||
|
||||
private static final String SAFE_CHAR = "[\\p{ASCII}&&[^\\x00\\x0A\\x0D]]"; //Any ASCII except NUL, LF, and CR
|
||||
|
||||
private static final String SAFE_INIT_CHAR = "[\\p{ASCII}&&[^ \\x00\\x0A\\x0D\\x3A\\x3C]]"; //Any ASCII except NUL, LF, CR, SPACE, colon, and less-than
|
||||
|
||||
/**
|
||||
* Distinguished name to which the object is bound.
|
||||
*/
|
||||
protected DistinguishedName dn = new DistinguishedName();
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public LdapAttributes() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdapAttributes object with the specified DN.
|
||||
*
|
||||
* @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound.
|
||||
*/
|
||||
public LdapAttributes(DistinguishedName dn) {
|
||||
super();
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for specifying whether or not the object is case sensitive.
|
||||
*
|
||||
* @param ignoreCase boolean indicator.
|
||||
*/
|
||||
public LdapAttributes(boolean ignoreCase) {
|
||||
super(ignoreCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdapAttributes object with the specified DN and case sensitivity setting.
|
||||
*
|
||||
* @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound.
|
||||
* @param ignoreCase boolean indicator.
|
||||
*/
|
||||
public LdapAttributes(DistinguishedName dn, boolean ignoreCase) {
|
||||
super(ignoreCase);
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdapAttributes object with the specified attribute.
|
||||
*
|
||||
* @param attrID {@link java.lang.String} ID of the attribute.
|
||||
* @param val Value of the attribute.
|
||||
*/
|
||||
public LdapAttributes(String attrID, Object val) {
|
||||
put(new LdapAttribute(attrID, val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdapAttributes object with the specifying attribute and value and case sensitivity setting.
|
||||
*
|
||||
* @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound.
|
||||
* @param attrID {@link java.lang.String} ID of the attribute.
|
||||
* @param val Value of the attribute.
|
||||
*/
|
||||
public LdapAttributes(DistinguishedName dn, String attrID, Object val) {
|
||||
this.dn = dn;
|
||||
put(new LdapAttribute(attrID, val));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdapAttributes object with the specifying attribute and value and case sensitivity setting.
|
||||
*
|
||||
* @param attrID {@link java.lang.String} ID of the attribute.
|
||||
* @param val Value of the attribute.
|
||||
* @param ignoreCase boolean indicator.
|
||||
*/
|
||||
public LdapAttributes(String attrID, Object val, boolean ignoreCase) {
|
||||
put(new LdapAttribute(attrID, val, ignoreCase));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdapAttributes object for the supplied DN with the attribute specified.
|
||||
*
|
||||
* @param dn The {@link org.springframework.ldap.core.DistinguishedName} to which this object is bound.
|
||||
* @param attrID {@link java.lang.String} ID of the attribute.
|
||||
* @param val Value of the attribute.
|
||||
* @param ignoreCase boolean indicator.
|
||||
*/
|
||||
public LdapAttributes(DistinguishedName dn, String attrID, Object val, boolean ignoreCase) {
|
||||
this.dn = dn;
|
||||
put(new LdapAttribute(attrID, val, ignoreCase));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distinguished name to which the object is bound.
|
||||
*
|
||||
* @return {@link org.springframework.ldap.core.DistinguishedName} specifying the name to which the object is bound.
|
||||
*/
|
||||
public DistinguishedName getDN() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the distinguished name of the object.
|
||||
*
|
||||
* @param dn {@link org.springframework.ldap.core.DistinguishedName} specifying the name to which the object is bound.
|
||||
*/
|
||||
public void setDN(DistinguishedName dn) {
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object in LDIF format.
|
||||
*
|
||||
* @return {@link java.lang.String} formated to RFC2849 LDIF specifications.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
try {
|
||||
|
||||
DistinguishedName dn = getDN();
|
||||
|
||||
if (!dn.toString().matches(SAFE_INIT_CHAR + SAFE_CHAR + "*")) {
|
||||
sb.append("dn:: " + new BASE64Encoder().encode(dn.toString().getBytes()) + "\n");
|
||||
} else {
|
||||
sb.append("dn: " + getDN() + "\n");
|
||||
}
|
||||
|
||||
NamingEnumeration<Attribute> attributes = getAll();
|
||||
|
||||
while (attributes.hasMore()) {
|
||||
Attribute attribute = attributes.next();
|
||||
NamingEnumeration<?> values = attribute.getAll();
|
||||
|
||||
while (values.hasMore()) {
|
||||
Object value = values.next();
|
||||
|
||||
if (value instanceof String)
|
||||
sb.append(attribute.getID() + ": " + (String) value + "\n");
|
||||
|
||||
else if (value instanceof byte[])
|
||||
sb.append(attribute.getID() + ":: " + new BASE64Encoder().encode((byte[]) value) + "\n");
|
||||
|
||||
else if (value instanceof URI)
|
||||
sb.append(attribute.getID() + ":< " + (URI) value + "\n");
|
||||
|
||||
else {
|
||||
sb.append(attribute.getID() + ": " + value + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (NamingException e) {
|
||||
log.error("Error formating attributes for output.", e);
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif;
|
||||
|
||||
import org.springframework.ldap.NamingException;
|
||||
|
||||
/**
|
||||
* Thrown whenever a parsed attribute does not conform to LDAP specifications.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class InvalidAttributeFormatException extends NamingException {
|
||||
|
||||
private static final long serialVersionUID = -4529380160785322985L;
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
*/
|
||||
public InvalidAttributeFormatException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public InvalidAttributeFormatException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @param cause
|
||||
*/
|
||||
public InvalidAttributeFormatException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif;
|
||||
|
||||
import org.springframework.ldap.NamingException;
|
||||
|
||||
/**
|
||||
* Thrown whenever a parsed record does not conform to LDAP specifications.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class InvalidRecordFormatException extends NamingException {
|
||||
|
||||
private static final long serialVersionUID = -5047874723621065139L;
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
*/
|
||||
public InvalidRecordFormatException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public InvalidRecordFormatException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @param cause
|
||||
*/
|
||||
public InvalidRecordFormatException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
The base package for Spring LDAPs LDIF parser implementation.
|
||||
<p>
|
||||
Classes declared in this package include the new base types for
|
||||
LDAP objects as well as exception types for the LDIF parser.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif.parser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
import org.springframework.ldap.ldif.InvalidRecordFormatException;
|
||||
import org.springframework.ldap.ldif.support.AttributeValidationPolicy;
|
||||
import org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy;
|
||||
import org.springframework.ldap.ldif.support.LineIdentifier;
|
||||
import org.springframework.ldap.ldif.support.SeparatorPolicy;
|
||||
import org.springframework.ldap.schema.DefaultSchemaSpecification;
|
||||
import org.springframework.ldap.schema.Specification;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The {@link LdifParser LdifParser} is the main class of the {@link org.springframework.ldap.ldif} package.
|
||||
* This class reads lines from a resource and assembles them into an {@link LdapAttributes LdapAttributes} object.
|
||||
* The {@link LdifParser LdifParser} does ignores <i>changetype</i> LDIF entries as their usefulness in the
|
||||
* context of an application has yet to be determined.
|
||||
* <p>
|
||||
* <b>Design</b><br/>
|
||||
* {@link LdifParser LdifParser} provides the main interface for operation but requires three supporting classes to
|
||||
* enable operation:
|
||||
* <ul>
|
||||
* <li>{@link SeparatorPolicy SeparatorPolicy} - establishes the mechanism by which lines are assembled into attributes.</li>
|
||||
* <li>{@link AttributeValidationPolicy AttributeValidationPolicy} - ensures that attributes are correctly structured prior to parsing.</li>
|
||||
* <li>{@link Specification Specification} - provides a mechanism by which object structure can be validated after assembly.</li>
|
||||
* </ul>
|
||||
* Together, these 4 classes read from the resource line by line and translate the data into objects for use.
|
||||
* <p>
|
||||
* <b>Usage</b><br/>
|
||||
* {@link #getRecord() getRecord()} reads the next available record from the resource. Lines are read and
|
||||
* passed to the {@link SeparatorPolicy SeparatorPolicy} for interpretation. The parser continues to read
|
||||
* lines and appends them to the buffer until it encounters the start of a new attribute or an end of record
|
||||
* delimiter. When the new attribute or end of record is encountered, the buffer is passed to the
|
||||
* {@link AttributeValidationPolicy AttributeValidationPolicy} which ensures the buffer conforms to a valid
|
||||
* attribute definition as defined in RFC2849 and returns an {@link org.springframework.ldap.core.LdapAttribute LdapAttribute} object
|
||||
* which is then added to the record, an {@link LdapAttributes LdapAttributes} object. Upon encountering the
|
||||
* end of record, the record is validated by the {@link Specification Specification} policy and,
|
||||
* if valid, returned to the requester.
|
||||
* <p>
|
||||
* <i>NOTE: By default, objects are not validated. If validation is required,
|
||||
* an appropriate specification object must be set.</i>
|
||||
* <p>
|
||||
* The parser requires the resource to be {@link #open() open()} prior to an invocation of {@link #getRecord() getRecord()}.
|
||||
* {@link #hasMoreRecords() hasMoreRecords()} can be used to loop over the resource until all records have been
|
||||
* retrieved. Likewise, the {@link #reset() reset()} method will reset the resource.
|
||||
* <p>
|
||||
* Objects implementing the {@link javax.naming.directory.Attributes Attributes} interface are required to support a case sensitivity setting
|
||||
* which controls whether or not the attribute IDs of the object are case sensitive. The {@link #caseInsensitive caseInsensitive}
|
||||
* setting of the {@link LdifParser LdifParser} is passed to the constructor of any {@link javax.naming.directory.Attributes Attributes} created. The
|
||||
* default value for this setting is true so that case insensitive objects are created.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class LdifParser implements Parser, InitializingBean {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LdifParser.class);
|
||||
|
||||
/**
|
||||
* The resource to parse.
|
||||
*/
|
||||
private Resource resource;
|
||||
|
||||
/**
|
||||
* A BufferedReader to read the file.
|
||||
*/
|
||||
private BufferedReader reader;
|
||||
|
||||
/**
|
||||
* The SeparatorPolicy to use for interpreting attributes from the lines of the resource.
|
||||
*/
|
||||
private SeparatorPolicy separatorPolicy = new SeparatorPolicy();
|
||||
|
||||
/**
|
||||
* The AttributeValidationPolicy to use to interpret attributes.
|
||||
*/
|
||||
private AttributeValidationPolicy attributePolicy = new DefaultAttributeValidationPolicy();
|
||||
|
||||
/**
|
||||
* The RecordSpecification for validating records produced.
|
||||
*/
|
||||
private Specification<LdapAttributes> specification = new DefaultSchemaSpecification();
|
||||
|
||||
/**
|
||||
* This setting is used to control the case sensitivity of LdapAttribute objects returned by the parser.
|
||||
*/
|
||||
private boolean caseInsensitive = true;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public LdifParser() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LdifParser with the indicated case sensitivity setting.
|
||||
*
|
||||
* @param caseInsensitive Case sensitivity setting for LdapAttributes objects returned by the parser.
|
||||
*/
|
||||
public LdifParser(boolean caseInsensitive) {
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LdifParser for the specified resource with the provided case sensitivity setting.
|
||||
*
|
||||
* @param resource The resource to parse.
|
||||
* @param caseInsensitive Case sensitivity setting for LdapAttributes objects returned by the parser.
|
||||
*/
|
||||
public LdifParser(Resource resource, boolean caseInsensitive) {
|
||||
this.resource = resource;
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience constructor for resource specification.
|
||||
*
|
||||
* @param resource The resource to parse.
|
||||
*/
|
||||
public LdifParser(Resource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience constructor: accepts a File object.
|
||||
*
|
||||
* @param file The file to parse.
|
||||
*/
|
||||
public LdifParser(File file) {
|
||||
this.resource = new FileSystemResource(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the separator policy.
|
||||
*
|
||||
* The default separator policy should suffice for most needs.
|
||||
*
|
||||
* @param separatorPolicy Separator policy.
|
||||
*/
|
||||
public void setSeparatorPolicy(SeparatorPolicy separatorPolicy) {
|
||||
this.separatorPolicy = separatorPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Policy object enforcing the rules for acceptable attributes.
|
||||
*
|
||||
* @param avPolicy Attribute validation policy.
|
||||
*/
|
||||
public void setAttributeValidationPolicy(AttributeValidationPolicy avPolicy) {
|
||||
this.attributePolicy = avPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Policy object for enforcing rules to acceptable LDAP objects.
|
||||
*
|
||||
* This policy may be used to enforce schema restrictions.
|
||||
* @param specification
|
||||
*/
|
||||
public void setRecordSpecification(Specification<LdapAttributes> specification) {
|
||||
this.specification = specification;
|
||||
}
|
||||
|
||||
public void setResource(Resource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public void setCaseInsensitive(boolean caseInsensitive) {
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
Assert.notNull(resource, "Resource must be set.");
|
||||
reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
|
||||
}
|
||||
|
||||
public boolean isReady() throws IOException {
|
||||
return reader.ready();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (resource.isOpen())
|
||||
reader.close();
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
Assert.notNull(reader, "A reader has not been obtained.");
|
||||
reader.reset();
|
||||
}
|
||||
|
||||
public boolean hasMoreRecords() throws IOException {
|
||||
return reader.ready();
|
||||
}
|
||||
|
||||
public LdapAttributes getRecord() throws IOException {
|
||||
Assert.notNull(reader, "A reader must be obtained: parser not open.");
|
||||
|
||||
if (!reader.ready()) {
|
||||
log.debug("Reader not ready!");
|
||||
return null;
|
||||
}
|
||||
|
||||
LdapAttributes record = new LdapAttributes(caseInsensitive);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
String line = reader.readLine();
|
||||
|
||||
while(true) {
|
||||
|
||||
LineIdentifier identifier = separatorPolicy.assess(line);
|
||||
|
||||
switch(identifier) {
|
||||
case NewRecord:
|
||||
log.trace("Starting new record.");
|
||||
//Start new record.
|
||||
builder = new StringBuilder(line);
|
||||
|
||||
break;
|
||||
|
||||
case Control:
|
||||
log.trace("'control' encountered.");
|
||||
|
||||
//Log WARN and discard record.
|
||||
log.warn("LDIF change records have no implementation: record will be ignored.");
|
||||
builder = null;
|
||||
record = null;
|
||||
|
||||
break;
|
||||
|
||||
case ChangeType:
|
||||
log.trace("'changetype' encountered.");
|
||||
|
||||
//Log WARN and discard record.
|
||||
log.warn("LDIF change records have no implementation: record will be ignored.");
|
||||
builder = null;
|
||||
record = null;
|
||||
|
||||
break;
|
||||
|
||||
case Attribute:
|
||||
//flush buffer.
|
||||
addAttributeToRecord(builder.toString(), record);
|
||||
|
||||
log.trace("Starting new attribute.");
|
||||
//Start new attribute.
|
||||
builder = new StringBuilder(line);
|
||||
|
||||
break;
|
||||
|
||||
case Continuation:
|
||||
log.trace("...appending line to buffer.");
|
||||
//Append line to buffer.
|
||||
builder.append(line.replaceFirst(" ", ""));
|
||||
|
||||
break;
|
||||
|
||||
case EndOfRecord:
|
||||
log.trace("...done parsing record. (EndOfRecord)");
|
||||
|
||||
//Validate record and return.
|
||||
if (record == null) return null;
|
||||
else {
|
||||
try {
|
||||
//flush buffer.
|
||||
addAttributeToRecord(builder.toString(), record);
|
||||
|
||||
if (specification.isSatisfiedBy(record)) {
|
||||
log.debug("record parsed:\n" + record);
|
||||
return record;
|
||||
|
||||
} else {
|
||||
throw new InvalidRecordFormatException("Record [dn: " + record.getDN() + "] does not conform to specification.");
|
||||
}
|
||||
} catch(NamingException e) {
|
||||
log.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
//Take no action -- applies to VersionIdentifier, Comments, and voided records.
|
||||
}
|
||||
|
||||
line = reader.readLine();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addAttributeToRecord(String buffer, LdapAttributes record) {
|
||||
try {
|
||||
if (StringUtils.isNotEmpty(buffer) && record != null) {
|
||||
//Validate previous attribute and add to record.
|
||||
Attribute attribute = attributePolicy.parse(buffer);
|
||||
|
||||
if (attribute.getID().equalsIgnoreCase("dn")) {
|
||||
log.trace("...adding DN to record.");
|
||||
|
||||
String dn;
|
||||
if (attribute.get() instanceof byte[]) {
|
||||
dn = new String((byte[]) attribute.get());
|
||||
} else {
|
||||
dn = (String) attribute.get();
|
||||
}
|
||||
|
||||
record.setDN(new DistinguishedName(dn));
|
||||
|
||||
} else {
|
||||
log.trace("...adding attribute to record.");
|
||||
Attribute attr = record.get(attribute.getID());
|
||||
|
||||
if (attr != null) {
|
||||
attr.add(attribute.get());
|
||||
} else {
|
||||
record.put(attribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
log.error(e);
|
||||
} catch (NoSuchElementException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(resource, "A resource to parse is required.");
|
||||
Assert.isTrue(resource.exists(), resource.getDescription() + ": resource does not exist!");
|
||||
Assert.isTrue(resource.isReadable(), "Resource is not readable.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.naming.directory.Attributes;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* The Parser interface represents the required methods to be implemented by parser utilities.
|
||||
* These methods are the base set of methods needed to provide parsing ability.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*/
|
||||
public interface Parser {
|
||||
|
||||
/**
|
||||
* Sets the resource to parse.
|
||||
*
|
||||
* @param resource The resource to parse.
|
||||
*/
|
||||
public void setResource(Resource resource);
|
||||
|
||||
/**
|
||||
* Sets the control parameter for specifying case sensitivity on creation of the {@link Attributes} object.
|
||||
*
|
||||
* @param caseInsensitive The resource to parse.
|
||||
*/
|
||||
public void setCaseInsensitive(boolean caseInsensitive);
|
||||
|
||||
/**
|
||||
* Opens the resource: the resource must be opened prior to parsing.
|
||||
*
|
||||
* @throws IOException if a problem is encountered while trying to open the resource.
|
||||
*/
|
||||
public void open() throws IOException;
|
||||
|
||||
/**
|
||||
* Closes the resource after parsing.
|
||||
*
|
||||
* @throws IOException if a problem is encountered while trying to close the resource.
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Resets the line read parser.
|
||||
*
|
||||
* @throws Exception if a problem is encountered while trying to reset the resource.
|
||||
*/
|
||||
public void reset() throws IOException;
|
||||
|
||||
/**
|
||||
* True if the resource contains more records; false otherwise.
|
||||
*
|
||||
* @return boolean indicating whether or not the end of record has been reached.
|
||||
* @throws IOException if a problem is encountered while trying to validate the resource is ready.
|
||||
*/
|
||||
public boolean hasMoreRecords() throws IOException;
|
||||
|
||||
/**
|
||||
* Parses the next record from the resource.
|
||||
*
|
||||
* @return LdapAttributes object representing the record parsed.
|
||||
* @throws IOException if a problem is encountered while trying to read from the resource.
|
||||
*/
|
||||
public Attributes getRecord() throws IOException;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the parser is ready to to return results.
|
||||
*
|
||||
* @return boolean indicator
|
||||
* @throws IOException if there is a problem with the underlying resource.
|
||||
*/
|
||||
public boolean isReady() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This package contains the parser classes and interfaces.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif.support;
|
||||
|
||||
import javax.naming.directory.Attribute;
|
||||
|
||||
/**
|
||||
* Interface defining the required methods for AttributeValidationPolicies.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public interface AttributeValidationPolicy {
|
||||
|
||||
/**
|
||||
* Validates attribute contained in the buffer and returns an LdapAttribute.
|
||||
*
|
||||
* @param buffer Buffer containing the line parsed from the resource.
|
||||
* @return LdapAttribute representing the attribute parsed.
|
||||
*/
|
||||
Attribute parse(String buffer);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.naming.directory.Attribute;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.core.LdapAttribute;
|
||||
import org.springframework.ldap.ldif.InvalidAttributeFormatException;
|
||||
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
/**
|
||||
* Ensures the buffer represents a valid attribute as defined by RFC2849.
|
||||
*
|
||||
* Meets the standards imposed by RFC 2849 for the "LDAP Data Interchange Format (LDIF)
|
||||
* - Technical Specification".
|
||||
*
|
||||
* Special attention is called to URL support: RFC 2849 requires that
|
||||
* LDIFs support URLs as defined in 1738; however, RFC 1738 has been updated by several RFCs including
|
||||
* RFC 1808, RFC 2396, and RFC 3986 (which obsoleted the formers). Unsupported features of this
|
||||
* implementation of URL identification include query strings and fragments in HTTP URLs.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DefaultAttributeValidationPolicy implements AttributeValidationPolicy {
|
||||
|
||||
private static Log log = LogFactory.getLog(DefaultAttributeValidationPolicy.class);
|
||||
|
||||
/**
|
||||
* Pattern Declarations.
|
||||
*/
|
||||
|
||||
//General Definitions
|
||||
private static final String DIGIT = "\\p{Digit}";
|
||||
|
||||
private static final String LOW_ALPHA = "\\p{Lower}";
|
||||
|
||||
private static final String HIGH_ALPHA = "\\p{Upper}";
|
||||
|
||||
private static final String ALPHA = "\\p{Alpha}";
|
||||
|
||||
private static final String ALPHANUM = "\\p{Alnum}";
|
||||
|
||||
private static final String HEX = "\\p{XDigit}";
|
||||
|
||||
private static final String SAFE = "[\\x24\\x2D\\x5F\\x2E\\x2B]"; //$|-|_|.|+
|
||||
|
||||
private static final String EXTRA = "[\\x21\\x2A\\x27\\x7B\\x7D\\x2C]"; //!|*|'|(|)|,
|
||||
|
||||
private static final String PUNCTUATION = "[\\x3C\\x3E\\x23\\x25\\x22]"; //<|>|#|%|"
|
||||
|
||||
private static final String ESCAPE = "%" + HEX + "{2}";
|
||||
|
||||
private static final String RESERVED = "[\\x3B\\x2F\\x3F\\x3A\\x40\\x26\\x3D]"; //;|/|?|:|@|&|=
|
||||
|
||||
private static final String UNRESERVED = "[" + ALPHA + DIGIT + SAFE + EXTRA + "]";
|
||||
|
||||
private static final String UCHAR = "(?:" + UNRESERVED + "|" + ESCAPE + ")";
|
||||
|
||||
private static final String XCHAR = "(?:" + UNRESERVED + "|" + RESERVED + "|" + ESCAPE + ")";
|
||||
|
||||
private static final String DIGITS = DIGIT + "+";
|
||||
|
||||
//Standard LDAP Attribute Definitions
|
||||
private static final String ATTRIBUTE_SEPARATOR = ":";
|
||||
|
||||
private static final String OPTION_SEPARATOR = ";";
|
||||
|
||||
private static final String BASE64_INDICATOR = ":";
|
||||
|
||||
private static final String URL_INDICATOR = "<";
|
||||
|
||||
private static final String ATTRIBUTE_TYPE_CHARS = ALPHA + DIGIT + "-";
|
||||
|
||||
private static final String LDAP_OID = "[[0-9]|[1-9][0-9]+][\\.(?:[0-9]|[1-9][0-9]+)]+";
|
||||
|
||||
private static final String OPTION = "[" + ATTRIBUTE_TYPE_CHARS + "]+";
|
||||
|
||||
private static final String OPTIONS = "[" + OPTION_SEPARATOR + OPTION + "]*";
|
||||
|
||||
private static final String ATTRIBUTE_TYPE = LDAP_OID + "|" + ALPHANUM + "[" + ATTRIBUTE_TYPE_CHARS + "]*";
|
||||
|
||||
private static final String ATTRIBUTE_DESCRIPTION = "(" + ATTRIBUTE_TYPE + ")(" + OPTIONS + ")";
|
||||
|
||||
private static final String SAFE_CHAR = "[\\p{ASCII}&&[^\\x00\\x0A\\x0D]]"; //Any ASCII except NUL, LF, and CR
|
||||
|
||||
private static final String SAFE_INIT_CHAR = "[\\p{ASCII}&&[^ \\x00\\x0A\\x0D\\x3A\\x3C]]"; //Any ASCII except NUL, LF, CR, SPACE, colon, and less-than
|
||||
|
||||
private static final String SAFE_STRING = "(" + SAFE_INIT_CHAR + SAFE_CHAR + "*)";
|
||||
|
||||
private static final String FILL = "[ ]*"; //Any number of spaces
|
||||
|
||||
//BASE64 Definitions
|
||||
private static final String BASE64_CHAR = "[\\x2B\\x2F\\x30-\\x39\\x3D\\x41-\\x5A\\x61-\\x7A]"; //+, /, 0-9, -, A-Z, a-z
|
||||
|
||||
private static final String BASE64_STRING = "(" + BASE64_CHAR + "*)";
|
||||
|
||||
//URL Components
|
||||
private static final String USER = "[" + UCHAR + "\\x3B\\x3F\\x26\\x3D]*"; //UCHAR|;|?|&|=
|
||||
|
||||
private static final String PASSWORD = "[" + UCHAR + "\\x3B\\x3F\\x26\\x3D]*"; //UCHAR|;|?|&|=
|
||||
|
||||
private static final String DOMAINLABEL = ALPHANUM + "|" + ALPHANUM + "[" + ALPHANUM + "-]*" + ALPHANUM;
|
||||
|
||||
private static final String TOPLABEL = ALPHA + "|" + ALPHA + "[" + ALPHANUM + "-]*" + ALPHANUM;
|
||||
|
||||
private static final String HOSTNAME = "(?:" + DOMAINLABEL + "\\.)*" + TOPLABEL;
|
||||
|
||||
private static final String IPADDRESS = "(?:" + DIGIT + "{1,3}\\.){3}" + DIGIT + "{1,3}";
|
||||
|
||||
private static final String HOST = "(?:" + HOSTNAME + "|" + IPADDRESS + ")";
|
||||
|
||||
private static final String PORT = DIGITS;
|
||||
|
||||
private static final String HOSTPORT = HOST + "(?::" + PORT + ")?";
|
||||
|
||||
private static final String URLPATH = XCHAR + "*";
|
||||
|
||||
private static final String LOGIN = "(?:" + USER + "(?::" + PASSWORD + ")?@)?" + HOSTPORT;
|
||||
|
||||
//URL Definitions
|
||||
private static final String SCHEME = "[" + LOW_ALPHA + DIGIT + "\\x2B\\x2D\\x2E]+";
|
||||
|
||||
private static final String IP_SCHEMEPART = "//" + LOGIN + "(?:/" + URLPATH + ")?";
|
||||
|
||||
private static final String SCHEMEPART = "(?:" + XCHAR + "*|" + IP_SCHEMEPART + ")";
|
||||
|
||||
private static final String GENERIC_URL = SCHEME + ":" + SCHEMEPART;
|
||||
|
||||
//HTTP Definition
|
||||
private static final String HSEGMENT = "[" + UCHAR + "\\x3A\\x3B\\x26\\x3D\\x40]*"; //UCHAR|:|;|&|=|@
|
||||
|
||||
private static final String HPATH = HSEGMENT + "[/" + HSEGMENT + "]*";
|
||||
|
||||
private static final String SEARCH = HSEGMENT;
|
||||
|
||||
private static final String HTTP_URL = "http://" + HOSTPORT + "(?:/" + HPATH + "(?:\\x3F" + SEARCH + ")?)?";
|
||||
|
||||
//FTP
|
||||
private static final String FSEGMENT = "[" + UCHAR + "\\x3F\\x3A\\x26\\x3D\\x40]*"; //UCHAR|?|:|&|=|@
|
||||
|
||||
private static final String FPATH = FSEGMENT + "[/" + FSEGMENT + "]*";
|
||||
|
||||
private static final String FTPTYPE = "[AIDaid]";
|
||||
|
||||
private static final String FTP_URL = "ftp://" + LOGIN + "(?:/" + FPATH + "(?:;type=" + FTPTYPE + ")?)?";
|
||||
|
||||
//NEWS
|
||||
private static final String GROUP = ALPHA + "[" + ALPHA + DIGIT + "\\x2D\\x2E\\x2B\\x5F]*"; //ALPHA [ALPHA|DIGIT|-|.|+|_]*
|
||||
|
||||
private static final String ARTICLE = "[" + UCHAR + "\\x3A\\x3B\\x2F\\x3F\\x26\\x3D]@" + HOST; //[UCHAR|;|/|?|:|&|=]@HOST
|
||||
|
||||
private static final String GROUPPART = "(?:\\x2A|" + GROUP + "|" + ARTICLE + ")";
|
||||
|
||||
private static final String NEWS_URL = "news:" + GROUPPART;
|
||||
|
||||
//NNTP
|
||||
private static final String NNTP_URL = "nntp://" + HOSTPORT + "/" + GROUP + "/" + DIGITS;
|
||||
|
||||
//TELNET
|
||||
private static final String TELNET_URL = "telnet://" + LOGIN + "[/]?";
|
||||
|
||||
//GOPHER
|
||||
private static final String GTYPE = XCHAR;
|
||||
|
||||
private static final String SELECTOR = XCHAR + "*";
|
||||
|
||||
private static final String GOPHER_STRING = XCHAR + "*";
|
||||
|
||||
private static final String GOPHER_URL = "gopher://" + HOSTPORT + "(?:/(?:" + GTYPE + "(?:" + SELECTOR + "(?:%09" + SEARCH + "(?:%09" + GOPHER_STRING + ")?)?)?)?)?";
|
||||
|
||||
//WAIS
|
||||
private static final String WPATH = UCHAR + "*";
|
||||
|
||||
private static final String WTYPE = UCHAR + "*";
|
||||
|
||||
private static final String DATABASE = UCHAR + "*";
|
||||
|
||||
private static final String WAIS_DOC = "wais://" + HOSTPORT + "/" + DATABASE + "/" + WTYPE + "/" + WPATH;
|
||||
|
||||
private static final String WAIS_INDEX = "wais://" + HOSTPORT + "/" + DATABASE + "\\?" + SEARCH;
|
||||
|
||||
private static final String WAIS_DATABASE = "wais://" + HOSTPORT + "/" + DATABASE;
|
||||
|
||||
private static final String WAIS_URL = WAIS_DATABASE + "|" + WAIS_INDEX + "|" + WAIS_DOC;
|
||||
|
||||
//MAILTO
|
||||
private static final String ENCODED_822_ADDR = XCHAR + "+";
|
||||
|
||||
private static final String MAILTO_URL = "mailto:" + ENCODED_822_ADDR;
|
||||
|
||||
//FILE
|
||||
private static final String FILE_URL = "file://(?:" + HOST + "|localhost)?/" + FPATH ;
|
||||
|
||||
//PROPERO
|
||||
private static final String FIELD_VALUE = "[" + UCHAR + "\\x3F\\x3A\\x40\\x26]*"; //[UCHAR|?|:|@|&]*
|
||||
|
||||
private static final String FIELD_NAME = "[" + UCHAR + "\\x3F\\x3A\\x40\\x26]*"; //[UCHAR|?|:|@|&]*
|
||||
|
||||
private static final String FIELD_SPEC = ";" + FIELD_NAME + "=" + FIELD_VALUE;
|
||||
|
||||
private static final String PSEGMENT = "[" + UCHAR + "\\x3F\\x3A\\x40\\x26\\x3D]*"; //[UCHAR|?|:|@|&|=]*
|
||||
|
||||
private static final String PPATH = PSEGMENT + "(?:/" + PSEGMENT + ")*";
|
||||
|
||||
private static final String PROSPERO_URL = "prospero://" + HOSTPORT + "/" + PPATH + "(?:" + FIELD_SPEC + ")*";
|
||||
|
||||
//GENERIC
|
||||
private static final String OTHER_URL = GENERIC_URL;
|
||||
|
||||
private static final String URL = "((?:" + HTTP_URL + ")|(?:" + FTP_URL + ")|(?:" + NEWS_URL + ")|(?:" + NNTP_URL + ")|(?:" + TELNET_URL + ")|(?:" + GOPHER_URL + ")|(?:" + WAIS_URL + ")|(?:" + MAILTO_URL + ")|(?:" + FILE_URL + ")|(?:" + PROSPERO_URL + ")|(?:" + OTHER_URL + "))"; //URL Pattern
|
||||
|
||||
//Expression Definitions
|
||||
private static final String ATTRIBUTE_EXPRESSION = "^" + ATTRIBUTE_DESCRIPTION + ATTRIBUTE_SEPARATOR + FILL + SAFE_STRING + "{0,1}$"; //Regular Attribute
|
||||
|
||||
private static final String BASE64_ATTRIBUTE_EXPRESSION = "^" + ATTRIBUTE_DESCRIPTION + ATTRIBUTE_SEPARATOR + BASE64_INDICATOR + FILL + BASE64_STRING + "$"; //Base 64
|
||||
|
||||
private static final String URL_ATTRIBUTE_EXPRESSION = "^" + ATTRIBUTE_DESCRIPTION + ATTRIBUTE_SEPARATOR + URL_INDICATOR + FILL + URL + "$"; //URL
|
||||
|
||||
//Pattern Declarations
|
||||
private static final Pattern ATTRIBUTE_PATTERN = Pattern.compile(ATTRIBUTE_EXPRESSION);
|
||||
|
||||
private static final Pattern BASE64_ATTRIBUTE_PATTERN = Pattern.compile(BASE64_ATTRIBUTE_EXPRESSION);
|
||||
|
||||
private static final Pattern URL_ATTRIBUTE_PATTERN = Pattern.compile(URL_ATTRIBUTE_EXPRESSION);
|
||||
|
||||
private boolean ordered = false;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public DefaultAttributeValidationPolicy() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for indicating whether or not attribute values should be ordered alphabetically.
|
||||
*
|
||||
* @param ordered value.
|
||||
*/
|
||||
public DefaultAttributeValidationPolicy(boolean ordered) {
|
||||
this.ordered = ordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the attribute values should be ordered alphabetically.
|
||||
*
|
||||
* @param ordered value.
|
||||
*/
|
||||
public void setOrdered(boolean ordered) {
|
||||
this.ordered = ordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates attribute contained in the buffer and returns an LdapAttribute.
|
||||
* <p>
|
||||
* Ensures attributes meets one of three prescribed patterns for valid attributes:
|
||||
* <ol>
|
||||
* <li>A standard attribute pattern of the form: ATTR_ID[;options]: VALUE</li>
|
||||
* <li>A Base64 attribute pattern of the form: ATTR_ID[;options]:: BASE64_VALUE</li>
|
||||
* <li>A url attribute pattern of the form: ATTR_ID[;options]:< URL_VALUE</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* Upon success an LdapAttribute object is returned.
|
||||
*
|
||||
* @param buffer {@inheritDoc}
|
||||
* @return {@inheritDoc}
|
||||
* @throws InvalidAttributeFormatException if the attribute does not meet one of the three patterns above
|
||||
* or the attribute cannot be parsed.
|
||||
*/
|
||||
public Attribute parse(String buffer) {
|
||||
log.trace("Parsing --> [" + buffer + "]");
|
||||
|
||||
Matcher matcher = ATTRIBUTE_PATTERN.matcher(buffer);
|
||||
if (matcher.matches()) {
|
||||
//Is a regular attribute...
|
||||
return parseStringAttribute(matcher);
|
||||
}
|
||||
|
||||
matcher = BASE64_ATTRIBUTE_PATTERN.matcher(buffer);
|
||||
if (matcher.matches()) {
|
||||
//Is a base64 attribute...
|
||||
return parseBase64Attribute(matcher);
|
||||
}
|
||||
|
||||
matcher = URL_ATTRIBUTE_PATTERN.matcher(buffer);
|
||||
if (matcher.matches()) {
|
||||
//Is a URL attribute...
|
||||
return parseUrlAttribute(matcher);
|
||||
}
|
||||
|
||||
//default: no match.
|
||||
throw new InvalidAttributeFormatException("Not a valid attribute: [" + buffer + "]");
|
||||
}
|
||||
|
||||
private LdapAttribute parseStringAttribute(Matcher matcher) {
|
||||
String id = matcher.group(1);
|
||||
String value = matcher.group(3);
|
||||
List<String> options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR)));
|
||||
|
||||
if (options.isEmpty()) {
|
||||
return new LdapAttribute(id, value, ordered);
|
||||
} else {
|
||||
return new LdapAttribute(id, value, options, ordered);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private LdapAttribute parseBase64Attribute(Matcher matcher) {
|
||||
try {
|
||||
String id = matcher.group(1);
|
||||
String value = matcher.group(3);
|
||||
List<String> options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR)));
|
||||
|
||||
if (options.isEmpty()) {
|
||||
return new LdapAttribute(id, new BASE64Decoder().decodeBuffer(value), ordered);
|
||||
} else {
|
||||
return new LdapAttribute(id, new BASE64Decoder().decodeBuffer(value), options, ordered);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidAttributeFormatException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private LdapAttribute parseUrlAttribute(Matcher matcher) {
|
||||
try {
|
||||
String id = matcher.group(1);
|
||||
String value = matcher.group(3);
|
||||
List<String> options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR)));
|
||||
|
||||
if (options.isEmpty()) {
|
||||
return new LdapAttribute(id, new URI(value), ordered);
|
||||
} else {
|
||||
return new LdapAttribute(id, new URI(value), options, ordered);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
throw new InvalidAttributeFormatException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif.support;
|
||||
|
||||
/**
|
||||
* Enumeration declaring possible event types when parsing LDIF files.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*/
|
||||
|
||||
public enum LineIdentifier {
|
||||
/**
|
||||
* Every LDIF file may optionally start with a version identifier of the form 'version: 1'.
|
||||
*/
|
||||
VersionIdentifier,
|
||||
|
||||
/**
|
||||
* Signifies the start of a new record in the file has been encountered: a DN declaration.
|
||||
*/
|
||||
NewRecord,
|
||||
|
||||
/**
|
||||
* Signals the end of record has been reached.
|
||||
*/
|
||||
EndOfRecord,
|
||||
|
||||
/**
|
||||
* Signifies the event when a new attribute is encountered.
|
||||
*/
|
||||
Attribute,
|
||||
|
||||
/**
|
||||
* Indicates the current line parsed is a continuation of the previous line.
|
||||
*/
|
||||
Continuation,
|
||||
|
||||
/**
|
||||
* The current line is a comment and should be ignored.
|
||||
*/
|
||||
Comment,
|
||||
|
||||
/**
|
||||
* An LDAP changetype control was encountered.
|
||||
*/
|
||||
Control,
|
||||
|
||||
/**
|
||||
* Record being parsed is a 'changetype' record.
|
||||
*/
|
||||
ChangeType,
|
||||
|
||||
/**
|
||||
* Parsed line should be ignored - used to skip remaining lines in a 'changetype' record.
|
||||
*/
|
||||
Void
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.ldif.support;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Policy object for enforcing LDIF record separation rules. Designed explicitly
|
||||
* for use in LdifParser. This default separator policy should really not be
|
||||
* required to be replaced but it is modular just in case.
|
||||
* <p>
|
||||
* This class applies the separation policy prescribed in RFC2849 for LDIF files
|
||||
* and identifies the line type from the input.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class SeparatorPolicy {
|
||||
|
||||
private static Log log = LogFactory.getLog(SeparatorPolicy.class);
|
||||
|
||||
/*
|
||||
* Line Identification Patterns.
|
||||
*/
|
||||
|
||||
private static final String VERSION_IDENTIFIER = "^version: [0-9]+(\\.[0-9]*){0,1}$";
|
||||
|
||||
private static final String CONTROL = "control:";
|
||||
|
||||
private static final String CHANGE_TYPE = "changetype:";
|
||||
|
||||
private static final String CONTINUATION = " ";
|
||||
|
||||
private static final String COMMENT = "#";
|
||||
|
||||
private static final String NewRecord = "^dn:.*$";
|
||||
|
||||
private boolean record = false;
|
||||
|
||||
private boolean skip = false;
|
||||
|
||||
public SeparatorPolicy() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Assess a read line.
|
||||
* <p>
|
||||
* In LDIF, lines must adhere to a particular format. A line can only contain one attribute
|
||||
* and its value. The value may span multiple lines. Continuation lines are marked by the presence
|
||||
* of a single space in the 1st position. Non-continuation lines must start in the first position.
|
||||
*
|
||||
*/
|
||||
public LineIdentifier assess(String line) {
|
||||
log.trace("Assessing --> [" + line + "]");
|
||||
|
||||
if (record) {
|
||||
if (StringUtils.isEmpty(line)) {
|
||||
record = false;
|
||||
skip = false;
|
||||
return LineIdentifier.EndOfRecord;
|
||||
|
||||
} else if (skip) {
|
||||
return LineIdentifier.Void;
|
||||
|
||||
} else {
|
||||
if (line.startsWith(CONTROL)) {
|
||||
skip = true;
|
||||
return LineIdentifier.Control;
|
||||
|
||||
} else if (line.startsWith(CHANGE_TYPE)) {
|
||||
skip = true;
|
||||
return LineIdentifier.ChangeType;
|
||||
|
||||
} else if (line.startsWith(COMMENT)) {
|
||||
return LineIdentifier.Comment;
|
||||
|
||||
} else if (line.startsWith(CONTINUATION)) {
|
||||
return LineIdentifier.Continuation;
|
||||
|
||||
} else {
|
||||
return LineIdentifier.Attribute;
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (StringUtils.isNotEmpty(line) && line.matches(VERSION_IDENTIFIER) && !skip) {
|
||||
//Version Identifiers are ignored by parser.
|
||||
return LineIdentifier.VersionIdentifier;
|
||||
|
||||
} else if (StringUtils.isNotEmpty(line) && line.matches(NewRecord)) {
|
||||
record = true;
|
||||
skip = false;
|
||||
return LineIdentifier.NewRecord;
|
||||
|
||||
} else {
|
||||
return LineIdentifier.Void;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Provides the necessary auxiliary classes utilized by the LDIFParser.
|
||||
<p>
|
||||
Notable classes in this package include:
|
||||
<ul>
|
||||
<li>AttributeValidationPolicy - specifies the proper format valid attributes must adhere to.</li>
|
||||
<li>SeparatorPolicy - translates lines read from the resource into attributes.</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.springframework.ldap.schema;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
import org.springframework.ldap.core.LdapRdn;
|
||||
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
/**
|
||||
* BasicSchemaSpecification establishes a minimal set of requirements for object classes.
|
||||
* <p>
|
||||
* This basic specification, which does not actually validate against any schema, deems objects
|
||||
* valid as long as they meet the following criteria:
|
||||
* <ul>
|
||||
* <li>the object has a non-null DN.</li>
|
||||
* <li>the object contains the naming attribute declared by the DN.</li>
|
||||
* <li>the object declares an objectClass.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class BasicSchemaSpecification implements Specification<LdapAttributes> {
|
||||
|
||||
/**
|
||||
* Determines if the policy is satisfied by the supplied LdapAttributes object.
|
||||
*
|
||||
* @throws NamingException
|
||||
*/
|
||||
public boolean isSatisfiedBy(LdapAttributes record) throws NamingException {
|
||||
if (record != null) {
|
||||
|
||||
//DN is required.
|
||||
DistinguishedName dn = record.getDN();
|
||||
if (dn != null) {
|
||||
|
||||
//objectClass definition is required.
|
||||
if (record.get("objectClass") != null) {
|
||||
|
||||
//Naming attribute is required.
|
||||
LdapRdn rdn = dn.getLdapRdn(dn.size() - 1);
|
||||
if (record.get(rdn.getKey()) != null) {
|
||||
Object object = record.get(rdn.getKey()).get();
|
||||
|
||||
if (object instanceof String) {
|
||||
String value = (String) object;
|
||||
if (rdn.getValue().equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
} else if(object instanceof byte[]) {
|
||||
BASE64Encoder encoder = new BASE64Encoder();
|
||||
String rdnValue = encoder.encode(rdn.getValue().getBytes());
|
||||
String attributeValue = encoder.encode((byte[]) object);
|
||||
if (rdnValue.equals(attributeValue)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.schema;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
|
||||
/**
|
||||
* DefaultSchemaSpecification does not validate objects at all - it simply returns true.
|
||||
* <p>
|
||||
* This specification is intended for cases where validation of the parsed entries is not
|
||||
* required.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class DefaultSchemaSpecification implements Specification<LdapAttributes> {
|
||||
|
||||
/**
|
||||
* Determines if the policy is satisfied by the supplied LdapAttributes object.
|
||||
*
|
||||
* @throws NamingException
|
||||
*/
|
||||
public boolean isSatisfiedBy(LdapAttributes record) throws NamingException {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2005-2009 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.ldap.schema;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* The specification interface is implemented to declare rules that
|
||||
* a record must conform to. The motivation behind this class was
|
||||
* to provide a mechanism to enable schema validations.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface Specification<T> {
|
||||
|
||||
boolean isSatisfiedBy(T record) throws NamingException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This package is aimed at providing a mechanism to implement LDAP schemas.
|
||||
<p>
|
||||
Utilized by the LDIFParser to validate object composition post assembly, these
|
||||
classes may also be referenced by other utilities where seen fit.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
13
ldif/ldif-core/src/main/java/overview.html
Normal file
13
ldif/ldif-core/src/main/java/overview.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Insert title here</title>
|
||||
</head>
|
||||
<body>
|
||||
This document is the API specification for the Spring LDAP LDIF Parser and its associated utilities.
|
||||
<p>
|
||||
This series of packages provides an LDIF parser utility compliant with
|
||||
"RFC 2849 : The LDAP Data Interchange Format (LDIF) - Technical Specification".
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
package org.springframework.ldap.ldif;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.springframework.ldap.core.LdapAttribute;
|
||||
import org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy;
|
||||
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
/**
|
||||
* Parses a preselected set of attributes to test the full spectrum of functionality
|
||||
* expected of an attribute parser. Attributes are validated to ensure they conform to
|
||||
* the requirements for attribute values prescribed in RFC2849.
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class DefaultAttributeValidationPolicyTest {
|
||||
|
||||
private static Log log = LogFactory.getLog(DefaultAttributeValidationPolicyTest.class);
|
||||
|
||||
private static DefaultAttributeValidationPolicy policy = new DefaultAttributeValidationPolicy();
|
||||
|
||||
private static enum AttributeType { STRING, BASE64, URL }
|
||||
|
||||
private String line;
|
||||
private String id;
|
||||
private String options;
|
||||
private String value;
|
||||
private AttributeType type;
|
||||
|
||||
private List<String> exceptions = Arrays.asList(new String[] {
|
||||
"description: :A big sailing fan.",
|
||||
"cn;lang-ja:: 5bCP56yg5Y6fIO.ODreODieODi+ODvA==",
|
||||
"url:< http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28"
|
||||
});
|
||||
|
||||
/**
|
||||
* The data set to parse.
|
||||
* @return
|
||||
*/
|
||||
@Parameters
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
//Format: line, id, options, value, type
|
||||
|
||||
//String
|
||||
{ "cn: Keith Barlow", "cn", "", "Keith Barlow", AttributeType.STRING},
|
||||
{ "sn: Jensen", "sn", "", "Jensen", AttributeType.STRING},
|
||||
{ "cn: Barbara J Jensen", "cn", "", "Barbara J Jensen", AttributeType.STRING},
|
||||
{ "telephonenumber: +1 408 555 1212", "telephonenumber", "", "+1 408 555 1212", AttributeType.STRING},
|
||||
{ "description: A big sailing fan.", "description", "", "A big sailing fan.", AttributeType.STRING},
|
||||
{ "title;lang-en;phonetic: Sales, Director", "title", ";lang-en;phonetic", "Sales, Director", AttributeType.STRING},
|
||||
{ "mail: rogasawara@airius.co.jp", "mail", "", "rogasawara@airius.co.jp", AttributeType.STRING},
|
||||
{ "description: A big sailing fan.", "description", "", "A big sailing fan.", AttributeType.STRING},
|
||||
{ "description: :A big sailing fan.", "description", "", ":A big sailing fan.", AttributeType.STRING},
|
||||
|
||||
//Base64
|
||||
{ "xml:: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4=", "xml", "", "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4=", AttributeType.BASE64},
|
||||
{ "ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2", "ou", ";lang-ja;phonetic", "44GI44GE44GO44KH44GG44G2", AttributeType.BASE64 },
|
||||
{ "dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz", "dn", "", "dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz", AttributeType.BASE64 },
|
||||
{ "cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==", "cn", ";lang-ja", "5bCP56yg5Y6fIOODreODieODi+ODvA==", AttributeType.BASE64 },
|
||||
{ "cn;lang-ja:: 5bCP56yg5Y6fIO.ODreODieODi+ODvA==", "cn", ";lang-ja", "5bCP56yg5Y6fIO.ODreODieODi+ODvA==", AttributeType.BASE64 },
|
||||
|
||||
//Url
|
||||
{ "url:< http://www.oracle.com/", "url", "", "http://www.oracle.com/", AttributeType.URL},
|
||||
{ "url:< http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html", "url", "", "http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html", AttributeType.URL},
|
||||
{ "url:< ftp://kbarlow:test@ftp.is.co.za/rfc/rfc1808.txt", "url", "", "ftp://kbarlow:test@ftp.is.co.za/rfc/rfc1808.txt", AttributeType.URL},
|
||||
{ "url;option:< ftp://ftp.is.co.za:2100/rfc/rfc1808.txt;type=a", "url", ";option", "ftp://ftp.is.co.za:2100/rfc/rfc1808.txt;type=a", AttributeType.URL},
|
||||
{ "url:< telnet://kbarlow@melvyl.ucop.edu/", "url", "", "telnet://kbarlow@melvyl.ucop.edu/", AttributeType.URL},
|
||||
{ "url;option1;option2:< telnet://kbarlow:test@melvyl.ucop.edu/", "url", ";option1;option2", "telnet://kbarlow:test@melvyl.ucop.edu/", AttributeType.URL},
|
||||
{ "url:< gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles", "url", "", "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles", AttributeType.URL},
|
||||
{ "url:< file:///usr/local/directory/photos/fiona.jpg", "url", "", "file:///usr/local/directory/photos/fiona.jpg", AttributeType.URL},
|
||||
{ "url:< mailto:java-net@java.sun.com", "url", "", "mailto:java-net@java.sun.com", AttributeType.URL},
|
||||
{ "url:< news:comp.infosystems.www.servers.unix", "url", "", "news:comp.infosystems.www.servers.unix", AttributeType.URL},
|
||||
{ "url:< prospero://host.dom:1525//pros/name;key=value", "url", "", "prospero://host.dom:1525//pros/name;key=value", AttributeType.URL},
|
||||
{ "url:< nntp://news.cs.hut.fi/alt.html/239157", "url", "", "nntp://news.cs.hut.fi/alt.html/239157", AttributeType.URL},
|
||||
{ "url:< wais://vega.lib.ncsu.edu/alawon.src?nren", "url", "", "wais://vega.lib.ncsu.edu/alawon.src?nren", AttributeType.URL},
|
||||
{ "url:< http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28", "url", "", "http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28", AttributeType.URL}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* DefaultAttributeValidationPolicyTest: Parameterized constructor.
|
||||
* @param line The attribute to parse.
|
||||
* @param id The ID portion of the attribute expected on successful parsing.
|
||||
* @param options The Options expected on successful parsing.
|
||||
* @param value The value expected from successful parsing.
|
||||
* @param type The attribute type: one of enum AttributeType.
|
||||
*/
|
||||
public DefaultAttributeValidationPolicyTest(String line, String id, String options, String value, AttributeType type) {
|
||||
this.line = line;
|
||||
this.id = id;
|
||||
this.options = options;
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The test case: parses passed in parameters and validates the outcome against the expected results.
|
||||
*/
|
||||
@Test
|
||||
public void parseAttribute() {
|
||||
try {
|
||||
LdapAttribute attribute = (LdapAttribute) policy.parse(line);
|
||||
|
||||
assertTrue("IDs do not match: [expected: " + attribute.getID() + ", obtained: " + id + "]", id.equalsIgnoreCase(attribute.getID()));
|
||||
|
||||
String[] expected = StringUtils.isEmpty(options) ? new String[] {} : options.replaceFirst(";","").split(";");
|
||||
Arrays.sort(expected);
|
||||
String[] obtained = attribute.getOptions().toArray(new String[] {});
|
||||
Arrays.sort(obtained);
|
||||
assertArrayEquals("Options do not match: ", expected, obtained);
|
||||
|
||||
switch(type) {
|
||||
case STRING:
|
||||
assertTrue("Value is not a string.", attribute.get() instanceof String);
|
||||
assertEquals("Values do not match: ", value, (String) attribute.get());
|
||||
break;
|
||||
|
||||
case BASE64:
|
||||
byte[] bytes = new BASE64Decoder().decodeBuffer(value);
|
||||
assertTrue("Value is not a byte[].", attribute.get() instanceof byte[]);
|
||||
assertArrayEquals("Values do not match: ", bytes, (byte[]) attribute.get());
|
||||
break;
|
||||
|
||||
case URL:
|
||||
URI url = new URI(value);
|
||||
assertTrue("Value is not a URL.", attribute.get() instanceof URI);
|
||||
assertEquals("Values do not match: ", url, (URI) attribute.get());
|
||||
break;
|
||||
}
|
||||
|
||||
log.info("Success!");
|
||||
|
||||
} catch (Exception e) {
|
||||
if (!exceptions.contains(line))
|
||||
fail("Exception thrown: " + e.getClass().getSimpleName() + " (message: " + e.getMessage() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package org.springframework.ldap.ldif;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.ldap.core.LdapAttributes;
|
||||
import org.springframework.ldap.ldif.parser.LdifParser;
|
||||
import org.springframework.ldap.schema.BasicSchemaSpecification;
|
||||
|
||||
/**
|
||||
* Unit test for LdifParser.
|
||||
*
|
||||
* Test results in complete end to end test of all LdifParser functionality:
|
||||
* 1.) Open a file
|
||||
* 2.) Read lines and compose an attribute.
|
||||
* 3.) Parse the attribute and create a LdapAttribute object.
|
||||
* 4.) Repeat until end of record (Identify end of record).
|
||||
* 5.) Return a valid LdapAttributes object.
|
||||
* 6.) Close file upon completion.
|
||||
*
|
||||
* Provided test file is comprised of sample LDIFs from RFC2849 and exhausts the full range of
|
||||
* the functionality prescribed by RFC2849 for the LDAP Data Interchange Format (LDIF).
|
||||
*
|
||||
* @author Keith Barlow
|
||||
*
|
||||
*/
|
||||
public class LdifParserTest {
|
||||
|
||||
private static Log log = LogFactory.getLog(LdifParserTest.class);
|
||||
|
||||
private LdifParser parser;
|
||||
|
||||
/**
|
||||
* Default constructor: loads a preselected resource with sample LDIF entries.
|
||||
* Each entry is parsed and checked for a DN and objectclass. Output is printed for visual verification
|
||||
* of LDIF correctness.
|
||||
*/
|
||||
public LdifParserTest() {
|
||||
parser = new LdifParser(new ClassPathResource("test.ldif"));
|
||||
parser.setRecordSpecification(new BasicSchemaSpecification());
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup: opens file.
|
||||
*/
|
||||
@Before
|
||||
public void openLdif() {
|
||||
try {
|
||||
parser.open();
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes test: reads all records from LDIF file and validates an LdapAttributes object is successfully created.
|
||||
*/
|
||||
@Test
|
||||
public void parseLdif() {
|
||||
int count = 0;
|
||||
|
||||
try {
|
||||
LdapAttributes attributes;
|
||||
|
||||
while (parser.hasMoreRecords()) {
|
||||
try {
|
||||
attributes = parser.getRecord();
|
||||
log.info("attributes:\n" + attributes);
|
||||
if (attributes != null) {
|
||||
assertTrue("A dn is required.", attributes.getDN() != null);
|
||||
assertTrue("Object class is required.", attributes.get("objectclass") != null);
|
||||
count++;
|
||||
}
|
||||
} catch (InvalidAttributeFormatException e) {
|
||||
log.error(e);
|
||||
if (count != 6) fail();
|
||||
}
|
||||
|
||||
log.debug("hasMoreRecords: " + parser.hasMoreRecords());
|
||||
}
|
||||
|
||||
log.info("record count: " + count);
|
||||
//assertTrue("An incorrect number of records were parsed.", count == 8);
|
||||
|
||||
log.info("Done!");
|
||||
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup: closes file.
|
||||
*/
|
||||
@After
|
||||
public void closeLdif() {
|
||||
try {
|
||||
parser.close();
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
6
ldif/ldif-core/src/test/resources/log4j.properties
Normal file
6
ldif/ldif-core/src/test/resources/log4j.properties
Normal file
@@ -0,0 +1,6 @@
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
|
||||
log4j.appender.console.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
|
||||
|
||||
log4j.logger.org.springframework.ldap.ldif=INFO, console
|
||||
235
ldif/ldif-core/src/test/resources/test.ldif
Normal file
235
ldif/ldif-core/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
|
||||
74
ldif/pom.xml
Normal file
74
ldif/pom.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-parent</artifactId>
|
||||
<version>1.3.1.CI-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.ldap.ldif</groupId>
|
||||
<artifactId>spring-ldap-ldif</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring LDAP LDIF</name>
|
||||
<description>This packages provides an LDIF Parser for use with the Spring LDAP suite of utilities.</description>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
<show>public</show>
|
||||
<links>
|
||||
<link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
|
||||
<link>http://static.springsource.org/spring/docs/2.5.x/api/</link>
|
||||
<link>http://static.springsource.org/spring-ldap/docs/1.3.x/apidocs/</link>
|
||||
<link>http://static.springsource.org/spring-batch/apidocs/</link>
|
||||
</links>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<modules>
|
||||
<module>ldif-core</module>
|
||||
<module>ldif-batch</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap</artifactId>
|
||||
<version>${version}</version>
|
||||
<classifier>all</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
25
parent/tiger/pom.xml
Normal file
25
parent/tiger/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-parent</artifactId>
|
||||
<version>1.3.1.CI-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-ldap-parent-tiger</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring LDAP - Parent Tiger</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Building -->
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
Reference in New Issue
Block a user