You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2019/04/18 22:15:36 UTC
[directory-ldap-api] branch master updated: Added support for RFC
4525 (modify increment operation)
This is an automated email from the ASF dual-hosted git repository.
elecharny pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/directory-ldap-api.git
The following commit(s) were added to refs/heads/master by this push:
new a9640f8 Added support for RFC 4525 (modify increment operation)
new 721bef1 Merge branch 'master' of https://gitbox.apache.org/repos/asf/directory-ldap-api
a9640f8 is described below
commit a9640f8e36f035152f76b3a1031a9506daefeb0f
Author: emmanuel lecharny <el...@apache.org>
AuthorDate: Fri Apr 19 00:14:54 2019 +0200
Added support for RFC 4525 (modify increment operation)
---
.../api/dsmlv2/request/Dsmlv2Grammar.java | 4 +
.../api/dsmlv2/request/ModifyRequestDsml.java | 52 ++++++++
.../dsmlv2/modifyRequest/ModifyRequestTest.java | 37 ++++++
.../request_with_1_modification_increment.xml | 26 ++++
.../java/org/apache/directory/api/i18n/I18n.java | 4 +
.../apache/directory/api/i18n/errors.properties | 4 +
.../request/modify/AddModifyRequestAttribute.java | 7 ++
.../actions/request/modify/StoreOperationType.java | 4 +-
.../api/ldap/codec/api/LdapCodecConstants.java | 2 +
.../ldap/codec/factory/ModifyRequestFactory.java | 12 +-
.../api/ldap/codec/modify/ModifyRequestTest.java | 131 ++++++++++++++++++++-
.../api/ldap/model/constants/SchemaConstants.java | 3 +
.../api/ldap/model/entry/DefaultModification.java | 19 ++-
.../ldap/model/entry/ModificationOperation.java | 16 ++-
.../directory/api/ldap/model/ldif/LdifEntry.java | 3 +
.../directory/api/ldap/model/ldif/LdifReader.java | 25 ++++
.../api/ldap/model/ldif/LdifRevertor.java | 12 +-
.../api/ldap/model/message/ModifyRequest.java | 57 ++++++++-
.../api/ldap/model/message/ModifyRequestImpl.java | 54 ++++++++-
.../api/ldap/model/schema/SchemaUtils.java | 56 +++++++++
.../api/ldap/model/ldif/LdifEntryTest.java | 70 +++++++++++
.../ldap/model/message/ModifyRequestImplTest.java | 24 ++++
22 files changed, 608 insertions(+), 14 deletions(-)
diff --git a/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java b/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java
index c1b714a..1e03788 100644
--- a/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java
+++ b/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java
@@ -956,6 +956,10 @@ public final class Dsmlv2Grammar extends AbstractGrammar implements Grammar
{
modifyRequest.setCurrentOperation( LdapCodecConstants.OPERATION_REPLACE );
}
+ else if ( "increment".equals( attributeValue ) )
+ {
+ modifyRequest.setCurrentOperation( LdapCodecConstants.OPERATION_INCREMENT );
+ }
else
{
throw new XmlPullParserException( I18n.err( I18n.ERR_03040_UNKNOWN_OPERATION ), xpp, null );
diff --git a/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java b/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java
index 47e0c10..52a1d56 100644
--- a/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java
+++ b/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java
@@ -205,6 +205,10 @@ public class ModifyRequestDsml
{
modElement.addAttribute( "operation", "delete" );
}
+ else if ( operation == ModificationOperation.INCREMENT_ATTRIBUTE )
+ {
+ modElement.addAttribute( "operation", "increment" );
+ }
}
return element;
@@ -426,6 +430,54 @@ public class ModifyRequestDsml
* {@inheritDoc}
*/
@Override
+ public ModifyRequest increment( Attribute attributeName )
+ {
+ getDecorated().increment( attributeName );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( Attribute attributeName, int increment )
+ {
+ getDecorated().increment( attributeName, increment );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( String attr )
+ {
+ getDecorated().increment( attr );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( String attr, int increment )
+ {
+ getDecorated().increment( attr, increment );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public ModifyRequest setMessageId( int messageId )
{
super.setMessageId( messageId );
diff --git a/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java b/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java
index b2accf5..d940415 100644
--- a/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java
+++ b/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java
@@ -317,6 +317,43 @@ public class ModifyRequestTest extends AbstractTest
/**
+ * Test parsing of a request with a Modification element and Increment operation
+ * @throws NamingException
+ */
+ @Test
+ public void testRequestWith1ModificationIncrement() throws LdapException
+ {
+ Dsmlv2Parser parser = null;
+ try
+ {
+ parser = newParser();
+
+ parser.setInput( ModifyRequestTest.class.getResource( "request_with_1_modification_increment.xml" ).openStream(),
+ "UTF-8" );
+
+ parser.parse();
+ }
+ catch ( Exception e )
+ {
+ fail( e.getMessage() );
+ }
+
+ ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+ Collection<Modification> modifications = modifyRequest.getModifications();
+ assertEquals( 1, modifications.size() );
+
+ Modification modification = modifications.iterator().next();
+
+ assertEquals( ModificationOperation.INCREMENT_ATTRIBUTE, modification.getOperation() );
+
+ Attribute attribute = modification.getAttribute();
+
+ assertEquals( "uidnumber", attribute.getId() );
+ assertEquals( "CN=John Smith, DC=microsoft, DC=com", attribute.get().getString() );
+ }
+
+
+ /**
* Test parsing of a request with a Modification element with Base64 Value
* @throws NamingException
*/
diff --git a/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification_increment.xml b/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification_increment.xml
new file mode 100644
index 0000000..c1a214e
--- /dev/null
+++ b/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification_increment.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+ <modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+ <modification name="uidNumber" operation="increment">
+ <value>CN=John Smith, DC=microsoft, DC=com</value>
+ </modification>
+ </modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java b/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
index a8c51c3..05d5bc5 100644
--- a/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
+++ b/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
@@ -854,6 +854,10 @@ public enum I18n
ERR_13863_MR_DOES_NOT_HAVE_A_COMP( "ERR_13863_MR_DOES_NOT_HAVE_A_COMP" ),
ERR_13864_AT_DOES_NOT_HAVE_A_SUPERIOR_NOR_SYNTAX( "ERR_13864_AT_DOES_NOT_HAVE_A_SUPERIOR_NOR_SYNTAX" ),
ERR_13865_ERROR_PARSING_AT( "ERR_13865_ERROR_PARSING_AT" ),
+ ERR_13866_MOD_INCREMENT_INVALID_VALUE( "ERR_13866_MOD_INCREMENT_INVALID_VALUE" ),
+ ERR_13867_MOD_INCREMENT_NO_ATTRIBUTE( "ERR_13867_MOD_INCREMENT_NO_ATTRIBUTE" ),
+ ERR_13868_MOD_INCREMENT_NO_INT_ATTRIBUTE( "ERR_13868_MOD_INCREMENT_NO_INT_ATTRIBUTE" ),
+ ERR_13869_MOD_INCREMENT_OVERFLOW( "ERR_13869_MOD_INCREMENT_OVERFLOW" ),
// api-ldap-model subtree 13900-13999
ERR_13900_INTEGER_TOKEN_NOT_INTEGER( "ERR_13900_INTEGER_TOKEN_NOT_INTEGER" ),
diff --git a/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties b/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
index 5bfb687..8802ed1 100644
--- a/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
+++ b/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
@@ -847,6 +847,10 @@ ERR_13862_SC_PARSING_FAILURE=Parser failure on syntax checker description:\n\t{0
ERR_13863_MR_DOES_NOT_HAVE_A_COMP=The MatchingRule {0} does not have a comparator. This is invalid
ERR_13864_AT_DOES_NOT_HAVE_A_SUPERIOR_NOR_SYNTAX=The AttributeType {0} does not have a superior nor a Syntax. This is invalid
ERR_13865_ERROR_PARSING_AT=Error parsing attribute type {0}: {1}
+ERR_13866_MOD_INCREMENT_INVALID_VALUE=Increment operation on {0} with invalid increment {1}
+ERR_13867_MOD_INCREMENT_NO_ATTRIBUTE=Increment operation on a non existing attribute {0}
+ERR_13868_MOD_INCREMENT_NO_INT_ATTRIBUTE=Increment operation on a non integer attribute {0}
+ERR_13869_MOD_INCREMENT_OVERFLOW=Increment operation overflow for attribute {0}, value is {1}
# api-ldap-model subtree 13900-13999
ERR_13900_INTEGER_TOKEN_NOT_INTEGER=Value of INTEGER token {0} cannot be converted to an Integer
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/AddModifyRequestAttribute.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/AddModifyRequestAttribute.java
index f9b4f92..a5f54e8 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/AddModifyRequestAttribute.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/AddModifyRequestAttribute.java
@@ -28,6 +28,7 @@ import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.message.ModifyRequest;
import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
@@ -95,6 +96,12 @@ public class AddModifyRequestAttribute extends GrammarAction<LdapMessageContaine
container.getCurrentModification().setAttribute( currentAttribute );
}
+ // We can have an END transition if the operation was INCREMENT
+ if ( container.getCurrentModification().getOperation() == ModificationOperation.INCREMENT_ATTRIBUTE )
+ {
+ container.setGrammarEndAllowed( true );
+ }
+
if ( LOG.isDebugEnabled() )
{
LOG.debug( I18n.msg( I18n.MSG_05128_MODIFYING_TYPE, type ) );
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/StoreOperationType.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/StoreOperationType.java
index 23bb812..d6fe9bf 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/StoreOperationType.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/request/modify/StoreOperationType.java
@@ -30,6 +30,7 @@ import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
import org.apache.directory.api.ldap.model.entry.DefaultModification;
import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.message.ModifyRequest;
import org.apache.directory.api.util.Strings;
import org.slf4j.Logger;
@@ -76,7 +77,8 @@ public class StoreOperationType extends GrammarAction<LdapMessageContainer<Modif
try
{
// Store the current operation.
- operation = IntegerDecoder.parse( tlv.getValue(), 0, 2 );
+ operation = IntegerDecoder.parse( tlv.getValue(), ModificationOperation.ADD_ATTRIBUTE.getValue(),
+ ModificationOperation.INCREMENT_ATTRIBUTE.getValue() );
Modification modification = new DefaultModification();
modification.setOperation( operation );
modifyRequest.addModification( modification );
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java
index fd53907..9af0f39 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java
@@ -50,6 +50,8 @@ public final class LdapCodecConstants
public static final int OPERATION_REPLACE = 2;
+ public static final int OPERATION_INCREMENT = 3;
+
/** The filters */
public static final int EQUALITY_MATCH_FILTER = 0;
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/factory/ModifyRequestFactory.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/factory/ModifyRequestFactory.java
index d2f197f..7d044d7 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/factory/ModifyRequestFactory.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/factory/ModifyRequestFactory.java
@@ -28,6 +28,7 @@ import org.apache.directory.api.ldap.codec.api.LdapApiService;
import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.message.Message;
import org.apache.directory.api.ldap.model.message.ModifyRequest;
@@ -114,10 +115,15 @@ public final class ModifyRequestFactory implements Messagefactory
if ( modification.getAttribute().size() != 0 )
{
encodeValues( buffer, modification.getAttribute().iterator() );
- }
- // the value set
- BerValue.encodeSet( buffer, start );
+ // the value set
+ BerValue.encodeSet( buffer, start );
+ }
+ else if ( modification.getOperation() != ModificationOperation.INCREMENT_ATTRIBUTE )
+ {
+ // the value set, if not a INCREMENT operation
+ BerValue.encodeSet( buffer, start );
+ }
// The attribute type
BerValue.encodeOctetString( buffer, attribute.getUpId() );
diff --git a/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java b/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java
index 6c4e8e3..e422da2 100644
--- a/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java
+++ b/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java
@@ -39,6 +39,7 @@ import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.message.Control;
import org.apache.directory.api.ldap.model.message.Message;
@@ -837,7 +838,7 @@ public class ModifyRequestTest extends AbstractCodecServiceTest
0x30, 0x33, // LdapMessage
0x02, 0x01, 0x31, // messageID MessageID
0x66, 0x2E, // ModifyRequest
- 0x04, 0x20, // entry LDAPDN,
+ 0x04, 0x20, // entry LDAPDN,
'c', 'n', '=', 't', 'e', 's', 't', 'M', 'o', 'd', 'i', 'f', 'y',
',', 'o', 'u', '=', 'u', 's', 'e', 'r', 's', ',',
'o', 'u', '=', 's', 'y', 's', 't', 'e', 'm',
@@ -1061,4 +1062,132 @@ public class ModifyRequestTest extends AbstractCodecServiceTest
assertArrayEquals( stream.array(), buffer.getBytes().array() );
}
+
+
+ /**
+ * Test the decoding of a ModifyRequest with an add operation, and a
+ * modification with a type and an empty vals
+ */
+ @Test
+ public void testDecodeModifyRequestAddOperationModificationIncrement()
+ throws DecoderException, EncoderException
+ {
+ ByteBuffer stream = ByteBuffer.allocate( 0x3D );
+
+ stream.put( new byte[]
+ {
+ 0x30, 0x3B, // LdapMessage
+ 0x02, 0x01, 0x31, // messageID MessageID
+ 0x66, 0x36, // ModifyRequest
+ 0x04, 0x20, // entry LDAPDN,
+ 'c', 'n', '=', 't', 'e', 's', 't', 'M', 'o', 'd', 'i', 'f', 'y',
+ ',', 'o', 'u', '=', 'u', 's', 'e', 'r', 's', ',',
+ 'o', 'u', '=', 's', 'y', 's', 't', 'e', 'm',
+ 0x30, 0x012,
+ 0x30, 0x10,
+ 0x0A, 0x01, 0x03,
+ 0x30, 0x0B,
+ 0x04, 0x09,
+ 'u', 'i', 'd', 'n', 'u', 'm', 'b', 'e', 'r',
+ } );
+
+ stream.flip();
+
+ // Allocate a LdapMessage Container
+ LdapMessageContainer<ModifyRequest> ldapMessageContainer = new LdapMessageContainer<>( codec );
+
+ // Decode a ModifyRequest PDU
+ Asn1Decoder.decode( stream, ldapMessageContainer );
+
+ // Check the decoded PDU
+ ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+ assertEquals( 49, modifyRequest.getMessageId() );
+ assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+ Object[] modifications = modifyRequest.getModifications().toArray();
+
+ assertEquals( 1, modifications.length );
+
+ Modification modification = ( Modification ) modifications[0];
+
+ assertEquals( ModificationOperation.INCREMENT_ATTRIBUTE, modification.getOperation() );
+ Attribute attributeValue = modification.getAttribute();
+
+ assertEquals( "uidnumber", Strings.toLowerCaseAscii( attributeValue.getUpId() ) );
+ assertEquals( 0, attributeValue.size() );
+
+ // Check encode reverse
+ Asn1Buffer buffer = new Asn1Buffer();
+
+ LdapEncoder.encodeMessage( buffer, codec, modifyRequest );
+
+ assertArrayEquals( stream.array(), buffer.getBytes().array() );
+ }
+
+
+ /**
+ * Test the decoding of a ModifyRequest with an add operation, and a
+ * modification with a type and an empty vals
+ */
+ @Test
+ public void testDecodeModifyRequestAddOperationModificationIncrementWithValue()
+ throws DecoderException, EncoderException
+ {
+ ByteBuffer stream = ByteBuffer.allocate( 0x42 );
+
+ stream.put( new byte[]
+ {
+ 0x30, 0x40, // LdapMessage
+ 0x02, 0x01, 0x31, // messageID MessageID
+ 0x66, 0x3B, // ModifyRequest
+ 0x04, 0x20, // entry LDAPDN,
+ 'c', 'n', '=', 't', 'e', 's', 't', 'M', 'o', 'd', 'i', 'f', 'y',
+ ',', 'o', 'u', '=', 'u', 's', 'e', 'r', 's', ',',
+ 'o', 'u', '=', 's', 'y', 's', 't', 'e', 'm',
+ 0x30, 0x017,
+ 0x30, 0x15,
+ 0x0A, 0x01, 0x03,
+ 0x30, 0x10,
+ 0x04, 0x09,
+ 'u', 'i', 'd', 'n', 'u', 'm', 'b', 'e', 'r',
+ 0x31, 0x03,
+ 0x04, 0x01,
+ '3'
+ } );
+
+ stream.flip();
+
+ // Allocate a LdapMessage Container
+ LdapMessageContainer<ModifyRequest> ldapMessageContainer = new LdapMessageContainer<>( codec );
+
+ // Decode a ModifyRequest PDU
+ Asn1Decoder.decode( stream, ldapMessageContainer );
+
+ // Check the decoded PDU
+ ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+ assertEquals( 49, modifyRequest.getMessageId() );
+ assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+ Object[] modifications = modifyRequest.getModifications().toArray();
+
+ assertEquals( 1, modifications.length );
+
+ Modification modification = ( Modification ) modifications[0];
+
+ assertEquals( ModificationOperation.INCREMENT_ATTRIBUTE, modification.getOperation() );
+ Attribute attributeValue = modification.getAttribute();
+
+ assertEquals( "uidnumber", Strings.toLowerCaseAscii( attributeValue.getUpId() ) );
+ assertEquals( 1, attributeValue.size() );
+ assertEquals( "3", attributeValue.get().getString() );
+
+ // Check encode reverse
+ Asn1Buffer buffer = new Asn1Buffer();
+
+ LdapEncoder.encodeMessage( buffer, codec, modifyRequest );
+
+ assertArrayEquals( stream.array(), buffer.getBytes().array() );
+ }
}
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java
index dc2b81e..2133dee 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java
@@ -2188,6 +2188,9 @@ public final class SchemaConstants
// ---- Features ----------------------------------------------------------
public static final String FEATURE_ALL_OPERATIONAL_ATTRIBUTES = "1.3.6.1.4.1.4203.1.5.1";
+
+ // RFC 4525
+ public static final String FEATURE_MODIFY_INCREMENT = "1.3.6.1.1.14";
// ----Administrative roles -----------------------------------------------
// AutonomousArea
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java
index 4ccca0e..96f0fe2 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java
@@ -425,9 +425,22 @@ public class DefaultModification implements Modification
sb.append( "Modification: " ).
append( operation ).
- append( "\n" ).
- append( ", attribute : " ).
- append( attribute );
+ append( ", [" ).
+ append( attribute.getId() );
+
+ if ( attribute.size() == 0 )
+ {
+ if ( operation == ModificationOperation.INCREMENT_ATTRIBUTE )
+ {
+ sb.append( " : 1" );
+ }
+ }
+ else
+ {
+ sb.append( " : " ).append( attribute );
+ }
+
+ sb.append( "]" );
return sb.toString();
}
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java
index bbb1af7..b51f424 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java
@@ -23,7 +23,9 @@ package org.apache.directory.api.ldap.model.entry;
/**
* An enum storing the different modification operation which can be used
* in a Modification. There is a one to one mapping with the DirContext.ADD_ATTRIBUTE,
- * DirContext.REMOVE_ATTRIBUTE, DirContext.REPLACE_ATTRIBUTE
+ * DirContext.REMOVE_ATTRIBUTE, DirContext.REPLACE_ATTRIBUTE.
+ *
+ * We have added the INCREMENT operation (RFC 4525)
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@@ -36,7 +38,10 @@ public enum ModificationOperation
REMOVE_ATTRIBUTE(1),
/** Replaced attribute value */
- REPLACE_ATTRIBUTE(2);
+ REPLACE_ATTRIBUTE(2),
+
+ /** Increment operation, RFC 4525 */
+ INCREMENT_ATTRIBUTE(3);
/** Internal value */
private int value;
@@ -83,6 +88,10 @@ public enum ModificationOperation
{
return REPLACE_ATTRIBUTE;
}
+ else if ( value == INCREMENT_ATTRIBUTE.value )
+ {
+ return INCREMENT_ATTRIBUTE;
+ }
else
{
return null;
@@ -107,6 +116,9 @@ public enum ModificationOperation
case REMOVE_ATTRIBUTE:
return "remove";
+ case INCREMENT_ATTRIBUTE:
+ return "increment";
+
default:
return "";
}
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java
index 2c3d174..e80f569 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java
@@ -406,6 +406,7 @@ public class LdifEntry implements Cloneable, Externalizable, Iterable<Attribute>
* <li>ModificationOperation.ADD_ATTRIBUTE</li>
* <li>ModificationOperation.REMOVE_ATTRIBUTE</li>
* <li>ModificationOperation.REPLACE_ATTRIBUTE</li>
+ * <li>ModificationOperation.INCREMENT_ATTRIBUTE</li>
* </ul>
*
* @param attr The attribute to be added
@@ -429,6 +430,7 @@ public class LdifEntry implements Cloneable, Externalizable, Iterable<Attribute>
* <li>ModificationOperation.ADD_ATTRIBUTE</li>
* <li>ModificationOperation.REMOVE_ATTRIBUTE</li>
* <li>ModificationOperation.REPLACE_ATTRIBUTE</li>
+ * <li>ModificationOperation.INCREMENT_ATTRIBUTE</li>
* </ul>
*
* @param id The attribute's ID
@@ -454,6 +456,7 @@ public class LdifEntry implements Cloneable, Externalizable, Iterable<Attribute>
* <li>ModificationOperation.ADD_ATTRIBUTE</li>
* <li>ModificationOperation.REMOVE_ATTRIBUTE</li>
* <li>ModificationOperation.REPLACE_ATTRIBUTE</li>
+ * <li>ModificationOperation.INCREMENT_ATTRIBUTE</li>
* </ul>
*
* @param id The attribute's ID
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java
index 697cc7c..a18e203 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java
@@ -1114,6 +1114,7 @@ public class LdifReader implements Iterable<LdifEntry>, Closeable
* <pre>
* <changerecord> ::= "changetype:" FILL "modify" SEP <mod-spec> <mod-specs-e>
* <mod-spec> ::= "add:" <mod-val> | "delete:" <mod-val-del> | "replace:" <mod-val>
+ * | "increment:" <mod-val>
* <mod-specs-e> ::= <mod-spec>
* <mod-specs-e> | e
* <mod-val> ::= FILL ATTRIBUTE-DESCRIPTION SEP ATTRVAL-SPEC <attrval-specs-e> "-" SEP
@@ -1227,6 +1228,30 @@ public class LdifReader implements Iterable<LdifEntry>, Closeable
state = ATTRVAL_SPEC_OR_SEP;
}
+ else if ( lowerLine.startsWith( "increment:" ) )
+ {
+ if ( ( state != MOD_SPEC ) && ( state != ATTRVAL_SPEC ) )
+ {
+ String msg = I18n.err( I18n.ERR_13414_BAD_MODIFY_SEPARATOR_2, lineNumber );
+ LOG.error( msg );
+ throw new LdapLdifException( msg );
+ }
+
+ modified = Strings.trim( line.substring( "increment:".length() ) );
+ modificationType = ModificationOperation.INCREMENT_ATTRIBUTE;
+
+ if ( schemaManager != null )
+ {
+ AttributeType attributeType = schemaManager.getAttributeType( modified );
+ attribute = new DefaultAttribute( modified, attributeType );
+ }
+ else
+ {
+ attribute = new DefaultAttribute( modified );
+ }
+
+ state = ATTRVAL_SPEC_OR_SEP;
+ }
else
{
if ( ( state != ATTRVAL_SPEC ) && ( state != ATTRVAL_SPEC_OR_SEP ) )
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java
index 9c3b18f..22b03d8 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java
@@ -221,7 +221,17 @@ public final class LdifRevertor
continue;
}
- reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, previous );
+ reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
+ previous );
+ reverseModifications.add( 0, reverseModification );
+ break;
+
+ case INCREMENT_ATTRIBUTE:
+ mod = modification.getAttribute();
+ previous = clonedEntry.get( mod.getId() );
+
+ reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
+ previous );
reverseModifications.add( 0, reverseModification );
break;
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java
index ccbdf38..3209d13 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java
@@ -46,7 +46,8 @@ import org.apache.directory.api.ldap.model.name.Dn;
* operation ENUMERATED {
* add (0),
* delete (1),
- * replace (2) },
+ * replace (2),
+ * ... },
* modification AttributeTypeAndValues } }
*
* AttributeTypeAndValues ::= SEQUENCE {
@@ -93,6 +94,22 @@ import org.apache.directory.api.ldap.model.name.Dn;
* borrow good ideas and familiar signatures, interfaces and classes where we
* can.
*
+ * RFC 4525 suggest to add an operation in the enumeration:
+ *
+ * <pre>
+ * ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+ * object LDAPDN,
+ * modification SEQUENCE OF SEQUENCE {
+ *
+ * operation ENUMERATED {
+ * add (0),
+ * delete (1),
+ * replace (2),
+ * increment (3),
+ * ... },
+ * </pre>
+ *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*
*/
@@ -267,6 +284,44 @@ public interface ModifyRequest extends SingleReplyRequest, AbandonableRequest
/**
+ * marks a given attribute for increment by 1 in the target entry.
+ *
+ * @param attributeName the attribute to be incremented
+ * @return The ModifyRequest instance
+ */
+ ModifyRequest increment( String attributeName );
+
+
+ /**
+ * marks a given attribute for increment in the target entry.
+ *
+ * @param attributeName the attribute to be incremented
+ * @param increment The increment value (>=1)
+ * @return The ModifyRequest instance
+ */
+ ModifyRequest increment( String attributeName, int increment );
+
+
+ /**
+ * marks a given attribute for increment by 1 in the target entry.
+ *
+ * @param attr the attribute to be incremented
+ * @return The ModifyRequest instance
+ */
+ ModifyRequest increment( Attribute attr );
+
+
+ /**
+ * marks a given attribute for increment in the target entry.
+ *
+ * @param attr the attribute to be incremented
+ * @param increment The increment value (>=1)
+ * @return The ModifyRequest instance
+ */
+ ModifyRequest increment( Attribute attr, int increment );
+
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java
index a9cd293..c961fda 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java
@@ -274,9 +274,59 @@ public class ModifyRequestImpl extends AbstractAbandonableRequest implements Mod
* {@inheritDoc}
*/
@Override
- public ModifyRequest remove( String attributerName )
+ public ModifyRequest remove( String attributeName )
{
- addModification( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attributerName ) );
+ addModification( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attributeName ) );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( String attributeName )
+ {
+ addModification( new DefaultModification( ModificationOperation.INCREMENT_ATTRIBUTE, attributeName ) );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( String attributeName, int increment )
+ {
+ addModification( new DefaultModification( ModificationOperation.INCREMENT_ATTRIBUTE, attributeName,
+ Integer.toString( increment ) ) );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( Attribute attr )
+ {
+ addModification( attr, ModificationOperation.INCREMENT_ATTRIBUTE );
+
+ return this;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ModifyRequest increment( Attribute attr, int increment )
+ {
+ addModification( new DefaultModification( ModificationOperation.INCREMENT_ATTRIBUTE, attr.getId(),
+ Integer.toString( increment ) ) );
return this;
}
diff --git a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java
index c668cda..721078d 100644
--- a/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java
+++ b/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java
@@ -28,6 +28,7 @@ import java.util.UUID;
import org.apache.directory.api.i18n.I18n;
import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Modification;
@@ -117,6 +118,61 @@ public final class SchemaUtils
}
break;
+
+ case INCREMENT_ATTRIBUTE:
+ // The incremented attribute might not exist
+ AttributeType attributeType = mod.getAttribute().getAttributeType();
+ String incrementStr = mod.getAttribute().getString();
+ int increment = 1;
+
+ if ( !Strings.isEmpty( incrementStr ) )
+ {
+ try
+ {
+ increment = Integer.parseInt( incrementStr );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ throw new IllegalArgumentException( I18n.err( I18n.ERR_13866_MOD_INCREMENT_INVALID_VALUE,
+ attributeType.getName(), incrementStr ) );
+ }
+ }
+ Attribute modified = targetEntry.get( attributeType );
+
+ if ( !targetEntry.containsAttribute( attributeType ) )
+ {
+ throw new IllegalArgumentException( I18n.err( I18n.ERR_13867_MOD_INCREMENT_NO_ATTRIBUTE,
+ attributeType.getName() ) );
+ }
+
+ if ( !SchemaConstants.INTEGER_SYNTAX.equals( modified.getAttributeType().getSyntax().getOid() ) )
+ {
+ throw new IllegalArgumentException( I18n.err( I18n.ERR_13868_MOD_INCREMENT_NO_INT_ATTRIBUTE,
+ attributeType.getName() ) );
+ }
+ else
+ {
+ Value[] newValues = new Value[ modified.size() ];
+ int i = 0;
+
+ for ( Value value : modified )
+ {
+ int intValue = Integer.parseInt( value.getNormalized() );
+
+ if ( intValue == Integer.MAX_VALUE )
+ {
+ throw new IllegalArgumentException( I18n.err( I18n.ERR_13869_MOD_INCREMENT_OVERFLOW,
+ attributeType.getName(), intValue ) );
+ }
+
+ newValues[i++] = new Value( Integer.toString( intValue + increment ) );
+ modified.remove( value );
+ }
+
+ modified.add( newValues );
+ }
+
+ break;
default:
throw new IllegalStateException( I18n.err( I18n.ERR_13775_UNDEFINED_MODIFICATION_TYPE, mod.getOperation() ) );
diff --git a/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java b/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java
index c00b3cf..270363c 100644
--- a/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java
+++ b/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java
@@ -564,6 +564,76 @@ public class LdifEntryTest
/**
+ * Test a Modify changeType LdifEntry with increment operation
+ */
+ @Test
+ public void testLdifEntryChangeTypeModifyIncrement() throws Exception
+ {
+ String ldif =
+ "changetype: modify\n" +
+ "increment: uidNumber\n" +
+ "-";
+
+ LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+ assertNotNull( ldifEntry );
+ assertEquals( ChangeType.Modify, ldifEntry.getChangeType() );
+ assertNull( ldifEntry.getEntry() );
+ assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+ assertFalse( ldifEntry.hasControls() );
+ assertTrue( ldifEntry.isLdifChange() );
+
+ // Check the modification
+ assertNotNull( ldifEntry.getModifications() );
+
+ for ( Modification modification : ldifEntry.getModifications() )
+ {
+ assertEquals( ModificationOperation.INCREMENT_ATTRIBUTE, modification.getOperation() );
+ Attribute attribute = modification.getAttribute();
+
+ assertNotNull( attribute );
+ assertEquals( "uidnumber", attribute.getId() );
+ }
+ }
+
+
+ /**
+ * Test a Modify changeType LdifEntry with increment operation
+ */
+ @Test
+ public void testLdifEntryChangeTypeModifyIncrementNumber() throws Exception
+ {
+ String ldif =
+ "changetype: modify\n" +
+ "increment: uidNumber\n" +
+ "uidNumber: 3\n" +
+ "-";
+
+ LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+ assertNotNull( ldifEntry );
+ assertEquals( ChangeType.Modify, ldifEntry.getChangeType() );
+ assertNull( ldifEntry.getEntry() );
+ assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+ assertFalse( ldifEntry.hasControls() );
+ assertTrue( ldifEntry.isLdifChange() );
+
+ // Check the modification
+ assertNotNull( ldifEntry.getModifications() );
+
+ for ( Modification modification : ldifEntry.getModifications() )
+ {
+ assertEquals( ModificationOperation.INCREMENT_ATTRIBUTE, modification.getOperation() );
+ Attribute attribute = modification.getAttribute();
+
+ assertNotNull( attribute );
+ assertEquals( "uidnumber", attribute.getId() );
+ assertEquals( "3", attribute.getString() );
+ }
+ }
+
+
+ /**
* Test a Modify changeType LdifEntry with no operation
*/
@Test(expected = LdapLdifException.class)
diff --git a/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java b/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java
index 3a4446f..858b832 100644
--- a/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java
+++ b/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java
@@ -527,6 +527,30 @@ public class ModifyRequestImplTest
{
return this;
}
+
+
+ public ModifyRequest increment( Attribute attr )
+ {
+ return this;
+ }
+
+
+ public ModifyRequest increment( Attribute attr, int increment )
+ {
+ return this;
+ }
+
+
+ public ModifyRequest increment( String attributerName )
+ {
+ return this;
+ }
+
+
+ public ModifyRequest increment( String attributerName, int increment )
+ {
+ return this;
+ }
};
ModifyRequestImpl req1 = getRequest();