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 
+         *   | 
+         *   +--&gt; 0x0A 0x0(1-4) [1|2|4|8] (changeType) 
+         *  [+--&gt; 0x04 L2 previousDN] 
+         *  [+--&gt; 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;
+        }
+    }