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 *    https://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.api.ldap.model.message.extended;
021
022
023import org.apache.directory.api.i18n.I18n;
024import org.apache.directory.api.ldap.model.message.AbstractExtendedResponse;
025import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
026import org.apache.directory.api.util.Strings;
027
028
029/**
030 * An extended operation intended for notifying clients of upcoming
031 * disconnection. Here's what <a
032 * href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a> has to say about
033 * it:
034 * 
035 * <pre>
036 *  Section 4.1.1 (Small snippet on sending NoD)
037 *  
038 *     If the server receives a PDU from the client in which the LDAPMessage
039 *     SEQUENCE tag cannot be recognized, the messageID cannot be parsed,
040 *     the tag of the protocolOp is not recognized as a request, or the
041 *     encoding structures or lengths of data fields are found to be
042 *     incorrect, then the server MUST return the notice of disconnection
043 *     described in section 4.4.1, with resultCode protocolError, and
044 *     immediately close the connection. In other cases that the server
045 *     cannot parse the request received by the client, the server MUST
046 *     return an appropriate response to the request, with the resultCode
047 *     set to protocolError.
048 *     
049 *  ...   
050 *     
051 *  4.4. Unsolicited Notification
052 *  
053 *     An unsolicited notification is an LDAPMessage sent from the server to
054 *     the client which is not in response to any LDAPMessage received by
055 *     the server. It is used to signal an extraordinary condition in the
056 *     server or in the connection between the client and the server.  The
057 *     notification is of an advisory nature, and the server will not expect
058 *     any response to be returned from the client.
059 *  
060 *     The unsolicited notification is structured as an LDAPMessage in which
061 *     the messageID is 0 and protocolOp is of the extendedResp form.  The
062 *     responseName field of the ExtendedResponse is present. The LDAPOID
063 *     value MUST be unique for this notification, and not be used in any
064 *     other situation.
065 *  
066 *     One unsolicited notification is defined in this document.
067 *  
068 *  4.4.1. Notice of Disconnection
069 *  
070 *     This notification may be used by the server to advise the client that
071 *     the server is about to close the connection due to an error
072 *     condition. Note that this notification is NOT a response to an
073 *     unbind requested by the client: the server MUST follow the procedures
074 *     of section 4.3. This notification is intended to assist clients in
075 *     distinguishing between an error condition and a transient network
076 *     failure. As with a connection close due to network failure, the
077 *     client MUST NOT assume that any outstanding requests which modified
078 *     the directory have succeeded or failed.
079 *  
080 *     The responseName is 1.3.6.1.4.1.1466.20036, the response field is
081 *     absent, and the resultCode is used to indicate the reason for the
082 *     disconnection.
083 *  
084 *     The following resultCode values are to be used in this notification:
085 *  
086 *     - protocolError: The server has received data from the client in
087 *       which the LDAPMessage structure could not be parsed.
088 *  
089 *     - strongAuthRequired: The server has detected that an established
090 *       underlying security association protecting communication between
091 *       the client and server has unexpectedly failed or been compromised.
092 *  
093 *     - unavailable: This server will stop accepting new connections and
094 *       operations on all existing connections, and be unavailable for an
095 *       extended period of time. The client may make use of an alternative
096 *       server.
097 *  
098 *     After sending this notice, the server MUST close the connection.
099 *     After receiving this notice, the client MUST NOT transmit any further
100 *     on the connection, and may abruptly close the connection.
101 * </pre>
102 * 
103 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
104 */
105public final class NoticeOfDisconnect extends AbstractExtendedResponse
106{
107    /** The OID of the NotiveOfDisconnect extended operation. */
108    public static final String EXTENSION_OID = "1.3.6.1.4.1.1466.20036";
109
110    /** The single instance with unavailable result code. */
111    public static final NoticeOfDisconnect UNAVAILABLE = new NoticeOfDisconnect( ResultCodeEnum.UNAVAILABLE );
112
113    /** The single instance with protocolError result code. */
114    public static final NoticeOfDisconnect PROTOCOLERROR = new NoticeOfDisconnect( ResultCodeEnum.PROTOCOL_ERROR );
115
116    /** The single instance with strongAuthRequired result code. */
117    public static final NoticeOfDisconnect STRONGAUTHREQUIRED = new NoticeOfDisconnect(
118        ResultCodeEnum.STRONG_AUTH_REQUIRED );
119
120
121    /**
122     * Creates a new instance of NoticeOfDisconnect.
123     * 
124     * @param rcode The result code
125     */
126    private NoticeOfDisconnect( ResultCodeEnum rcode )
127    {
128        super( 0, EXTENSION_OID );
129
130        switch ( rcode )
131        {
132            case UNAVAILABLE:
133                break;
134
135            case PROTOCOL_ERROR:
136                break;
137
138            case STRONG_AUTH_REQUIRED:
139                break;
140
141            default:
142                throw new IllegalArgumentException( I18n.err( I18n.ERR_13503_RESULT_CODE_SHOULD_BE_IN, ResultCodeEnum.UNAVAILABLE,
143                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
144        }
145
146        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
147        super.getLdapResult().setMatchedDn( null );
148        super.getLdapResult().setResultCode( rcode );
149    }
150    
151    
152    /**
153     * Create a NoD associated with a result code enum
154     *
155     * @param rcode The result code
156     * @return The created NoticeOfDisconnect
157     */
158    public static NoticeOfDisconnect createNoticeOfDisconnect( ResultCodeEnum rcode )
159    {
160        NoticeOfDisconnect nod;
161        
162        switch ( rcode )
163        {
164            case UNAVAILABLE:
165                nod = UNAVAILABLE;
166                break;
167                
168            case PROTOCOL_ERROR:
169                nod = PROTOCOLERROR;
170                break;
171                
172            case STRONG_AUTH_REQUIRED:
173                nod = STRONGAUTHREQUIRED;
174                break;
175                
176            default:
177                nod = new NoticeOfDisconnect( rcode );
178                break;
179        }
180        
181        nod.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
182        nod.getLdapResult().setMatchedDn( null );
183        nod.getLdapResult().setResultCode( rcode );
184        
185        return nod;
186    }
187
188
189    // ------------------------------------------------------------------------
190    // ExtendedResponse Interface Method Implementations
191    // ------------------------------------------------------------------------
192
193    /**
194     * Gets the reponse OID specific encoded response values.
195     * 
196     * @return the response specific encoded response values.
197     */
198    public byte[] getResponse()
199    {
200        return Strings.EMPTY_BYTES;
201    }
202
203
204    /**
205     * Sets the response OID specific encoded response values.
206     * 
207     * @param value the response specific encoded response values.
208     */
209    public void setResponse( byte[] value )
210    {
211        throw new UnsupportedOperationException( I18n.err( I18n.ERR_13505_HARDCODED_ZERO_LENGTH_RESPONSE ) );
212    }
213
214
215    /**
216     * Sets the OID uniquely identifying this extended response (a.k.a. its
217     * name).
218     * 
219     * @param oid the OID of the extended response type.
220     */
221    @Override
222    public void setResponseName( String oid )
223    {
224        throw new UnsupportedOperationException( I18n.err( I18n.ERR_13504_FIX_OID, EXTENSION_OID ) );
225    }
226
227
228    /**
229     * {@inheritDoc}
230     */
231    @Override
232    public int hashCode()
233    {
234        int hash = 37;
235        // Seems simple but look at the equals() method ...
236        hash = hash * 17 + getClass().getName().hashCode();
237
238        return hash;
239    }
240
241
242    /**
243     * {@inheritDoc}
244     */
245    @Override
246    public boolean equals( Object obj )
247    {
248        if ( obj == this )
249        {
250            return true;
251        }
252
253        return obj instanceof NoticeOfDisconnect;
254    }
255}