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 2018/01/16 14:34:38 UTC
svn commit: r1821250 [1/3] - in /directory/site/trunk/content/api/dev-guide:
13-controls.mdtext 4-asn1.mdtext 4.1-asn1-tlv.mdtext
images/controls.graphml images/controls.png
Author: elecharny
Date: Tue Jan 16 14:34:38 2018
New Revision: 1821250
URL: http://svn.apache.org/viewvc?rev=1821250&view=rev
Log:
Added a page about controls, and a few fixes for ASN/1 pages
Added:
directory/site/trunk/content/api/dev-guide/13-controls.mdtext
directory/site/trunk/content/api/dev-guide/images/controls.graphml
directory/site/trunk/content/api/dev-guide/images/controls.png (with props)
Modified:
directory/site/trunk/content/api/dev-guide/4-asn1.mdtext
directory/site/trunk/content/api/dev-guide/4.1-asn1-tlv.mdtext
Added: directory/site/trunk/content/api/dev-guide/13-controls.mdtext
URL: http://svn.apache.org/viewvc/directory/site/trunk/content/api/dev-guide/13-controls.mdtext?rev=1821250&view=auto
==============================================================================
--- directory/site/trunk/content/api/dev-guide/13-controls.mdtext (added)
+++ directory/site/trunk/content/api/dev-guide/13-controls.mdtext Tue Jan 16 14:34:38 2018
@@ -0,0 +1,179 @@
+Title: 13 - Controls
+NavPrev: 12-cursor.html
+NavPrevText: 12 - Cursor
+NavUp: ../dev-guide.html
+NavUpText: Developer Guide
+NavNext: 14-extended-operations.html
+NavNextText: 14 - Extended Operations
+Notice: 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.
+
+# 13 - Controls
+
+
+Controls are extension to the protocol. They are added in messages, and can contain extra information. A **Control** contains :
+
+* an **OID**, unique to this **Control**, as an identifier
+* a **Criticality** flag, which tells if the control can be ignored or not
+* a value, which might be **BER** encoded
+
+We have 21 **Control**s declared in the **LDAP API**, and we can add more.
+
+## Implementation
+
+Here is teh **Control** classes and interfaces hierarchy :
+
+![Control Hierarchy](images/controls.png)
+
+As we can see, each _Impl_ class is coupled with a _Decorator_ class, used to process teh encoding and decoding of a **Control**
+
+Keep in mind that **Control**s have to be sent within a message, thus be encoded or decoded when the response come back.
+
+## Creating a new Control
+
+The **Control** creation follows a few rules :
+
+* It has to have a unique **OID** (this is generally the case, for **Control**s defined in RFCs)
+* It has an _Interface_, a _Decorator_ and an implementation
+* It must be declared
+
+Let's see how it all works, using an example. We will add the **Transaction Specification Control**, defined in [RFC 5805(https://tools.ietf.org/html/rfc5805)], paragraphe 2.2 :
+
+ :::Text
+ 2.2. Transaction Specification Control
+
+ A Transaction Specification Control is an LDAPControl where the
+ controlType is 1.3.6.1.1.21.2, the criticality is TRUE, and the
+ controlValue is a transaction identifier. The control is appropriate
+ for update requests including Add, Delete, Modify, and ModifyDN
+ (Rename) requests [RFC4511], as well as the Password Modify requests
+ [RFC3062].
+
+ As discussed in Section 4, the Transaction Specification control can
+ be used in conjunction with request controls appropriate for the
+ update request.
+
+The _Interface_ will just expose the _Transaction Identifier_, and store the **Control** **OID** :
+
+ :::Java
+ /**
+ * The Transaction Specification control. It's defined in RFC 5805.
+ * This control is sent with every update once a transaction is started.
+ * It contains the Transaction ID.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+ public interface TransactionSpecification
+ {
+ /** The Transaction Specification control OID */
+ String OID = "1.3.6.1.1.21.2";
+
+ /**
+ * @return The transaction identifier
+ */
+ byte[] getIdentifier();
+
+
+ /**
+ * Set the transaction ID
+ * @param The transaction identifier, an opaque byte array
+ */
+ void setIdentifier( byte[] identifier );
+ }
+
+We now need an implementation for this **Control**. It really just a matter of having an instanciable object. Note that this class exteds the _AbstractControl_ class.
+
+Here is it :
+
+ :::Java
+ /**
+ * The Transaction Specification control. It's defined in RFC 5805.
+ * This control is sent with every update once a transaction is started.
+ * It contains the Transaction ID.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+ public class TransactionSpecificationImpl extends AbstractControl implements TransactionSpecification
+ {
+ /** The Transaction Specification identifier */
+ private byte[] identifier;
+
+
+ /**
+ * Default constructor
+ */
+ public TransactionSpecificationImpl()
+ {
+ super( OID );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public byte[] getIdentifier()
+ {
+ return identifier;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setIdentifier( byte[] identifier )
+ {
+ // Copy the byte[]
+ if ( identifier != null )
+ {
+ this.identifier = new byte[identifier.length];
+ System.arraycopy( identifier, 0, this.identifier, 0, identifier.length );
+ }
+ }
+
+
+ /**
+ * @see Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ if ( identifier != null )
+ {
+ return "Transaction specification ID=null";
+ }
+ else
+ {
+ return "Transaction specification ID=" + Strings.dumpBytes( identifier );
+ }
+ }
+ }
+
+Nothing much to say, except that we have a default constructor that use the **Control**'s **OID** and a _toString()_ method, for convenience. The _Identifier_ is printed in hex format.
+
+
+
+### Encoding
+
+### Decoding
+
+## Adding a Control to the API
+
+
+
+When
\ No newline at end of file
Modified: directory/site/trunk/content/api/dev-guide/4-asn1.mdtext
URL: http://svn.apache.org/viewvc/directory/site/trunk/content/api/dev-guide/4-asn1.mdtext?rev=1821250&r1=1821249&r2=1821250&view=diff
==============================================================================
--- directory/site/trunk/content/api/dev-guide/4-asn1.mdtext (original)
+++ directory/site/trunk/content/api/dev-guide/4-asn1.mdtext Tue Jan 16 14:34:38 2018
@@ -109,4 +109,4 @@ So we decode a message using a state mac
![State Machine transition](images/sm-transition.png)
-Now, let's see a real example =
+Now, let's see a real example.
Modified: directory/site/trunk/content/api/dev-guide/4.1-asn1-tlv.mdtext
URL: http://svn.apache.org/viewvc/directory/site/trunk/content/api/dev-guide/4.1-asn1-tlv.mdtext?rev=1821250&r1=1821249&r2=1821250&view=diff
==============================================================================
--- directory/site/trunk/content/api/dev-guide/4.1-asn1-tlv.mdtext (original)
+++ directory/site/trunk/content/api/dev-guide/4.1-asn1-tlv.mdtext Tue Jan 16 14:34:38 2018
@@ -374,4 +374,246 @@ The implementation is not really complex
This is pretty much trivial.
+We now need a _Decorator to manipulate this instance. Here is the code :
+ :::Java
+ public class EntryChangeDecorator extends ControlDecorator<EntryChange> implements EntryChange
+ {
+ /** Default value when no change number is provided */
+ public static final int UNDEFINED_CHANGE_NUMBER = -1;
+
+ /** A temporary storage for the previous Dn */
+ private byte[] previousDnBytes = null;
+
+ /** The entry change global length */
+ private int eccSeqLength;
+
+ /** An instance of this decoder */
+ private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+ /**
+ * Creates a new instance of EntryChangeDecoder wrapping a newly created
+ * EntryChange Control object.
+ *
+ * @param codec The LDAP service instance
+ */
+ public EntryChangeDecorator( LdapApiService codec )
+ {
+ super( codec, new EntryChangeImpl() );
+ }
+
+
+ /**
+ * Creates a new instance of EntryChangeDecorator wrapping the supplied
+ * EntryChange Control.
+ *
+ * @param codec The LDAP service instance
+ * @param control The EntryChange Control to be decorated.
+ */
+ public EntryChangeDecorator( LdapApiService codec, EntryChange control )
+ {
+ super( codec, control );
+ }
+
+
+ /**
+ * Internally used to not have to cast the decorated Control.
+ *
+ * @return the decorated Control.
+ */
+ private EntryChange getEntryChange()
+ {
+ return getDecorated();
+ }
+
+
+ /**
+ * Compute the EntryChangeControl length
+ *
+ * <pre>
+ * 0x30 L1
+ * |
+ * +--> 0x0A 0x0(1-4) [1|2|4|8] (changeType)
+ * [+--> 0x04 L2 previousDN]
+ * [+--> 0x02 0x0(1-4) [0..2^63-1] (changeNumber)]
+ * </pre>
+ *
+ * @return the control length.
+ */
+ @Override
+ public int computeLength()
+ {
+ int changeTypesLength = 1 + 1 + 1;
+
+ int previousDnLength = 0;
+ int changeNumberLength = 0;
+
+ if ( getPreviousDn() != null )
+ {
+ previousDnBytes = Strings.getBytesUtf8( getPreviousDn().getName() );
+ previousDnLength = 1 + TLV.getNbBytes( previousDnBytes.length ) + previousDnBytes.length;
+ }
+
+ if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
+ {
+ changeNumberLength = 1 + 1 + BerValue.getNbBytes( getChangeNumber() );
+ }
+
+ eccSeqLength = changeTypesLength + previousDnLength + changeNumberLength;
+ valueLength = 1 + TLV.getNbBytes( eccSeqLength ) + eccSeqLength;
+
+ return valueLength;
+ }
+
+
+ /**
+ * Encodes the entry change control.
+ *
+ * @param buffer The encoded sink
+ * @return A ByteBuffer that contains the encoded PDU
+ * @throws EncoderException If anything goes wrong.
+ */
+ @Override
+ public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+ {
+ if ( buffer == null )
+ {
+ throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+ }
+
+ buffer.put( UniversalTag.SEQUENCE.getValue() );
+ buffer.put( TLV.getBytes( eccSeqLength ) );
+
+ buffer.put( UniversalTag.ENUMERATED.getValue() );
+ buffer.put( ( byte ) 1 );
+ buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
+
+ if ( getPreviousDn() != null )
+ {
+ BerValue.encode( buffer, previousDnBytes );
+ }
+
+ if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
+ {
+ BerValue.encode( buffer, getChangeNumber() );
+ }
+
+ return buffer;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public byte[] getValue()
+ {
+ if ( value == null )
+ {
+ try
+ {
+ computeLength();
+ ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+ buffer.put( UniversalTag.SEQUENCE.getValue() );
+ buffer.put( TLV.getBytes( eccSeqLength ) );
+
+ buffer.put( UniversalTag.ENUMERATED.getValue() );
+ buffer.put( ( byte ) 1 );
+ buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
+
+ if ( getPreviousDn() != null )
+ {
+ BerValue.encode( buffer, previousDnBytes );
+ }
+
+ if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
+ {
+ BerValue.encode( buffer, getChangeNumber() );
+ }
+
+ value = buffer.array();
+ }
+ catch ( Exception e )
+ {
+ return null;
+ }
+ }
+
+ return value;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ChangeType getChangeType()
+ {
+ return getEntryChange().getChangeType();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setChangeType( ChangeType changeType )
+ {
+ getEntryChange().setChangeType( changeType );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Dn getPreviousDn()
+ {
+ return getEntryChange().getPreviousDn();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPreviousDn( Dn previousDn )
+ {
+ getEntryChange().setPreviousDn( previousDn );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getChangeNumber()
+ {
+ return getEntryChange().getChangeNumber();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setChangeNumber( long changeNumber )
+ {
+ getEntryChange().setChangeNumber( changeNumber );
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+ {
+ ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+ EntryChangeContainer container = new EntryChangeContainer( getCodecService(), this );
+ DECODER.decode( bb, container );
+ return this;
+ }
+ }