001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect;
021    
022    
023    import java.nio.ByteBuffer;
024    import java.util.ArrayList;
025    import java.util.List;
026    
027    import org.apache.directory.shared.asn1.ber.tlv.TLV;
028    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
029    import org.apache.directory.shared.asn1.ber.tlv.Value;
030    import org.apache.directory.shared.asn1.codec.EncoderException;
031    import org.apache.directory.shared.ldap.codec.extended.operations.GracefulAction;
032    import org.apache.directory.shared.ldap.codec.extended.operations.GracefulActionConstants;
033    import org.apache.directory.shared.ldap.util.LdapURL;
034    
035    
036    /**
037     * An extended operation to proceed a graceful disconnect
038     * 
039     * <pre>
040     *   GracefulDisconnect ::= SEQUENCE 
041     *   {
042     *       timeOffline           INTEGER (0..720) DEFAULT 0,
043     *       delay             [0] INTEGER (0..86400) DEFAULT 0,
044     *       replicatedContexts    Referral OPTIONAL
045     *   }
046     * </pre>
047     * 
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev: 910150 $, $Date: 2010-02-15 02:37:34 +0100 (Mon, 15 Feb 2010) $, 
050     */
051    public class GracefulDisconnect extends GracefulAction
052    {
053        /** List of the alternate servers to use */
054        // Two urls will be enough, generally
055        private List<LdapURL> replicatedContexts = new ArrayList<LdapURL>( 2 );
056    
057        /** Length of the sequence */
058        private int gracefulDisconnectSequenceLength;
059    
060        /** Length of the replicated contexts */
061        private int replicatedContextsLength;
062    
063    
064        /**
065         * Create a GracefulDisconnect object, with a timeOffline and a delay
066         * 
067         * @param timeOffline The time the server will be offline
068         * @param delay The delay before the disconnection
069         */
070        public GracefulDisconnect( int timeOffline, int delay )
071        {
072            super( timeOffline, delay );
073        }
074    
075    
076        /**
077         * Default constructor.
078         */
079        public GracefulDisconnect()
080        {
081            super();
082        }
083    
084    
085        /**
086         * Get the list of replicated servers
087         * 
088         * @return The list of replicated servers
089         */
090        public List<LdapURL> getReplicatedContexts()
091        {
092            return replicatedContexts;
093        }
094    
095    
096        /**
097         * Add a new URL of a replicated server
098         * 
099         * @param replicatedContext The replictaed server to add.
100         */
101        public void addReplicatedContexts( LdapURL replicatedContext )
102        {
103            replicatedContexts.add( replicatedContext );
104        }
105    
106    
107        /**
108         * Compute the GracefulDisconnect length 
109         * 
110         * 0x30 L1 
111         *   | 
112         *   +--> [ 0x02 0x0(1-4) [0..720] ] 
113         *   +--> [ 0x80 0x0(1-3) [0..86400] ] 
114         *   +--> [ 0x30 L2 
115         *           | 
116         *           +--> (0x04 L3 value) + ]
117         */
118        public int computeLength()
119        {
120            gracefulDisconnectSequenceLength = 0;
121    
122            if ( timeOffline != 0 )
123            {
124                gracefulDisconnectSequenceLength += 1 + 1 + Value.getNbBytes( timeOffline );
125            }
126    
127            if ( delay != 0 )
128            {
129                gracefulDisconnectSequenceLength += 1 + 1 + Value.getNbBytes( delay );
130            }
131    
132            if ( replicatedContexts.size() > 0 )
133            {
134                replicatedContextsLength = 0;
135    
136                // We may have more than one reference.
137                for ( LdapURL replicatedContext:replicatedContexts )
138                {
139                    int ldapUrlLength = replicatedContext.getNbBytes();
140                    replicatedContextsLength += 1 + TLV.getNbBytes( ldapUrlLength ) + ldapUrlLength;
141                }
142    
143                gracefulDisconnectSequenceLength += 1 + TLV.getNbBytes( replicatedContextsLength )
144                    + replicatedContextsLength;
145            }
146    
147            return 1 + TLV.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength;
148        }
149    
150    
151        /**
152         * Encodes the gracefulDisconnect extended operation.
153         * 
154         * @return A ByteBuffer that contains the encoded PDU
155         * @throws EncoderException If anything goes wrong.
156         */
157        public ByteBuffer encode() throws EncoderException
158        {
159            // Allocate the bytes buffer.
160            ByteBuffer bb = ByteBuffer.allocate( computeLength() );
161    
162            bb.put( UniversalTag.SEQUENCE_TAG );
163            bb.put( TLV.getBytes( gracefulDisconnectSequenceLength ) );
164    
165            if ( timeOffline != 0 )
166            {
167                Value.encode( bb, timeOffline );
168            }
169    
170            if ( delay != 0 )
171            {
172                bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG );
173                bb.put( ( byte ) TLV.getNbBytes( delay ) );
174                bb.put( Value.getBytes( delay ) );
175            }
176    
177            if ( replicatedContexts.size() != 0 )
178            {
179                bb.put( UniversalTag.SEQUENCE_TAG );
180                bb.put( TLV.getBytes( replicatedContextsLength ) );
181    
182                // We may have more than one reference.
183                for ( LdapURL replicatedContext:replicatedContexts )
184                {
185                    Value.encode( bb, replicatedContext.getBytesReference() );
186                }
187            }
188    
189            return bb;
190        }
191    
192    
193        /**
194         * Return a string representation of the graceful disconnect
195         */
196        public String toString()
197        {
198            StringBuffer sb = new StringBuffer();
199    
200            sb.append( "Graceful Disconnect extended operation" );
201            sb.append( "    TimeOffline : " ).append( timeOffline ).append( '\n' );
202            sb.append( "    Delay : " ).append( delay ).append( '\n' );
203    
204            if ( ( replicatedContexts != null) && ( replicatedContexts.size() != 0 ) )
205            {
206                sb.append( "    Replicated contexts :" );
207    
208                // We may have more than one reference.
209                for ( LdapURL url:replicatedContexts )
210                {
211                    sb.append( "\n        " ).append( url );
212                }
213            }
214    
215            return sb.toString();
216        }
217    }