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.