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 */
020package org.apache.directory.shared.ldap.extras.extended.ads_impl.gracefulDisconnect;
021
022
023import java.nio.ByteBuffer;
024import java.util.ArrayList;
025import java.util.List;
026
027import org.apache.directory.shared.asn1.EncoderException;
028import org.apache.directory.shared.asn1.ber.tlv.TLV;
029import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030import org.apache.directory.shared.asn1.ber.tlv.Value;
031import org.apache.directory.shared.ldap.model.url.LdapUrl;
032
033
034/**
035 * An extended operation to proceed a graceful disconnect
036 * 
037 * <pre>
038 *   GracefulDisconnect ::= SEQUENCE 
039 *   {
040 *       timeOffline           INTEGER (0..720) DEFAULT 0,
041 *       delay             [0] INTEGER (0..86400) DEFAULT 0,
042 *       replicatedContexts    Referral OPTIONAL
043 *   }
044 * </pre>
045 * 
046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047 */
048public class GracefulDisconnect extends GracefulAction
049{
050    /** List of the alternate servers to use */
051    // Two urls will be enough, generally
052    private List<LdapUrl> replicatedContexts = new ArrayList<LdapUrl>( 2 );
053
054    /** Length of the sequence */
055    private int gracefulDisconnectSequenceLength;
056
057    /** Length of the replicated contexts */
058    private int replicatedContextsLength;
059
060
061    /**
062     * Create a GracefulDisconnect object, with a timeOffline and a delay
063     * 
064     * @param timeOffline The time the server will be offline
065     * @param delay The delay before the disconnection
066     */
067    public GracefulDisconnect( int timeOffline, int delay )
068    {
069        super( timeOffline, delay );
070    }
071
072
073    /**
074     * Default constructor.
075     */
076    public GracefulDisconnect()
077    {
078        super();
079    }
080
081
082    /**
083     * Get the list of replicated servers
084     * 
085     * @return The list of replicated servers
086     */
087    public List<LdapUrl> getReplicatedContexts()
088    {
089        return replicatedContexts;
090    }
091
092
093    /**
094     * Add a new URL of a replicated server
095     * 
096     * @param replicatedContext The replictaed server to add.
097     */
098    public void addReplicatedContexts( LdapUrl replicatedContext )
099    {
100        replicatedContexts.add( replicatedContext );
101    }
102
103
104    /**
105     * Compute the GracefulDisconnect length 
106     * 
107     * 0x30 L1 
108     *   | 
109     *   +--> [ 0x02 0x0(1-4) [0..720] ] 
110     *   +--> [ 0x80 0x0(1-3) [0..86400] ] 
111     *   +--> [ 0x30 L2 
112     *           | 
113     *           +--> (0x04 L3 value) + ]
114     */
115    public int computeLength()
116    {
117        gracefulDisconnectSequenceLength = 0;
118
119        if ( timeOffline != 0 )
120        {
121            gracefulDisconnectSequenceLength += 1 + 1 + Value.getNbBytes( timeOffline );
122        }
123
124        if ( delay != 0 )
125        {
126            gracefulDisconnectSequenceLength += 1 + 1 + Value.getNbBytes( delay );
127        }
128
129        if ( replicatedContexts.size() > 0 )
130        {
131            replicatedContextsLength = 0;
132
133            // We may have more than one reference.
134            for ( LdapUrl replicatedContext:replicatedContexts )
135            {
136                int ldapUrlLength = replicatedContext.getNbBytes();
137                replicatedContextsLength += 1 + TLV.getNbBytes( ldapUrlLength ) + ldapUrlLength;
138            }
139
140            gracefulDisconnectSequenceLength += 1 + TLV.getNbBytes( replicatedContextsLength )
141                + replicatedContextsLength;
142        }
143
144        return 1 + TLV.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength;
145    }
146
147
148    /**
149     * Encodes the gracefulDisconnect extended operation.
150     * 
151     * @return A ByteBuffer that contains the encoded PDU
152     * @throws org.apache.directory.shared.asn1.EncoderException If anything goes wrong.
153     */
154    public ByteBuffer encode() throws EncoderException
155    {
156        // Allocate the bytes buffer.
157        ByteBuffer bb = ByteBuffer.allocate( computeLength() );
158
159        bb.put( UniversalTag.SEQUENCE.getValue() );
160        bb.put( TLV.getBytes( gracefulDisconnectSequenceLength ) );
161
162        if ( timeOffline != 0 )
163        {
164            Value.encode( bb, timeOffline );
165        }
166
167        if ( delay != 0 )
168        {
169            bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG );
170            bb.put( ( byte ) TLV.getNbBytes( delay ) );
171            bb.put( Value.getBytes( delay ) );
172        }
173
174        if ( replicatedContexts.size() != 0 )
175        {
176            bb.put( UniversalTag.SEQUENCE.getValue() );
177            bb.put( TLV.getBytes( replicatedContextsLength ) );
178
179            // We may have more than one reference.
180            for ( LdapUrl replicatedContext:replicatedContexts )
181            {
182                Value.encode( bb, replicatedContext.getBytesReference() );
183            }
184        }
185
186        return bb;
187    }
188
189
190    /**
191     * Return a string representation of the graceful disconnect
192     */
193    public String toString()
194    {
195        StringBuffer sb = new StringBuffer();
196
197        sb.append( "Graceful Disconnect extended operation" );
198        sb.append( "    TimeOffline : " ).append( timeOffline ).append( '\n' );
199        sb.append( "    Delay : " ).append( delay ).append( '\n' );
200
201        if ( ( replicatedContexts != null) && ( replicatedContexts.size() != 0 ) )
202        {
203            sb.append( "    Replicated contexts :" );
204
205            // We may have more than one reference.
206            for ( LdapUrl url:replicatedContexts )
207            {
208                sb.append( "\n        " ).append( url );
209            }
210        }
211
212        return sb.toString();
213    }
214}