LDAP-234: Rollback intermittently causes data loss

Moved stuff related to LDAP-176 from sandbox to core.
Minor formatting tweaks.
This commit is contained in:
Mattias Hellborg Arthursson
2013-07-30 12:46:26 +02:00
parent 895af4a44f
commit 79a922c778
11 changed files with 486 additions and 483 deletions

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2005-2010 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.support.ad;
/**
* @since 1.3.2
* @author Marius Scurtescu
*/
public interface AttributeValueProcessor {
public void process(Object value);
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2005-2010 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.support.ad;
import org.springframework.ldap.core.AttributesMapper;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
/**
* Utility class that helps with reading all attribute values from Active Directory using <em>Incremental Retrieval of
* Multi-valued Properties</em>.
* <p/>
* <p>Example usage of this attribute mapper:
* <pre>
* public void retrieveAttributeIncrementally(LdapTemplate ldap, LdapName entrDn, String attributeName, AttributeValueProcessor valueProcessor)
* {
* IncrementalAttributeMapper incrementalAttributeMapper = new IncrementalAttributeMapper(attributeName, valueProcessor);
*
* while (incrementalAttributeMapper.hasMore())
* {
* ldap.lookup(entrDn, incrementalAttributeMapper.getAttributesArray(), incrementalAttributeMapper);
* }
* }
* </pre>
*
* @author Marius Scurtescu
* @see <a href="http://www.watersprings.org/pub/id/draft-kashi-incremental-00.txt">Incremental Retrieval of Multi-valued Properties</a>
* @since 1.3.2
*/
public class IncrementalAttributeMapper implements AttributesMapper {
private final String attributeName;
private final AttributeValueProcessor valueProcessor;
private boolean more = true;
private int pageSize;
private RangeOption requestRange = new RangeOption(0, pageSize);
private boolean omitFullRange = true;
public IncrementalAttributeMapper(String attributeName, AttributeValueProcessor valueProcessor) {
this(attributeName, valueProcessor, RangeOption.TERMINAL_END_OF_RANGE);
}
public IncrementalAttributeMapper(String attributeName, AttributeValueProcessor valueProcessor, int pageSize) {
this.attributeName = attributeName;
this.pageSize = pageSize;
this.requestRange = new RangeOption(0, pageSize);
this.valueProcessor = valueProcessor;
}
public boolean isOmitFullRange() {
return omitFullRange;
}
public void setOmitFullRange(boolean omitFullRange) {
this.omitFullRange = omitFullRange;
}
public Object mapFromAttributes(Attributes attributes) throws NamingException {
if (!more) {
throw new IllegalStateException("No more attributes!");
}
more = false;
NamingEnumeration attributeNameEnum = attributes.getIDs();
while (attributeNameEnum.hasMore()) {
String attributeName = (String) attributeNameEnum.next();
if (attributeName.equals(this.attributeName)) {
processValues(attributes, this.attributeName);
} else if (attributeName.startsWith(this.attributeName + ";")) {
String[] attributeNameSplit = attributeName.split(";");
for (int i = 0; i < attributeNameSplit.length; i++) {
String option = attributeNameSplit[i];
RangeOption responseRange = RangeOption.parse(option);
if (responseRange != null) {
more = requestRange.compareTo(responseRange) > 0;
if (more) {
requestRange = responseRange.nextRange(pageSize);
}
processValues(attributes, attributeName);
}
}
}
}
return this;
}
private void processValues(Attributes attributes, String attributeName) throws NamingException {
Attribute attribute = attributes.get(attributeName);
NamingEnumeration valueEnum = attribute.getAll();
while (valueEnum.hasMore()) {
valueProcessor.process(valueEnum.next());
}
}
public boolean hasMore() {
return more;
}
public String[] getAttributesArray() {
StringBuilder attributeBuilder = new StringBuilder(attributeName);
if (!(omitFullRange && requestRange.isFullRange())) {
attributeBuilder.append(';');
requestRange.toString(attributeBuilder);
}
return new String[]{attributeBuilder.toString()};
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2005-2010 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.support.ad;
import java.util.LinkedList;
import java.util.List;
/**
* @since 1.3.2
* @author Marius Scurtescu
*/
public class ListAttributeValueProcessor implements AttributeValueProcessor {
private List values = new LinkedList();
public void process(Object value) {
values.add(value);
}
public List getValues() {
return values;
}
}

View File

@@ -1,4 +1,19 @@
package org.springframework.ldap.util;
/*
* Copyright 2005-2010 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.support.ad;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -7,66 +22,62 @@ import java.util.regex.Matcher;
* Attribute name Range Option used for <em>Incremental Retrieval of
* Multi-valued Properties</em>.
*
* @see org.springframework.ldap.util.IncrementalAttributeMapper
* @author Marius Scurtescu
*/
public class RangeOption implements Comparable<RangeOption>
{
*
* @see IncrementalAttributeMapper
* @since 1.3.2
*/
public class RangeOption implements Comparable {
public static final int TERMINAL_END_OF_RANGE = -1;
public static final int TERMINAL_MISSING = -2;
private int _initial = 0;
private int _terminal = TERMINAL_END_OF_RANGE;
private int initial = 0;
private int terminal = TERMINAL_END_OF_RANGE;
private static Pattern RANGE_PATTERN = Pattern.compile("^Range=([0-9]+)(-([0-9]+|\\*))?$", Pattern.CASE_INSENSITIVE);
public RangeOption(int initial)
{
public RangeOption(int initial) {
this(initial, TERMINAL_END_OF_RANGE);
}
public RangeOption(int initial, int terminal)
{
if (terminal < 0 && (terminal != TERMINAL_END_OF_RANGE && terminal != TERMINAL_MISSING))
public RangeOption(int initial, int terminal) {
if (terminal < 0 && (terminal != TERMINAL_END_OF_RANGE && terminal != TERMINAL_MISSING)) {
throw new IllegalArgumentException("Illegal range-terminal: " + terminal);
}
if (initial < 0)
if (initial < 0) {
throw new IllegalArgumentException("Illegal range-initial: " + initial);
}
if (terminal >= 0 && terminal < initial)
if (terminal >= 0 && terminal < initial) {
throw new IllegalArgumentException("range-terminal cannot be smaller than range-initial: " + initial + "-" + terminal);
}
_initial = initial;
_terminal = terminal;
this.initial = initial;
this.terminal = terminal;
}
public boolean isTerminalEndOfRange()
{
return _terminal == TERMINAL_END_OF_RANGE;
public boolean isTerminalEndOfRange() {
return terminal == TERMINAL_END_OF_RANGE;
}
public boolean isTerminalMissing()
{
return _terminal == TERMINAL_MISSING;
public boolean isTerminalMissing() {
return terminal == TERMINAL_MISSING;
}
public int getInitial()
{
return _initial;
public int getInitial() {
return initial;
}
public int getTerminal()
{
return _terminal;
public int getTerminal() {
return terminal;
}
public boolean isFullRange()
{
public boolean isFullRange() {
return getInitial() == 0 && getTerminal() == TERMINAL_END_OF_RANGE;
}
public String toString()
{
public String toString() {
StringBuilder rangeBuilder = new StringBuilder();
toString(rangeBuilder);
@@ -74,37 +85,34 @@ public class RangeOption implements Comparable<RangeOption>
return rangeBuilder.toString();
}
public void toString(StringBuilder rangeBuilder)
{
rangeBuilder.append("Range=").append(_initial);
public void toString(StringBuilder rangeBuilder) {
rangeBuilder.append("Range=").append(initial);
if (!isTerminalMissing())
{
if (!isTerminalMissing()) {
rangeBuilder.append('-');
if (isTerminalEndOfRange())
rangeBuilder.append('*');
else
rangeBuilder.append(_terminal);
rangeBuilder.append(terminal);
}
}
public static RangeOption parse(String option)
{
public static RangeOption parse(String option) {
Matcher rangeMatcher = RANGE_PATTERN.matcher(option);
rangeMatcher.find();
if (!rangeMatcher.matches())
if (!rangeMatcher.matches()) {
return null;
}
String initialStr = rangeMatcher.group(1);
int initial = Integer.parseInt(initialStr);
int initial = Integer.parseInt(initialStr);
int terminal = TERMINAL_MISSING;
if (rangeMatcher.group(2) != null)
{
if (rangeMatcher.group(2) != null) {
String terminalStr = rangeMatcher.group(3);
if ("*".equals(terminalStr))
@@ -116,38 +124,50 @@ public class RangeOption implements Comparable<RangeOption>
return new RangeOption(initial, terminal);
}
public int compareTo(RangeOption that)
{
public int compareTo(Object o) {
RangeOption that;
if (o instanceof RangeOption) {
that = (RangeOption) o;
} else {
throw new IllegalArgumentException("A RangeOption instance cannot be compared to " + o.getClass());
}
if (this.getInitial() != that.getInitial())
throw new IllegalStateException("Ranges cannot be compared, range-initial not the same: " + this.toString() + " vs " + that.toString());
if (this.getTerminal() == that.getTerminal())
if (this.getTerminal() == that.getTerminal()) {
return 0;
}
if (that.getTerminal() == TERMINAL_MISSING)
if (that.getTerminal() == TERMINAL_MISSING) {
throw new IllegalStateException("Don't know how to deal with missing range-terminal: " + that.toString());
}
if (this.getTerminal() == TERMINAL_MISSING)
if (this.getTerminal() == TERMINAL_MISSING) {
throw new IllegalStateException("Don't know how to deal with missing range-terminal: " + this.toString());
}
if (this.getTerminal() == TERMINAL_END_OF_RANGE)
if (this.getTerminal() == TERMINAL_END_OF_RANGE) {
return 1;
}
if (that.getTerminal() == TERMINAL_END_OF_RANGE)
if (that.getTerminal() == TERMINAL_END_OF_RANGE) {
return -1;
}
return this.getTerminal() > that.getTerminal() ? 1 : -1;
}
public RangeOption nextRange(int pageSize)
{
if (getTerminal() < 0)
public RangeOption nextRange(int pageSize) {
if (getTerminal() < 0) {
throw new IllegalStateException("Cannot generate next range, range-terminal: " + getTerminal());
}
if (pageSize < 0 && pageSize != TERMINAL_END_OF_RANGE)
if (pageSize < 0 && pageSize != TERMINAL_END_OF_RANGE) {
throw new IllegalArgumentException("Invalid page size: " + pageSize);
}
int initial = getTerminal() + 1;
int initial = getTerminal() + 1;
int terminal = pageSize == TERMINAL_END_OF_RANGE ? TERMINAL_END_OF_RANGE : getTerminal() + pageSize;
return new RangeOption(initial, terminal);

View File

@@ -0,0 +1,7 @@
<html>
<body>
Support classes for Active Directory-specific functionality.
</body>
</html>

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2005-2010 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.support.ad;
import junit.framework.TestCase;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
/**
* IncrementalAttributeMapper Tester.
*
* @author Marius Scurtescu
*/
public class IncrementalAttributeMapperTest extends TestCase {
private IncrementalAttributeMapper incrementalAttributeMapper;
private ListAttributeValueProcessor valueProcessor;
public IncrementalAttributeMapperTest(String name) {
super(name);
}
public void setUp() throws Exception {
valueProcessor = new ListAttributeValueProcessor();
incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor);
}
public void tearDown() throws Exception {
incrementalAttributeMapper = null;
valueProcessor = null;
}
public void testGetAttributesArray() throws Exception {
String[] attributes = incrementalAttributeMapper.getAttributesArray();
assertEquals(1, attributes.length);
assertEquals("member", attributes[0]);
incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 10);
attributes = incrementalAttributeMapper.getAttributesArray();
assertEquals(1, attributes.length);
assertEquals("member;Range=0-10", attributes[0]);
}
public void testLoopEmpty() throws Exception {
assertTrue(incrementalAttributeMapper.hasMore());
Attributes attributes = new BasicAttributes();
incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(incrementalAttributeMapper.hasMore());
assertEquals(0, valueProcessor.getValues().size());
}
public void testLoop() throws Exception {
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertTrue(incrementalAttributeMapper.hasMore());
assertEquals(11, valueProcessor.getValues().size());
attributes = createAttributes(new RangeOption(11), 5, false);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(incrementalAttributeMapper.hasMore());
assertEquals(16, valueProcessor.getValues().size());
}
public void test1LoopWithPageSizeExact() throws Exception {
incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 10);
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(incrementalAttributeMapper.hasMore());
assertEquals(11, valueProcessor.getValues().size());
}
public void test2LoopsWithPageSizeExact() throws Exception {
incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 20);
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertTrue(incrementalAttributeMapper.hasMore());
assertEquals(11, valueProcessor.getValues().size());
attributes = createAttributes(new RangeOption(11, 30), false);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(incrementalAttributeMapper.hasMore());
assertEquals(31, valueProcessor.getValues().size());
}
public void test2LoopsWithPageSize() throws Exception {
incrementalAttributeMapper = new IncrementalAttributeMapper("member", valueProcessor, 20);
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertTrue(incrementalAttributeMapper.hasMore());
assertEquals(11, valueProcessor.getValues().size());
attributes = createAttributes(new RangeOption(11), 5, false);
incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(incrementalAttributeMapper.hasMore());
assertEquals(16, valueProcessor.getValues().size());
}
private Attributes createAttributes(RangeOption range, boolean emptyPlain) {
return createAttributes(range, range.getTerminal() - range.getInitial() + 1, emptyPlain);
}
private Attributes createAttributes(RangeOption range, int valueCnt, boolean emptyPlain) {
Attributes attributes = new BasicAttributes();
if (emptyPlain) {
attributes.put(new BasicAttribute("member"));
}
Attribute attribute = new BasicAttribute("member;" + range.toString());
for (int i = 0; i < valueCnt; i++) {
attribute.add("value" + (range.getInitial() + i - 1));
}
attributes.put(attribute);
return attributes;
}
}

View File

@@ -1,7 +1,20 @@
package org.springframework.ldap.util;
/*
* Copyright 2005-2010 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.support.ad;
import junit.framework.Test;
import junit.framework.TestSuite;
import junit.framework.TestCase;
/**
@@ -9,115 +22,79 @@ import junit.framework.TestCase;
*
* @author Marius Scurtescu
*/
public class RangeOptionTest extends TestCase
{
public RangeOptionTest(String name)
{
public class RangeOptionTest extends TestCase {
public RangeOptionTest(String name) {
super(name);
}
public void setUp() throws Exception
{
super.setUp();
}
public void tearDown() throws Exception
{
super.tearDown();
}
public void testConstructorInvalid()
{
try
{
public void testConstructorInvalid() {
try {
new RangeOption(101, 100);
fail();
}
catch (IllegalArgumentException e)
{
// ignore
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try
{
try {
new RangeOption(-1, 100);
fail();
}
catch (IllegalArgumentException e)
{
// ignore
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try
{
try {
new RangeOption(-10, 100);
fail();
}
catch (IllegalArgumentException e)
{
// ignore
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try
{
try {
new RangeOption(0, -3);
fail();
}
catch (IllegalArgumentException e)
{
// ignore
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testToString() throws Exception
{
public void testToString() throws Exception {
RangeOption range = new RangeOption(0, 100);
assertEquals("Range=0-100", range.toString());
range = new RangeOption(0, RangeOption.TERMINAL_END_OF_RANGE);
assertEquals("Range=0-*", range.toString());
range = new RangeOption(0, RangeOption.TERMINAL_MISSING);
assertEquals("Range=0", range.toString());
}
public void testParse() throws Exception
{
public void testParse() throws Exception {
RangeOption range = RangeOption.parse("Range=0-100");
assertEquals(0, range.getInitial());
assertEquals(100, range.getTerminal());
range = RangeOption.parse("range=0-100");
assertEquals(0, range.getInitial());
assertEquals(100, range.getTerminal());
range = RangeOption.parse("RANGE=0-100");
assertEquals(0, range.getInitial());
assertEquals(100, range.getTerminal());
range = RangeOption.parse("Range=0-*");
assertEquals(0, range.getInitial());
assertEquals(RangeOption.TERMINAL_END_OF_RANGE, range.getTerminal());
range = RangeOption.parse("Range=10");
assertEquals(10, range.getInitial());
assertEquals(RangeOption.TERMINAL_MISSING, range.getTerminal());
}
public void testParseInvalid()
{
public void testParseInvalid() {
assertNull(RangeOption.parse("Range=10-"));
assertNull(RangeOption.parse("Range=10-a"));
assertNull(RangeOption.parse("lang-en"));
@@ -127,106 +104,81 @@ public class RangeOptionTest extends TestCase
assertNull(RangeOption.parse("Range=10-100;lang-de"));
}
public void testCompare()
{
public void testCompare() {
RangeOption range1 = RangeOption.parse("Range=10-500");
RangeOption range2 = RangeOption.parse("Range=10-500");
assertTrue(range1.compareTo(range2) == 0);
assertTrue(range2.compareTo(range1) == 0);
range1 = RangeOption.parse("Range=0-*");
range2 = RangeOption.parse("Range=0-*");
assertTrue(range1.compareTo(range2) == 0);
assertTrue(range2.compareTo(range1) == 0);
range1 = RangeOption.parse("Range=0");
range2 = RangeOption.parse("Range=0");
assertTrue(range1.compareTo(range2) == 0);
assertTrue(range2.compareTo(range1) == 0);
range1 = RangeOption.parse("Range=0-101");
range2 = RangeOption.parse("Range=0-100");
assertTrue(range1.compareTo(range2) > 0);
assertTrue(range2.compareTo(range1) < 0);
range1 = RangeOption.parse("Range=0-*");
range2 = RangeOption.parse("Range=0-100");
assertTrue(range1.compareTo(range2) > 0);
assertTrue(range2.compareTo(range1) < 0);
}
public void testCompareInvalid()
{
public void testCompareInvalid() {
RangeOption range1 = RangeOption.parse("Range=10-500");
RangeOption range2 = RangeOption.parse("Range=11-500");
try
{
try {
assertTrue(range1.compareTo(range2) == 0);
fail();
}
catch (IllegalStateException e)
{
// ignore
fail("IllegalStateException expected");
} catch (IllegalStateException expected) {
assertTrue(true);
}
range1 = RangeOption.parse("Range=10");
range2 = RangeOption.parse("Range=10-500");
try
{
try {
assertTrue(range1.compareTo(range2) == 0);
fail();
}
catch (IllegalStateException e)
{
// ignore
fail("IllegalStateException expected");
} catch (IllegalStateException expected) {
assertTrue(true);
}
range1 = RangeOption.parse("Range=10-500");
range2 = RangeOption.parse("Range=10");
try
{
try {
assertTrue(range1.compareTo(range2) == 0);
fail();
}
catch (IllegalStateException e)
{
// ignore
fail("IllegalStateException expected");
} catch (IllegalStateException expected) {
assertTrue(true);
}
}
public void testNext()
{
public void testNext() {
RangeOption range = RangeOption.parse("Range=0-100");
range = range.nextRange(100);
assertEquals(101, range.getInitial());
assertEquals(200, range.getTerminal());
range = range.nextRange(10);
assertEquals(201, range.getInitial());
assertEquals(210, range.getTerminal());
range = range.nextRange(RangeOption.TERMINAL_END_OF_RANGE);
assertEquals(211, range.getInitial());
assertEquals(RangeOption.TERMINAL_END_OF_RANGE, range.getTerminal());
}
public static Test suite()
{
return new TestSuite(RangeOptionTest.class);
}
}

View File

@@ -1,9 +0,0 @@
package org.springframework.ldap.util;
/**
* @author Marius Scurtescu
*/
public interface AttributeValueProcessor
{
public void process(Object value);
}

View File

@@ -1,133 +0,0 @@
package org.springframework.ldap.util;
import org.springframework.ldap.core.AttributesMapper;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
/**
* Utility class that helps with reading all attribute values from Active Directory using <em>Incremental Retrieval of
* Multi-valued Properties</em>.
*
* <p>Example usage of this attribute mapper:
* <pre>
* public void retrieveAttributeIncrementally(LdapTemplate ldap, LdapName entrDn, String attributeName, AttributeValueProcessor valueProcessor)
* {
* IncrementalAttributeMapper incrementalAttributeMapper = new IncrementalAttributeMapper(attributeName, valueProcessor);
*
* while (incrementalAttributeMapper.hasMore())
* {
* ldap.lookup(entrDn, incrementalAttributeMapper.getAttributesArray(), incrementalAttributeMapper);
* }
* }
* </pre>
*
* @author Marius Scurtescu
* @see <a href="http://www.watersprings.org/pub/id/draft-kashi-incremental-00.txt">Incremental Retrieval of Multi-valued Properties</a>
*/
public class IncrementalAttributeMapper implements AttributesMapper
{
private String _attributeName;
private boolean _more = true;
private int _pageSize = RangeOption.TERMINAL_END_OF_RANGE;
private RangeOption _requestRange = new RangeOption(0, _pageSize);
private AttributeValueProcessor _valueProcessor;
private boolean _omitFullRange = true;
public IncrementalAttributeMapper(String attributeName, AttributeValueProcessor valueProcessor)
{
_attributeName = attributeName;
_valueProcessor = valueProcessor;
}
public IncrementalAttributeMapper(String attributeName, AttributeValueProcessor valueProcessor, int pageSize)
{
_attributeName = attributeName;
_pageSize = pageSize;
_requestRange = new RangeOption(0, pageSize);
_valueProcessor = valueProcessor;
}
public boolean isOmitFullRange()
{
return _omitFullRange;
}
public void setOmitFullRange(boolean omitFullRange)
{
_omitFullRange = omitFullRange;
}
public Object mapFromAttributes(Attributes attributes) throws NamingException
{
if (!_more)
throw new IllegalStateException("No more attributes!");
_more = false;
NamingEnumeration<String> attributeNameEnum = attributes.getIDs();
while (attributeNameEnum.hasMore())
{
String attributeName = attributeNameEnum.next();
if (attributeName.equals(_attributeName))
{
processValues(attributes, _attributeName);
}
else if (attributeName.startsWith(_attributeName + ";"))
{
for (String option : attributeName.split(";"))
{
RangeOption responseRange = RangeOption.parse(option);
if (responseRange != null)
{
_more = _requestRange.compareTo(responseRange) > 0;
if (_more)
{
_requestRange = responseRange.nextRange(_pageSize);
}
processValues(attributes, attributeName);
}
}
}
}
return this;
}
private void processValues(Attributes attributes, String attributeName) throws NamingException
{
Attribute attribute = attributes.get(attributeName);
NamingEnumeration valueEnum = attribute.getAll();
while (valueEnum.hasMore())
{
_valueProcessor.process(valueEnum.next());
}
}
public boolean hasMore()
{
return _more;
}
public String [] getAttributesArray()
{
StringBuilder attributeBuilder = new StringBuilder(_attributeName);
if (!(_omitFullRange && _requestRange.isFullRange()))
{
attributeBuilder.append(';');
_requestRange.toString(attributeBuilder);
}
return new String[]{attributeBuilder.toString()};
}
}

View File

@@ -1,22 +0,0 @@
package org.springframework.ldap.util;
import java.util.List;
import java.util.ArrayList;
/**
* @author Marius Scurtescu
*/
public class ListAttributeValueProcessor implements AttributeValueProcessor
{
private List<String> _values = new ArrayList<String>();
public void process(Object value)
{
_values.add((String) value);
}
public List<String> getValues()
{
return _values;
}
}

View File

@@ -1,162 +0,0 @@
package org.springframework.ldap.util;
import junit.framework.Test;
import junit.framework.TestSuite;
import junit.framework.TestCase;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.Attribute;
/**
* IncrementalAttributeMapper Tester.
*
* @author Marius Scurtescu
*/
public class IncrementalAttributeMapperTest extends TestCase
{
private IncrementalAttributeMapper _incrementalAttributeMapper;
private ListAttributeValueProcessor _valueProcessor;
public IncrementalAttributeMapperTest(String name)
{
super(name);
}
public void setUp() throws Exception
{
super.setUp();
_valueProcessor = new ListAttributeValueProcessor();
_incrementalAttributeMapper = new IncrementalAttributeMapper("member", _valueProcessor);
}
public void tearDown() throws Exception
{
_incrementalAttributeMapper = null;
_valueProcessor = null;
super.tearDown();
}
public void testGetAttributesArray() throws Exception
{
String[] attributes = _incrementalAttributeMapper.getAttributesArray();
assertEquals(1, attributes.length);
assertEquals("member", attributes[0]);
_incrementalAttributeMapper = new IncrementalAttributeMapper("member", _valueProcessor, 10);
attributes = _incrementalAttributeMapper.getAttributesArray();
assertEquals(1, attributes.length);
assertEquals("member;Range=0-10", attributes[0]);
}
public void testLoopEmpty() throws Exception
{
assertTrue(_incrementalAttributeMapper.hasMore());
Attributes attributes = new BasicAttributes();
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(_incrementalAttributeMapper.hasMore());
assertEquals(0, _valueProcessor.getValues().size());
}
public void testLoop() throws Exception
{
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertTrue(_incrementalAttributeMapper.hasMore());
assertEquals(11, _valueProcessor.getValues().size());
attributes = createAttributes(new RangeOption(11), 5, false);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(_incrementalAttributeMapper.hasMore());
assertEquals(16, _valueProcessor.getValues().size());
}
public void test1LoopWithPageSizeExact() throws Exception
{
_incrementalAttributeMapper = new IncrementalAttributeMapper("member", _valueProcessor, 10);
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(_incrementalAttributeMapper.hasMore());
assertEquals(11, _valueProcessor.getValues().size());
}
public void test2LoopsWithPageSizeExact() throws Exception
{
_incrementalAttributeMapper = new IncrementalAttributeMapper("member", _valueProcessor, 20);
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertTrue(_incrementalAttributeMapper.hasMore());
assertEquals(11, _valueProcessor.getValues().size());
attributes = createAttributes(new RangeOption(11, 30), false);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(_incrementalAttributeMapper.hasMore());
assertEquals(31, _valueProcessor.getValues().size());
}
public void test2LoopsWithPageSize() throws Exception
{
_incrementalAttributeMapper = new IncrementalAttributeMapper("member", _valueProcessor, 20);
Attributes attributes = createAttributes(new RangeOption(0, 10), true);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertTrue(_incrementalAttributeMapper.hasMore());
assertEquals(11, _valueProcessor.getValues().size());
attributes = createAttributes(new RangeOption(11), 5, false);
_incrementalAttributeMapper.mapFromAttributes(attributes);
assertFalse(_incrementalAttributeMapper.hasMore());
assertEquals(16, _valueProcessor.getValues().size());
}
private Attributes createAttributes(RangeOption range, boolean emptyPlain)
{
return createAttributes(range, range.getTerminal() - range.getInitial() + 1, emptyPlain);
}
private Attributes createAttributes(RangeOption range, int valueCnt, boolean emptyPlain)
{
Attributes attributes = new BasicAttributes();
if (emptyPlain)
attributes.put(new BasicAttribute("member"));
Attribute attribute = new BasicAttribute("member;" + range.toString());
for (int i = 0; i < valueCnt; i++)
attribute.add("value" + (range.getInitial() + i - 1));
attributes.put(attribute);
return attributes;
}
public static Test suite()
{
return new TestSuite(IncrementalAttributeMapperTest.class);
}
}