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 2006/01/22 01:34:12 UTC

svn commit: r371152 - in /directory/trunks/common/ldap/src: main/java/org/apache/ldap/common/codec/extended/operations/ test/java/org/apache/ldap/common/codec/extended/operations/

Author: elecharny
Date: Sat Jan 21 16:34:03 2006
New Revision: 371152

URL: http://svn.apache.org/viewcvs?rev=371152&view=rev
Log:
Created a first version of GracefulDisconnect.
Test to be completed

Added:
    directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnect.java
    directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectConstants.java
    directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectContainer.java
    directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectDecoder.java
    directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectGrammar.java
    directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectStatesEnum.java
    directory/trunks/common/ldap/src/test/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectTest.java

Added: directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnect.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnect.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnect.java (added)
+++ directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnect.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,222 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.asn1.Asn1Object;
+import org.apache.asn1.ber.tlv.Length;
+import org.apache.asn1.ber.tlv.UniversalTag;
+import org.apache.asn1.ber.tlv.Value;
+import org.apache.asn1.codec.EncoderException;
+import org.apache.ldap.common.codec.util.LdapURL;
+
+
+/**
+ * An extended operation to proceed a graceful disconnect
+ * 
+ * <pre>
+ *  GracefulDisconnect ::= SEQUENCE 
+ *  {
+ *      timeOffline INTEGER (0..720) DEFAULT 0,
+ *      delay [0] INTEGER (0..86400) DEFAULT 0,
+ *      replicatedContexts Referral OPTIONAL
+ *  }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class GracefulDisconnect extends Asn1Object
+{
+    private int timeOffline;
+    private int delay;
+    private List replicatedContexts;
+    private transient int gracefulDisconnectSequenceLength;
+    private transient int replicatedContextsLength;
+    
+    public GracefulDisconnect( int timeOffline, int delay )
+    {
+        this.timeOffline = timeOffline;
+        this.delay = delay;
+        this.replicatedContexts = new ArrayList(2);
+    }
+
+    public GracefulDisconnect()
+    {
+        this.timeOffline = 0;
+        this.delay = 0;
+        this.replicatedContexts = new ArrayList(2);
+    }
+
+    public int getDelay() 
+    {
+        return delay;
+    }
+
+
+    public void setDelay( int delay ) 
+    {
+        this.delay = delay;
+    }
+
+
+    public int getTimeOffline() 
+    {
+        return timeOffline;
+    }
+
+
+    public void setTimeOffline( int timeOffline ) 
+    {
+        this.timeOffline = timeOffline;
+    }
+    
+    public List getReplicatedContexts() 
+    {
+        return replicatedContexts;
+    }
+
+    public void setReplicatedContexts( List replicatedContexts ) 
+    {
+        this.replicatedContexts = replicatedContexts;
+    }
+
+    public void addReplicatedContexts( LdapURL replicatedContext ) 
+    {
+        replicatedContexts.add( replicatedContext );
+    }
+
+    /**
+     * Compute the GracefulDisconnect length
+     * 0x30 L1
+     *  |
+     *  +--> [ 0x02 0x0(1-4) [0..720] ]
+     *  +--> [ 0x80 0x0(1-3) [0..86400] ]
+     *  +--> [ 0x30 L2
+     *          |
+     *          +--> (0x04 L3 value) + 
+     *  
+     */
+    public int computeLength()
+    {
+        gracefulDisconnectSequenceLength = 0;
+        
+        if ( timeOffline != 0 )
+        {
+            gracefulDisconnectSequenceLength += 1 + 1 + Length.getNbBytes( timeOffline );
+        }
+
+        if ( delay != 0 )
+        {
+            gracefulDisconnectSequenceLength += 1 + 1 + Length.getNbBytes( delay );
+        }
+
+        if ( replicatedContexts.size() > 0 )
+        {
+            replicatedContextsLength = 0;
+
+            Iterator replicatedContextIterator = replicatedContexts.iterator();
+            
+            // We may have more than one reference.
+            while (replicatedContextIterator.hasNext())
+            {
+                int ldapUrlLength = ((LdapURL)replicatedContextIterator.next()).getNbBytes();
+                replicatedContextsLength += 1 + Length.getNbBytes( ldapUrlLength ) + ldapUrlLength;
+            }
+        }
+        else
+        {
+            replicatedContextsLength = 1 + 1;
+        }
+        
+        gracefulDisconnectSequenceLength += 1 + Length.getNbBytes( replicatedContextsLength ) + replicatedContextsLength; 
+
+        return 1 + Length.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength;
+    }
+    
+    /**
+     * Encodes the gracefulDisconnect extended request.
+     * 
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLength() );
+        
+        bb.put( UniversalTag.SEQUENCE_TAG );
+        bb.put( Length.getBytes( gracefulDisconnectSequenceLength ) );
+
+        if ( timeOffline != 0 )
+        {
+            Value.encode( bb, timeOffline );
+        }
+        
+        if ( delay != 0 )
+        {
+            bb.put( (byte)GracefulDisconnectConstants.GRACEFUL_DISCONNECT_DELAY_TAG );
+            bb.put( (byte)Length.getNbBytes( delay ) );
+            bb.put( Value.getBytes( delay ) );
+        }
+        
+        if ( replicatedContexts.size() != 0 )
+        {
+            bb.put( UniversalTag.SEQUENCE_TAG );
+            bb.put( Length.getBytes( replicatedContextsLength ) );
+            
+            Iterator replicatedContextIterator = replicatedContexts.iterator();
+            
+            // We may have more than one reference.
+            while (replicatedContextIterator.hasNext())
+            {
+                LdapURL url = (LdapURL)replicatedContextIterator.next();
+                Value.encode( bb, url.getBytes() );
+            }
+        }
+                 
+        return bb;
+    }
+    
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        sb.append( "    TimeOffline : " ).append( timeOffline ).append( '\n' );
+        sb.append( "    Delay : ").append( delay ).append( '\n' );
+        
+        if ( replicatedContexts.size() != 0 )
+        {
+            Iterator replicatedContextIterator = replicatedContexts.iterator();
+            sb.append( "    Replicated contexts :" );
+            
+            // We may have more than one reference.
+            while (replicatedContextIterator.hasNext())
+            {
+                LdapURL url = (LdapURL)replicatedContextIterator.next();
+                sb.append( "\n        " ).append(url.toString() );
+            }
+        }
+        
+        return sb.toString();
+    }
+}

Added: directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectConstants.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectConstants.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectConstants.java (added)
+++ directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectConstants.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,29 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+
+/**
+ * GracefulDisconnect extended operation constants  
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class GracefulDisconnectConstants
+{
+    public static final int GRACEFUL_DISCONNECT_DELAY_TAG = 0x80;
+}

Added: directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectContainer.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectContainer.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectContainer.java (added)
+++ directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectContainer.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,80 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+
+import org.apache.asn1.ber.AbstractContainer;
+import org.apache.asn1.ber.IAsn1Container;
+import org.apache.asn1.ber.grammar.IGrammar;
+
+
+/**
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectContainer extends AbstractContainer implements IAsn1Container 
+{
+    /** GracefulShutdown */
+    private GracefulDisconnect gracefulDisconnect;
+
+    /**
+     * Creates a new GracefulDisconnectContainer object.
+     * We will store one grammar, it's enough ...
+     */
+    public GracefulDisconnectContainer()
+    {
+        super( );
+        currentGrammar = 0;
+        grammars = new IGrammar[GracefulDisconnectStatesEnum.NB_GRAMMARS];
+        grammarStack = new IGrammar[1];
+        stateStack = new int[1];
+        nbGrammars = 0;
+
+        grammars[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_GRAMMAR] = GracefulDisconnectGrammar.getInstance();
+        grammarStack[currentGrammar] = grammars[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_GRAMMAR];
+        states = GracefulDisconnectStatesEnum.getInstance();
+    }
+
+
+    /**
+     * @return Returns the Graceful Shutdown object.
+     */
+    public GracefulDisconnect getGracefulDisconnect()
+    {
+
+        return gracefulDisconnect;
+    }
+
+    
+    /**
+     * Set a GracefulDisconnect Object into the container. It will be completed
+     * by the ldapDecoder.
+     *
+     * @param control the GracefulShutdown to set.
+     */
+    public void setGracefulDisconnect( GracefulDisconnect gracefulDisconnect )
+    {
+        this.gracefulDisconnect = gracefulDisconnect;
+    }
+
+    
+    public void clean()
+    {
+        super.clean();
+        gracefulDisconnect = null;
+    }
+}

Added: directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectDecoder.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectDecoder.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectDecoder.java (added)
+++ directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectDecoder.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,43 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.asn1.Asn1Object;
+import org.apache.asn1.ber.Asn1Decoder;
+import org.apache.asn1.codec.DecoderException;
+
+
+/**
+ * A decoder for GracefulDisconnects.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectDecoder extends Asn1Decoder
+{
+    private static final Asn1Decoder decoder = new Asn1Decoder();
+    
+    public Asn1Object decode(byte[] controlBytes) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        decoder.decode( bb, container );
+        return container.getGracefulDisconnect();
+    }
+}

Added: directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectGrammar.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectGrammar.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectGrammar.java (added)
+++ directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectGrammar.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,213 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+import org.apache.asn1.ber.IAsn1Container;
+import org.apache.asn1.ber.grammar.AbstractGrammar;
+import org.apache.asn1.ber.grammar.GrammarAction;
+import org.apache.asn1.ber.grammar.GrammarTransition;
+import org.apache.asn1.ber.grammar.IGrammar;
+import org.apache.asn1.ber.tlv.UniversalTag;
+import org.apache.asn1.ber.tlv.Value;
+import org.apache.asn1.codec.DecoderException;
+import org.apache.asn1.util.IntegerDecoder;
+import org.apache.asn1.util.IntegerDecoderException;
+import org.apache.ldap.common.util.StringTools;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.ldap.common.codec.util.LdapURL;
+import org.apache.ldap.common.codec.util.LdapURLEncodingException;
+
+
+
+/**
+ * This class implements the Graceful Disconnect. All the actions are declared in this
+ * class. As it is a singleton, these declaration are only done once.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectGrammar extends AbstractGrammar implements IGrammar
+{
+    /** The logger */
+    private static final Logger log = LoggerFactory.getLogger( GracefulDisconnectGrammar.class );
+
+    /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */
+    private static IGrammar instance = new GracefulDisconnectGrammar();
+
+    /**
+     * Creates a new GracefulDisconnectGrammar object.
+     */
+    private GracefulDisconnectGrammar()
+    {
+        name = GracefulDisconnectGrammar.class.getName();
+        statesEnum = GracefulDisconnectStatesEnum.getInstance();
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[GracefulDisconnectStatesEnum.LAST_GRACEFUL_DISCONNECT_STATE][256];
+
+        super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_TAG][UniversalTag.SEQUENCE_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_TAG,
+                    GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_VALUE][UniversalTag.SEQUENCE_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_VALUE,
+                    GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG, 
+                new GrammarAction( "Init Graceful Disconnect" )
+                {
+                    public void action( IAsn1Container container ) 
+                    {
+                        GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
+                        GracefulDisconnect gracefulDisconnect = new GracefulDisconnect();
+                        gracefulDisconnectContainer.setGracefulDisconnect( gracefulDisconnect );
+                        gracefulDisconnectContainer.grammarEndAllowed( true );
+                    }
+                }
+            );
+
+        super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG][UniversalTag.INTEGER_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG,
+                GracefulDisconnectStatesEnum.TIME_OFFLINE_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG][GracefulDisconnectConstants.GRACEFUL_DISCONNECT_DELAY_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG,
+                GracefulDisconnectStatesEnum.DELAY_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG][UniversalTag.SEQUENCE_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_VALUE][UniversalTag.INTEGER_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_VALUE, 
+                GracefulDisconnectStatesEnum.DELAY_OR_REPLICATED_OR_END_TAG, 
+                new GrammarAction( "Set Graceful Disconnect delay" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
+                        Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
+                        
+                        try
+                        {
+                            int timeOffline = IntegerDecoder.parse( value, 0, 720 );
+                            
+                            if ( log.isDebugEnabled() )
+                            {
+                                log.debug( "Time Offline = " + timeOffline );
+                            }
+                            
+                            gracefulDisconnectContainer.getGracefulDisconnect().setTimeOffline( timeOffline );
+                            gracefulDisconnectContainer.grammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException e )
+                        {
+                            String msg = "failed to decode the timeOffline, the value should be between 0 and 720 minutes, it is '" + 
+                                            StringTools.dumpBytes( value.getData() ) + "'";
+                            log.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                    }
+                }
+            );
+
+        super.transitions[GracefulDisconnectStatesEnum.DELAY_OR_REPLICATED_OR_END_TAG][GracefulDisconnectConstants.GRACEFUL_DISCONNECT_DELAY_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.DELAY_OR_REPLICATED_OR_END_TAG,
+                GracefulDisconnectStatesEnum.DELAY_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.DELAY_VALUE][GracefulDisconnectConstants.GRACEFUL_DISCONNECT_DELAY_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.DELAY_VALUE, 
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_OR_END_TAG, 
+                new GrammarAction( "Set Graceful Disconnect Delay" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
+                        Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
+                        
+                        try
+                        {
+                            int delay = IntegerDecoder.parse( value, 0, 86400 );
+                            
+                            if ( log.isDebugEnabled() )
+                            {
+                                log.debug( "Delay = " + delay );
+                            }
+                            
+                            gracefulDisconnectContainer.getGracefulDisconnect().setDelay( delay );
+                            gracefulDisconnectContainer.grammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException e )
+                        {
+                            String msg = "failed to decode the delay, the value should be between 0 and 86400 seconds, it is '" + 
+                                        StringTools.dumpBytes( value.getData() ) + "'";
+                            log.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                    }
+                }
+            );
+
+        super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_OR_END_TAG][UniversalTag.SEQUENCE_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_OR_END_TAG,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_VALUE][UniversalTag.SEQUENCE_TAG] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_VALUE, 
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_OR_END_TAG, null );
+    
+        super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_OR_END_TAG][UniversalTag.OCTET_STRING] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_OR_END_TAG,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_VALUE, null );
+
+        super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_VALUE][UniversalTag.OCTET_STRING] =
+            new GrammarTransition( GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_VALUE, 
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXT_OR_END_TAG, 
+                new GrammarAction( "Replicated context URL" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
+                        Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
+                        
+                        try
+                        {
+                            LdapURL url = new LdapURL( value.getData() );
+                            gracefulDisconnectContainer.getGracefulDisconnect().addReplicatedContexts( url );
+                            gracefulDisconnectContainer.grammarEndAllowed( true );
+                        }
+                        catch ( LdapURLEncodingException e )
+                        {
+                            String msg = "failed to decode the URL '" + 
+                                        StringTools.dumpBytes( value.getData() ) + "'";
+                            log.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                    }
+                }
+            );
+    }
+
+    /**
+     * This class is a singleton.
+     *
+     * @return An instance on this grammar
+     */
+    public static IGrammar getInstance()
+    {
+        return instance;
+    }
+}

Added: directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectStatesEnum.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectStatesEnum.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectStatesEnum.java (added)
+++ directory/trunks/common/ldap/src/main/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectStatesEnum.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,193 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+
+import org.apache.asn1.ber.grammar.IStates;
+import org.apache.asn1.ber.grammar.IGrammar;
+
+
+/**
+ * This class store the GracefulDisconnect's grammar constants.
+ * It is also used for debugging purposes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectStatesEnum implements IStates
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    //=========================================================================
+    // GracefulDisconnect grammar states 
+    //=========================================================================
+
+    /** Sequence Tag */
+    public static int GRACEFUL_DISCONNECT_SEQUENCE_TAG = 0;
+
+    /** Sequence Value */
+    public static int GRACEFUL_DISCONNECT_SEQUENCE_VALUE = 1;
+
+    /** Time offline Tag */
+    public static int TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG = 2;
+
+    /** Time offline Value */
+    public static int TIME_OFFLINE_VALUE = 3;
+
+    /** Delay Tag */
+    public static int DELAY_OR_REPLICATED_OR_END_TAG = 4;
+
+    /** Delay Value */
+    public static int DELAY_VALUE = 5;
+
+    /** Replicated contexts Tag */
+    public static int REPLICATED_CONTEXTS_OR_END_TAG = 6;
+
+    /** Replicated contexts Value */
+    public static int REPLICATED_CONTEXTS_VALUE = 7;
+
+    /** Replicated contexts Tag */
+    public static int REPLICATED_CONTEXT_OR_END_TAG = 8;
+
+    /** Replicated contexts Value */
+    public static int REPLICATED_CONTEXT_VALUE = 9;
+
+    /** terminal state */
+    public static int LAST_GRACEFUL_DISCONNECT_STATE = 10;
+
+    //=========================================================================
+    // Grammars declaration.
+    //=========================================================================
+    /** GracefulDisconnect grammar */
+    public static final int GRACEFUL_DISCONNECT_GRAMMAR_SWITCH = 0x0100;
+
+    /** GracefulDisconnect grammar number */
+    public static final int GRACEFUL_DISCONNECT_GRAMMAR = 0;
+
+    /** The total number of grammars used */
+    public static final int NB_GRAMMARS = 1;
+
+    //=========================================================================
+    // Grammar switches debug strings 
+    //=========================================================================
+    /** A string representation of grammars */
+    private static String[] GrammarSwitchString =
+        new String[]
+        {
+            "GRACEFUL_DISCONNECT_GRAMMAR_SWITCH"
+        };
+
+    //=========================================================================
+    // States debug strings 
+    //=========================================================================
+    /** A string representation of all the states */
+    private static String[] GracefulDisconnectString = new String[]
+    {
+        "GRACEFUL_DISCONNECT_SEQUENCE_TAG",
+        "GRACEFUL_DISCONNECT_SEQUENCE_VALUE",
+        "TIME_OFFLINE_OR_DELAY_OR_REPLICATED_OR_END_TAG",
+        "TIME_OFFLINE_VALUE",
+        "DELAY_OR_REPLICATED_OR_END_TAG",
+        "DELAY_VALUE",
+        "REPLICATED_CONTEXTS_OR_END_TAG",
+        "REPLICATED_CONTEXTS_VALUE",
+        "REPLICATED_CONTEXT_OR_END_TAG",
+        "REPLICATED_CONTEXT_VALUE"
+    };
+
+    /** The instance */
+    private static GracefulDisconnectStatesEnum instance = new GracefulDisconnectStatesEnum();
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * This is a private constructor. This class is a singleton
+     *
+     */
+    private GracefulDisconnectStatesEnum()
+    {
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Get an instance of this class
+     * @return An instance on this class
+     */
+    public static IStates getInstance()
+    {
+        return instance;
+    }
+
+    /**
+     * Get the grammar name
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        switch ( grammar )
+        {
+            case GRACEFUL_DISCONNECT_GRAMMAR: return "GRACEFUL_DISCONNECT_GRAMMAR";
+            default: return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Get the grammar name
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( IGrammar grammar )
+    {
+        if ( grammar instanceof GracefulDisconnectGrammar )
+        {
+            return "GRACEFUL_DISCONNECT_GRAMMAR";
+        }
+        
+        return "UNKNOWN GRAMMAR";
+    }
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param grammar The current grammar being used
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int grammar, int state )
+    {
+
+        if ( ( state & GRAMMAR_SWITCH_MASK ) != 0 )
+        {
+            return ( state == END_STATE ) ? "END_STATE"
+                : GrammarSwitchString[( ( state & GRAMMAR_SWITCH_MASK ) >> 8 ) - 1];
+        }
+        else
+        {
+
+            switch ( grammar )
+            {
+
+                case GRACEFUL_DISCONNECT_GRAMMAR :
+                    return ( ( state == GRAMMAR_END ) ? "GRACEFUL_DISCONNECT_END_STATE" : GracefulDisconnectString[state] );
+
+                default :
+                    return "UNKNOWN";
+            }
+        }
+    }
+}

Added: directory/trunks/common/ldap/src/test/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectTest.java
URL: http://svn.apache.org/viewcvs/directory/trunks/common/ldap/src/test/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectTest.java?rev=371152&view=auto
==============================================================================
--- directory/trunks/common/ldap/src/test/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectTest.java (added)
+++ directory/trunks/common/ldap/src/test/java/org/apache/ldap/common/codec/extended/operations/GracefulDisconnectTest.java Sat Jan 21 16:34:03 2006
@@ -0,0 +1,301 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed 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.
+ *
+ */
+package org.apache.ldap.common.codec.extended.operations;
+
+import java.nio.ByteBuffer;
+
+import javax.naming.NamingException;
+
+import org.apache.asn1.codec.DecoderException;
+import org.apache.asn1.ber.Asn1Decoder;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+/**
+ * Test the GracefulDisconnectTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectTest extends TestCase {
+    /**
+     * Test the decoding of a GracefulDisconnect
+     */
+    public void testDecodeGracefulDisconnectSuccess() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x70 );
+        bb.put( new byte[]
+            {
+                0x30, 0x6E, 		        // GracefulDisconnec ::= SEQUENCE {
+				  0x02, 0x01, 0x01,         //     timeOffline INTEGER (0..720) DEFAULT 0,
+				  (byte)0x80, 0x01, 0x01,	//     delay INTEGER (0..86400) DEFAULT 0
+                                            //     replicatedContexts Referral OPTIONAL
+                  0x30, 0x66, 
+                    0x04, 0x1F, 
+                      'l', 'd', 'a', 'p', ':', '/', '/', 'd', 
+                      'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 
+                      '.', 'a', 'p', 'a', 'c', 'h', 'e', '.', 
+                      'o', 'r', 'g', ':', '8', '0', '/',
+                    0x04, 0x43,
+                      'l', 'd', 'a', 'p', ':', '/', '/', 'l', 
+                      'd', 'a', 'p', '.', 'n', 'e', 't', 's', 
+                      'c', 'a', 'p', 'e', '.', 'c', 'o', 'm', 
+                      '/', 'o', '=', 'B', 'a', 'b', 's', 'c', 
+                      'o', ',', 'c', '=', 'U', 'S', '?', '?', 
+                      '?', '(', 'i', 'n', 't', '=', '%', '5', 
+                      'c', '0', '0', '%', '5', 'c', '0', '0', 
+                      '%', '5', 'c', '0', '0', '%', '5', 'c', 
+                      '0', '4', ')'
+                                            // }
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            Assert.fail( de.getMessage() );
+        }
+        
+        GracefulDisconnect gracefulDisconnect = container.getGracefulDisconnect();
+        assertEquals( 1, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 1, gracefulDisconnect.getDelay() );
+        assertEquals( 2, gracefulDisconnect.getReplicatedContexts().size() );
+        assertEquals( "ldap://directory.apache.org:80/", gracefulDisconnect.getReplicatedContexts().get( 0 ).toString() );
+        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)", gracefulDisconnect.getReplicatedContexts().get( 1 ).toString() );
+    }
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a timeOffline only
+     */
+    public void testDecodeGracefulDisconnectTimeOffline() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x03,                 // GracefulDisconnect ::= SEQUENCE {
+                  0x02, 0x01, 0x01          //     timeOffline INTEGER (0..720) DEFAULT 0,
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            Assert.fail( de.getMessage() );
+        }
+        
+        GracefulDisconnect gracefulDisconnect = container.getGracefulDisconnect();
+        assertEquals( 1, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 0, gracefulDisconnect.getDelay() );
+    }
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a delay only
+     */
+    public void testDecodeGracefulDisconnectDelay() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x03,                 // GracefulDisconnect ::= SEQUENCE {
+                  (byte)0x80, 0x01, 0x01          //     delay INTEGER (0..86400) DEFAULT 0
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            Assert.fail( de.getMessage() );
+        }
+        
+        GracefulDisconnect gracefulDisconnect = container.getGracefulDisconnect();
+        assertEquals( 0, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 1, gracefulDisconnect.getDelay() );
+    }
+
+    /**
+     * Test the decoding of a empty GracefulDisconnect
+     */
+    public void testDecodeGracefulDisconnectEmpty() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x00                 // GracefulDisconnect ::= SEQUENCE {
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            Assert.fail( de.getMessage() );
+        }
+        
+        GracefulDisconnect gracefulDisconnect = container.getGracefulDisconnect();
+        assertEquals( 0, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 0, gracefulDisconnect.getDelay() );
+    }
+    
+    // Defensive tests
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a timeOffline off limit
+     */
+    public void testDecodeGracefulDisconnectTimeOfflineOffLimit() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x04,                     // GracefulDisconnect ::= SEQUENCE {
+                  0x02, 0x02, 0x03, (byte)0xE8  //     timeOffline INTEGER (0..720) DEFAULT 0,
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            System.out.println( de.getMessage() );
+            assertTrue( true );
+            return;
+        }
+        
+        fail( "We should not reach this point" );
+    }
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a delay off limit
+     */
+    public void testDecodeGracefulDisconnectDelayOffLimit() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x05,                     // GracefulDisconnect ::= SEQUENCE {
+                  (byte)0x80, 0x03, 0x01, (byte)0x86, (byte)0xA0  //     delay INTEGER (0..86400) DEFAULT 0
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            System.out.println( de.getMessage() );
+            assertTrue( true );
+            return;
+        }
+        
+        fail( "We should not reach this point" );
+    }
+
+    /**
+     * Test the decoding of a GracefulDisconnect with an empty TimeOffline
+     */
+    public void testDecodeGracefulDisconnectTimeOfflineEmpty() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x02,   // GracefulDisconnect ::= SEQUENCE {
+                  0x02, 0x00  //     timeOffline INTEGER (0..720) DEFAULT 0,
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            System.out.println( de.getMessage() );
+            assertTrue( true );
+            return;
+        }
+        
+        fail( "We should not reach this point" );
+    }
+
+    /**
+     * Test the decoding of a GracefulDisconnect with an empty delay
+     */
+    public void testDecodeGracefulDisconnectDelayEmpty() throws NamingException
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x02,         // GracefulDisconnect ::= SEQUENCE {
+                  (byte)0x80, 0x00  //     delay INTEGER (0..86400) DEFAULT 0
+            } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            System.out.println( de.getMessage() );
+            assertTrue( true );
+            return;
+        }
+        
+        fail( "We should not reach this point" );
+    }
+}