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.message.extended;
021    
022    
023    import java.nio.ByteBuffer;
024    import java.util.Iterator;
025    import java.util.List;
026    
027    import org.apache.directory.shared.asn1.ber.Asn1Decoder;
028    import org.apache.directory.shared.asn1.codec.DecoderException;
029    import org.apache.directory.shared.asn1.codec.EncoderException;
030    import org.apache.directory.shared.i18n.I18n;
031    import org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnectContainer;
032    import org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnectDecoder;
033    import org.apache.directory.shared.ldap.codec.util.LdapURLEncodingException;
034    import org.apache.directory.shared.ldap.message.ExtendedResponseImpl;
035    import org.apache.directory.shared.ldap.message.ReferralImpl;
036    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
037    import org.apache.directory.shared.ldap.message.internal.InternalReferral;
038    import org.apache.directory.shared.ldap.util.LdapURL;
039    import org.slf4j.Logger;
040    import org.slf4j.LoggerFactory;
041    
042    
043    /**
044     * An unsolicited notification, extended response, intended for notifying
045     * clients of upcoming disconnection due to intended service windows. Unlike the
046     * {@link NoticeOfDisconnect} this response contains additional information about
047     * the amount of time the server will be offline and exactly when it intends to
048     * shutdown.
049     * 
050     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051     * @version $Rev: 912436 $
052     */
053    public class GracefulDisconnect extends ExtendedResponseImpl
054    {
055        private static final long serialVersionUID = -4682291068700593492L;
056    
057        public static final String EXTENSION_OID = "1.3.6.1.4.1.18060.0.1.5";
058    
059        private static final Logger log = LoggerFactory.getLogger( GracefulDisconnect.class );
060    
061        /** offline Time after disconnection */
062        private int timeOffline;
063    
064        /** Delay before disconnection */
065        private int delay;
066    
067        /** String based LDAP URL that may be followed for replicated namingContexts */
068        private InternalReferral replicatedContexts = new ReferralImpl();
069    
070    
071        public GracefulDisconnect(byte[] value) throws DecoderException
072        {
073            super( 0, EXTENSION_OID );
074            if ( value != null )
075            {
076                this.value = new byte[ value.length ];
077                System.arraycopy( value, 0, this.value, 0, value.length );
078            } else {
079                this.value = null;
080            }
081            decodeValue();
082        }
083    
084    
085        public GracefulDisconnect(int timeOffline, int delay)
086        {
087            super( 0, EXTENSION_OID );
088            super.oid = EXTENSION_OID;
089            this.timeOffline = timeOffline;
090            this.delay = delay;
091    
092            StringBuffer buf = new StringBuffer();
093            buf.append( "The server will disconnect and will be unavailable for " ).append( timeOffline );
094            buf.append( " minutes in " ).append( delay ).append( " seconds." );
095    
096            super.getLdapResult().setErrorMessage( buf.toString() );
097            super.getLdapResult().setMatchedDn( null );
098            super.getLdapResult().setResultCode( ResultCodeEnum.UNAVAILABLE );
099    
100            encodeResponse();
101        }
102    
103    
104        private void decodeValue() throws DecoderException
105        {
106            GracefulDisconnectDecoder decoder = new GracefulDisconnectDecoder();
107            org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnect codec = null;
108    
109            try
110            {
111                codec = ( org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnect ) decoder
112                    .decode( value );
113                this.timeOffline = codec.getTimeOffline();
114                this.delay = codec.getDelay();
115                super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
116                List<LdapURL> contexts = codec.getReplicatedContexts();
117                
118                for ( int ii = 0; ii < contexts.size(); ii++ )
119                {
120                    replicatedContexts.addLdapUrl( contexts.get( ii ).toString() );
121                }
122            }
123            catch ( DecoderException e )
124            {
125                log.error( I18n.err( I18n.ERR_04169 ), e );
126                throw e;
127            }
128        }
129    
130    
131        private void encodeResponse()
132        {
133            org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnect codec = new org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnect();
134            codec.setTimeOffline( this.timeOffline );
135            codec.setDelay( this.delay );
136            Iterator<String> contexts = this.replicatedContexts.getLdapUrls().iterator();
137            
138            while ( contexts.hasNext() )
139            {
140                String urlstr = ( String ) contexts.next();
141                LdapURL url = null;
142                try
143                {
144                    url = new LdapURL( urlstr );
145                }
146                catch ( LdapURLEncodingException e )
147                {
148                    log.error( I18n.err( I18n.ERR_04170, urlstr ), e );
149                    continue;
150                }
151                codec.addReplicatedContexts( url );
152            }
153    
154            try
155            {
156                super.value = codec.encode().array();
157            }
158            catch ( EncoderException e )
159            {
160                log.error( I18n.err( I18n.ERR_04171 ), e );
161                throw new RuntimeException( e );
162            }
163        }
164    
165    
166        // ------------------------------------------------------------------------
167        // ExtendedResponse Interface Method Implementations
168        // ------------------------------------------------------------------------
169    
170        /**
171         * Gets the reponse OID specific encoded response values.
172         * 
173         * @return the response specific encoded response values.
174         */
175        public byte[] getResponse()
176        {
177            if ( value == null )
178            {
179                encodeResponse();
180            }
181    
182            final byte[] copy = new byte[ value.length ];
183            System.arraycopy( value, 0, copy, 0, value.length );
184            return copy;
185        }
186    
187    
188        /**
189         * Sets the reponse OID specific encoded response values.
190         * 
191         * @param value
192         *            the response specific encoded response values.
193         */
194        public void setResponse( byte[] value )
195        {
196            ByteBuffer bb = ByteBuffer.wrap( value );
197            GracefulDisconnectContainer container = new GracefulDisconnectContainer();
198            Asn1Decoder decoder = new Asn1Decoder();
199            try
200            {
201                decoder.decode( bb, container );
202            }
203            catch ( DecoderException e )
204            {
205                log.error( I18n.err( I18n.ERR_04172 ), e );
206            }
207    
208            org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect.GracefulDisconnect codec = container
209                .getGracefulDisconnect();
210            this.delay = codec.getDelay();
211            this.timeOffline = codec.getTimeOffline();
212            List<LdapURL> contexts = codec.getReplicatedContexts();
213            
214            for ( int ii = 0; ii < contexts.size(); ii++ )
215            {
216                LdapURL url = contexts.get( ii );
217                replicatedContexts.addLdapUrl( url.toString() );
218            }
219    
220            if ( value != null )
221            {
222                this.value = new byte[ value.length ];
223                System.arraycopy( value, 0, this.value, 0, value.length );
224            } else {
225                this.value = null;
226            }
227        }
228    
229    
230        /**
231         * Gets the OID uniquely identifying this extended response (a.k.a. its
232         * name).
233         * 
234         * @return the OID of the extended response type.
235         */
236        public String getResponseName()
237        {
238            return EXTENSION_OID;
239        }
240    
241    
242        /**
243         * Sets the OID uniquely identifying this extended response (a.k.a. its
244         * name).
245         * 
246         * @param oid
247         *            the OID of the extended response type.
248         */
249        public void setResponseName( String oid )
250        {
251            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04168, EXTENSION_OID ) );
252        }
253    
254    
255        // -----------------------------------------------------------------------
256        // Parameters of the Extended Response Value
257        // -----------------------------------------------------------------------
258    
259        public void setDelay( int delay )
260        {
261            this.delay = delay;
262        }
263    
264    
265        public void setTimeOffline( int timeOffline )
266        {
267            this.timeOffline = timeOffline;
268        }
269    
270    
271        public int getDelay()
272        {
273            return delay;
274        }
275    
276    
277        public int getTimeOffline()
278        {
279            return timeOffline;
280        }
281    
282    
283        public InternalReferral getReplicatedContexts()
284        {
285            return replicatedContexts;
286        }
287    }