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 23:35:47 UTC

svn commit: r1821335 - /directory/site/trunk/content/api/dev-guide/13-controls.mdtext

Author: elecharny
Date: Tue Jan 16 23:35:47 2018
New Revision: 1821335

URL: http://svn.apache.org/viewvc?rev=1821335&view=rev
Log:
Completed the controls page

Modified:
    directory/site/trunk/content/api/dev-guide/13-controls.mdtext

Modified: 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=1821335&r1=1821334&r2=1821335&view=diff
==============================================================================
--- directory/site/trunk/content/api/dev-guide/13-controls.mdtext (original)
+++ directory/site/trunk/content/api/dev-guide/13-controls.mdtext Tue Jan 16 23:35:47 2018
@@ -31,11 +31,11 @@ Controls are extension to the protocol.
 * 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.
+We have 20 **Control**s declared in the **LDAP API**, and we can add more.
 
 ## Implementation
 
-Here is teh **Control** classes and interfaces hierarchy :
+Here is the **Control** classes and interfaces hierarchy :
 
 ![Control Hierarchy](images/controls.png)
 
@@ -43,6 +43,42 @@ As we can see, each _Impl_ class is coup
 
 Keep in mind that **Control**s have to be sent within a message, thus be encoded or decoded when the response come back.
 
+## Package/module
+
+We have two flavors of **Control**s, standard and 'extra'. Standard **Control**s are those supported by all he servers, extras are oly supported by a few servers. This is an arbitrary decision, we could have put all of them at teh same place.
+
+The list of standard **Control**s is :
+
+* _Cascade_
+* _EntryChange_
+* _ManageDsaIT_
+* _PagedResults_
+* _PersistentSearch_
+* _ProxiedAuthz_
+* _SortRequest_
+* _SortResponse_
+* _Subentries_
+
+The list of extra **Control**s is :
+
+* _AdDirSync_
+* _AdPolicyHints_
+* _AdShowDeleted_
+* _ChangeNotifications_
+* _PermissiveModify_
+* _PasswordPolicy_
+* _SyncDoneValue_
+* _SyncRequestValue_
+* _SyncStateValue_
+* _VirtualListViewRequest_
+* _VirtualListViewResponse_
+
+The standard **Control**s are described in the _ldap/model_ module (for the classes and interfaces) and in the _ldap/codec/core_ module (for the _Decorator_ and the decoding classes), in the _org.apache.directory.api.ldap.model.message.controls_ package.
+
+The extra **Control**s are described in the _ldap/extras/codec_ and _ldap/extras/codec-api modules (the first module contains the _classes_ and _interfaces_, the second module contains the _Decorator_s and all the decoder classes.) , in the _org.apache.directory.api.ldap.extras.controls.XXX_ packages (one sub-package per control) and in the _org.apache.directory.api.ldap.codec.controls.XXX_ package.
+
+Any new **Control** is likely to be declared as an extra **Control**.
+
 ## Creating a new Control
 
 The **Control** creation follows a few rules :
@@ -70,6 +106,10 @@ Let's see how it all works, using an exa
 The _Interface_ will just expose the _Transaction Identifier_, and store the **Control** **OID** :
 
     :::Java
+    package org.apache.directory.api.ldap.extras.controls.transaction;
+
+    import org.apache.directory.api.ldap.model.message.Control;
+
     /**
      * The Transaction Specification control. It's defined in RFC 5805.
      * This control is sent with every update once a transaction is started.
@@ -97,9 +137,14 @@ The _Interface_ will just expose the _Tr
 
 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 :
+Here it is :
 
     :::Java
+    package org.apache.directory.api.ldap.extras.controls.transaction;
+
+    import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+    import org.apache.directory.api.util.Strings;
+
     /**
      * The Transaction Specification control. It's defined in RFC 5805.
      * This control is sent with every update once a transaction is started.
@@ -166,14 +211,290 @@ Here is it :
 
 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.
 
+That's it for the two base _class_ and _interface_, we now have to deal with encoding and decoding.
+
+
+### Encoding & Decoding
+
+Encoding the **Control** is done by the **Decorator**. This class implements the _Asn1Object_ which defines the method _encode()_. Let's see how it works...
+
+In order to encode the value we need to know its length, this is why we also have to implement the _computeLegth()_ method. In our case, it's superflouous, as the length is known : it's the _identifier_'s length.
+Decoidng is quitre trivial : as we only need to decode the **Control** value, and as it's an opaque _byte[]_, we just need to copy this value in the instance.
+
+In any case, we don't encode the whole **Control**, we just encode it's value : the **Control** itself is encode by the **LdapMessage**.
+
+Here is the _Decorator_ code.
+
+    :::Java
+    package org.apache.directory.api.ldap.extras.controls.transaction;
+
+    import java.nio.ByteBuffer;
+
+    import org.apache.directory.api.asn1.Asn1Object;
+    import org.apache.directory.api.asn1.DecoderException;
+    import org.apache.directory.api.asn1.EncoderException;
+    import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+    import org.apache.directory.api.ldap.codec.api.LdapApiService;
+
+    /**
+     * TransactionSpecification decorator.
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public class TransactionSpecificationDecorator extends ControlDecorator<TransactionSpecification> implements TransactionSpecification
+    {
+        /**
+         * Create a new instance of TransactionSpecificationDecorator
+         * 
+         * @param codec  The LDAP Service to use
+         * @param decoratedControl The control to decorate
+         */
+        public TransactionSpecificationDecorator( LdapApiService codec, TransactionSpecification decoratedControl )
+        {
+            super( codec, decoratedControl );
+        }
+        
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+        {
+            // Nothing to decode, the byte array is copied as is in identifier
+            setIdentifier( controlBytes );
+            
+            return this;
+        }
+
+        
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int computeLength()
+        {
+            byte[] identifier = getDecorated().getIdentifier();
+            
+            if ( identifier != null )
+            {
+                return identifier.length;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+        {
+            byte[] identifier = getDecorated().getIdentifier();
+            
+            if ( identifier != null )
+            {
+                ByteBuffer encoded = ByteBuffer.allocate( identifier.length );
+                
+                encoded.put( identifier );
+                
+                return encoded;
+            }
+            else
+            {
+                return ByteBuffer.allocate( 0 );
+            }
+        }
+
+        
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public byte[] getIdentifier()
+        {
+            return getDecorated().getIdentifier();
+        }
+
+        
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void setIdentifier( byte[] identifier )
+        {
+            getDecorated().setIdentifier( identifier );
+        }
+    }
+
+### The Factory
+
+We also need a _Factory_ class that is used to register the **Control**. This class simply expose a constructor for the **Control**. It's code is pretty trival, there is nothing specific to the added **Control**.
+
+Side note : as this class is ony invoked at startup, we could use reflection instead of having one _Factory_ per **Control**...
+
+    :::Java
+    package org.apache.directory.api.ldap.extras.controls.transaction;
+
+
+    import org.apache.directory.api.ldap.codec.api.CodecControl;
+    import org.apache.directory.api.ldap.codec.api.ControlFactory;
+    import org.apache.directory.api.ldap.codec.api.LdapApiService;
+
+
+    /**
+     * A codec {@link ControlFactory} implementation for {@link TransactionSpecification} controls.
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public class TransactionSpecificationFactory implements ControlFactory<TransactionSpecification>
+    {
+        /** The LDAP codec responsible for encoding and decoding Cascade Controls */
+        private LdapApiService codec;
+
 
+        /**
+         * Creates a new instance of TransactionSpecificationFactory.
+         *
+         * @param codec The LDAP codec
+         */
+        public TransactionSpecificationFactory( LdapApiService codec )
+        {
+            this.codec = codec;
+        }
 
-### Encoding
 
-### Decoding
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String getOid()
+        {
+            return TransactionSpecification.OID;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public CodecControl<TransactionSpecification> newCodecControl()
+        {
+            return new TransactionSpecificationDecorator( codec, new TransactionSpecificationImpl() );
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public CodecControl<TransactionSpecification> newCodecControl( TransactionSpecification control )
+        {
+            return new TransactionSpecificationDecorator( codec, control );
+        }
+    }
+
+
+## A more complex Control
+
+We just shown a **Control** which was easy to encode or decode. Most of the time, the **Control**'s value is itself an **ASN/1** **BER** encoded value, and we need more classes to be able to process the decoding. Let use another **Control** as a sample : 
+
+
+TODO
+
 
 ## Adding a Control to the API
 
- 
+Once we have written the **Control** classes and interfaces, we need to declare it so that the **LDAP API** can use it.
+
+The thing is that the **LDAP API** is **OSGi** compliant, so we need to expose the **Control**s and we also have to activate them.
+
+The _ExtrasBundleActivator_ class (in the _ldap/extras/codec_ module) has to be modified to register and unregister the added **Control** :
+
+    :::Java
+
+    ...
+    import org.apache.directory.api.ldap.extras.controls.changeNotifications.TransactionSpecification;
+    ...
+
+    /**
+     * A BundleActivator for the ldap codec extras extension: extra ApacheDS and 
+     * Apache Directory Studio specific controls and extended operations. 
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public class ExtrasBundleActivator implements BundleActivator
+    {
+        ....
+        /**
+         * Registers all the extras controls present in this control pack.
+         *
+         * @param codec The codec service.
+         */
+        private void registerExtrasControls( LdapApiService codec )
+        {
+            ControlFactory<AdDirSync> adDirSyncFactory = new AdDirSyncFactory( codec );
+            codec.registerControl( adDirSyncFactory );
+            ...
+
+            ControlFactory<TransactionSpecification> TransactionSpecificationFactory = new TransactionSpecificationFactory( codec );
+            codec.registerControl( TransactionSpecification );
+        }
+    
+        ...
+
+        private void unregisterExtrasControls( LdapApiService codec )
+        {
+            codec.unregisterControl( AdDirSync.OID );
+            codec.unregisterControl( AdShowDeleted.OID );
+            ...
+            codec.unregisterControl( TransactionSpecification.OID );
+        }
+   
+        ....
+
+Here we added the _TransactionSpecification_ **Control** at the end of thse two methods, and added the associated _import_.
+
+Last, not least, we need to update the _loadStockControls_ method in the _CodecFactoryUtil_ class (in _ldap/codec/standalone_ module) :
+
+    :::Java
+    ...
+    import org.apache.directory.api.ldap.extras.controls.changeNotifications.TransactionSpecification;
+    ...
+
+    /**
+     * A utility class for adding Codec and extended operation factories.
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public final class CodecFactoryUtil
+    {
+        ....
+        /**
+         * Loads the Controls implement out of the box in the codec.
+         * 
+         * @param controlFactories The Control factories to use
+         * @param apiService The LDAP Service instance to use
+         */
+        public static void loadStockControls( Map<String, ControlFactory<?>> controlFactories, LdapApiService apiService )
+        {
+            // Standard controls
+            ControlFactory<Cascade> cascadeFactory = new CascadeFactory( apiService );
+            controlFactories.put( cascadeFactory.getOid(), cascadeFactory );
+            LOG.info( "Registered pre-bundled control factory: {}", cascadeFactory.getOid() );
+
+            ...
+            ControlFactory<TransactionSpecification> transactionSpecificationFactory = 
+                new TransactionSpecificationFactory( apiService );
+            controlFactories.put( transactionSpecificationFactory.getOid(), transactionSpecificationFactory );
+            LOG.info( "Registered pre-bundled control factory: {}", transactionSpecificationFactory.getOid() );
+        }
+
+        ...
+    }
+
 
-When 
\ No newline at end of file
+We are done ! Note that there is nothing to change in the _MANISFEST.MF_ file, as the packages are already exported.