View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
21  
22  
23  import java.nio.ByteBuffer;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.apache.directory.api.asn1.DecoderException;
28  import org.apache.directory.api.asn1.EncoderException;
29  import org.apache.directory.api.asn1.ber.tlv.BerValue;
30  import org.apache.directory.api.asn1.ber.tlv.TLV;
31  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
34  import org.apache.directory.api.ldap.codec.api.LdapApiService;
35  import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponse;
36  import org.apache.directory.api.ldap.model.message.Referral;
37  import org.apache.directory.api.util.Strings;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  
42  /**
43   * A Decorator for CancelResponses.
44   *
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   */
47  public class GracefulDisconnectResponseDecorator extends ExtendedResponseDecorator<GracefulDisconnectResponse>
48      implements GracefulDisconnectResponse
49  {
50      /** The logger. */
51      private static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectResponseDecorator.class );
52  
53      /** Length of the sequence */
54      private int gracefulDisconnectSequenceLength;
55  
56      /** Length of the replicated contexts */
57      private int replicatedContextsLength;
58      
59      /** The encoded LDAP URL list */
60      private List<byte[]> ldapUrlBytes;
61  
62      private GracefulDisconnectResponse gracefulDisconnectResponse;
63  
64      /**
65       * Creates a new instance of CancelResponseDecorator.
66       *
67       * @param codec The LDAP service instance
68       * @param decoratedMessage The decorated message
69       */
70      public GracefulDisconnectResponseDecorator( LdapApiService codec, GracefulDisconnectResponse decoratedMessage )
71      {
72          super( codec, decoratedMessage );
73          gracefulDisconnectResponse = decoratedMessage;
74      }
75  
76      
77      // ------------------------------------------------------------------------
78      // ExtendedResponse Interface Method Implementations
79      // ------------------------------------------------------------------------
80      /**
81       * Gets the response OID specific encoded response values.
82       * 
83       * @return the response specific encoded response values.
84       */
85      @Override
86      public byte[] getResponseValue()
87      {
88          if ( responseValue == null )
89          {
90              try
91              {
92                  responseValue = encodeInternal().array();
93              }
94              catch ( EncoderException e )
95              {
96                  LOG.error( I18n.err( I18n.ERR_04164 ), e );
97                  throw new RuntimeException( e );
98              }
99          }
100 
101         return responseValue;
102     }
103 
104 
105     /**
106      * Sets the response OID specific encoded response values.
107      * 
108      * @param responseValue the response specific encoded response values.
109      */
110     @Override
111     public void setResponseValue( byte[] responseValue )
112     {
113         GracefulDisconnectDecoder decoder = new GracefulDisconnectDecoder();
114 
115         try
116         {
117             if ( responseValue != null )
118             {
119                 decoder.decode( responseValue );
120                 this.responseValue = new byte[responseValue.length];
121                 System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
122             }
123             else
124             {
125                 this.responseValue = null;
126             }
127         }
128         catch ( DecoderException e )
129         {
130             LOG.error( I18n.err( I18n.ERR_04172 ), e );
131         }
132     }
133 
134 
135     /**
136      * {@inheritDoc}
137      */
138     @Override
139     public int getDelay()
140     {
141         return gracefulDisconnectResponse.getDelay();
142     }
143 
144 
145     /**
146      * {@inheritDoc}
147      */
148     @Override
149     public void setDelay( int delay )
150     {
151         gracefulDisconnectResponse.setDelay( delay );
152     }
153 
154 
155     /**
156      * {@inheritDoc}
157      */
158     @Override
159     public int getTimeOffline()
160     {
161         return gracefulDisconnectResponse.getTimeOffline();
162     }
163 
164 
165     /**
166      * {@inheritDoc}
167      */
168     @Override
169     public void setTimeOffline( int timeOffline )
170     {
171         gracefulDisconnectResponse.setTimeOffline( timeOffline );
172     }
173 
174 
175     /**
176      * {@inheritDoc}
177      */
178     @Override
179     public Referral getReplicatedContexts()
180     {
181         return gracefulDisconnectResponse.getReplicatedContexts();
182     }
183     
184     
185     /**
186      * {@inheritDoc}
187      */
188     @Override
189     public void addReplicatedContexts( String replicatedContext )
190     {
191         gracefulDisconnectResponse.getReplicatedContexts().addLdapUrl( replicatedContext );
192     }
193 
194 
195     /**
196      * Compute the GracefulDisconnect length 
197      * <pre>
198      * 0x30 L1 
199      *   | 
200      *   +--> [ 0x02 0x0(1-4) [0..720] ] 
201      *   +--> [ 0x80 0x0(1-3) [0..86400] ] 
202      *   +--> [ 0x30 L2 
203      *           | 
204      *           +--> (0x04 L3 value) + ]
205      * </pre>
206      */
207     /* no qualifier */ int computeLengthInternal()
208     {
209         gracefulDisconnectSequenceLength = 0;
210 
211         if ( gracefulDisconnectResponse.getTimeOffline() != 0 )
212         {
213             gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getTimeOffline() );
214         }
215 
216         if ( gracefulDisconnectResponse.getDelay() != 0 )
217         {
218             gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getDelay() );
219         }
220 
221         if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null )
222             && ( !gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().isEmpty() ) )
223         {
224             replicatedContextsLength = 0;
225             
226             ldapUrlBytes = new ArrayList<>( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() );
227 
228             // We may have more than one reference.
229             for ( String replicatedContext : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() )
230             {
231                 byte[] bytes = Strings.getBytesUtf8( replicatedContext );
232                 ldapUrlBytes.add( bytes );
233                 int ldapUrlLength = bytes.length;
234                 replicatedContextsLength += 1 + TLV.getNbBytes( ldapUrlLength ) + ldapUrlLength;
235             }
236 
237             gracefulDisconnectSequenceLength += 1 + TLV.getNbBytes( replicatedContextsLength )
238                 + replicatedContextsLength;
239         }
240 
241         return 1 + TLV.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength;
242     }
243 
244 
245     /**
246      * Encodes the gracefulDisconnect extended operation.
247      * 
248      * @return A ByteBuffer that contains the encoded PDU
249      * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
250      */
251     /* no qualifier */ ByteBuffer encodeInternal() throws EncoderException
252     {
253         // Allocate the bytes buffer.
254         ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
255 
256 
257         bb.put( UniversalTag.SEQUENCE.getValue() );
258         bb.put( TLV.getBytes( gracefulDisconnectSequenceLength ) );
259 
260         if ( gracefulDisconnectResponse.getTimeOffline() != 0 )
261         {
262             BerValue.encode( bb, gracefulDisconnectResponse.getTimeOffline() );
263         }
264 
265         if ( gracefulDisconnectResponse.getDelay() != 0 )
266         {
267             bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG );
268             bb.put( ( byte ) TLV.getNbBytes( gracefulDisconnectResponse.getDelay() ) );
269             bb.put( BerValue.getBytes( gracefulDisconnectResponse.getDelay() ) );
270         }
271 
272         if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null )
273             && ( !gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().isEmpty() ) )
274         {
275             bb.put( UniversalTag.SEQUENCE.getValue() );
276             bb.put( TLV.getBytes( replicatedContextsLength ) );
277 
278             // We may have more than one reference.
279             for ( byte[] replicatedContext : ldapUrlBytes )
280             {
281                 BerValue.encode( bb, replicatedContext );
282             }
283         }
284 
285         return bb;
286     }
287 
288 
289     /**
290      * Return a string representation of the graceful disconnect
291      */
292     @Override
293     public String toString()
294     {
295         StringBuilder sb = new StringBuilder();
296 
297         sb.append( "Graceful Disconnect extended operation" );
298         sb.append( "    TimeOffline : " ).append( gracefulDisconnectResponse.getTimeOffline() ).append( '\n' );
299         sb.append( "    Delay : " ).append( gracefulDisconnectResponse.getDelay() ).append( '\n' );
300 
301         if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) 
302             && ( !gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().isEmpty() ) )
303         {
304             sb.append( "    Replicated contexts :" );
305 
306             // We may have more than one reference.
307             for ( String url : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() )
308             {
309                 sb.append( "\n        " ).append( url );
310             }
311         }
312 
313         return sb.toString();
314     }
315 }