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.controls.replication.syncInfoValue;
021
022 import java.nio.ByteBuffer;
023 import java.util.ArrayList;
024 import java.util.List;
025
026 import org.apache.directory.shared.asn1.AbstractAsn1Object;
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.message.control.replication.SynchronizationInfoEnum;
032 import org.apache.directory.shared.ldap.util.StringTools;
033
034 /**
035 * A syncInfoValue object, as defined in RFC 4533
036 *
037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038 * @version $Rev:$, $Date:
039 */
040 public class SyncInfoValueControlCodec extends AbstractAsn1Object
041 {
042 /** The kind of syncInfoValue we are dealing with */
043 private SynchronizationInfoEnum type;
044
045 /** The cookie */
046 private byte[] cookie;
047
048 /** The refreshDone flag if we are dealing with refreshXXX syncInfo. Default to true */
049 private boolean refreshDone = true;
050
051 /** The refreshDeletes flag if we are dealing with syncIdSet syncInfo. Defaluts to false */
052 private boolean refreshDeletes = false;
053
054 /** The list of UUIDs if we are dealing with syncIdSet syncInfo */
055 private List<byte[]> syncUUIDs;
056
057 /** The syncUUIDs cumulative lentgh */
058 private int syncUUIDsLength;
059
060
061 /**
062 * The constructor for this codec.
063 * @param type The kind of syncInfo we will store. Can be newCookie,
064 * refreshPresent, refreshDelete or syncIdSet
065 */
066 public SyncInfoValueControlCodec( SynchronizationInfoEnum type )
067 {
068 this.type = type;
069
070 // Initialize the arrayList if needed
071 if ( type == SynchronizationInfoEnum.SYNC_ID_SET )
072 {
073 syncUUIDs = new ArrayList<byte[]>();
074 }
075 }
076
077
078 /** The global length for this control */
079 private int syncInfoValueLength;
080
081 /**
082 * Get the control type.
083 *
084 * @return the type : one of newCookie, refreshDelete, refreshPresent or syncIdSet
085 */
086 public SynchronizationInfoEnum getType()
087 {
088 return type;
089 }
090
091
092 /**
093 * @param syncMode the syncMode to set
094 */
095 public void setType( SynchronizationInfoEnum type )
096 {
097 this.type = type;
098 }
099
100
101 /**
102 * @return the cookie
103 */
104 public byte[] getCookie()
105 {
106 return cookie;
107 }
108
109
110 /**
111 * @param cookie the cookie to set
112 */
113 public void setCookie( byte[] cookie )
114 {
115 this.cookie = cookie;
116 }
117
118
119 /**
120 * @return the refreshDone
121 */
122 public boolean isRefreshDone()
123 {
124 return refreshDone;
125 }
126
127
128 /**
129 * @param refreshDone the refreshDone to set
130 */
131 public void setRefreshDone( boolean refreshDone )
132 {
133 this.refreshDone = refreshDone;
134 }
135
136
137 /**
138 * @return the refreshDeletes
139 */
140 public boolean isRefreshDeletes()
141 {
142 return refreshDeletes;
143 }
144
145
146 /**
147 * @param refreshDeletes the refreshDeletes to set
148 */
149 public void setRefreshDeletes( boolean refreshDeletes )
150 {
151 this.refreshDeletes = refreshDeletes;
152 }
153
154
155 /**
156 * @return the syncUUIDs
157 */
158 public List<byte[]> getSyncUUIDs()
159 {
160 return syncUUIDs;
161 }
162
163
164 /**
165 * @param syncUUIDs the syncUUIDs to set
166 */
167 public void setSyncUUIDs( List<byte[]> syncUUIDs )
168 {
169 this.syncUUIDs = syncUUIDs;
170 }
171
172
173 /**
174 * Compute the SyncInfoValue length.
175 *
176 * SyncInfoValue :
177 *
178 * 0xA0 L1 abcd // newCookie
179 * 0xA1 L2 // refreshDelete
180 * |
181 * [+--> 0x04 L3 abcd] // cookie
182 * [+--> 0x01 0x01 (0x00|0xFF) // refreshDone
183 * 0xA2 L4 // refreshPresent
184 * |
185 * [+--> 0x04 L5 abcd] // cookie
186 * [+--> 0x01 0x01 (0x00|0xFF) // refreshDone
187 * 0xA3 L6 // syncIdSet
188 * |
189 * [+--> 0x04 L7 abcd] // cookie
190 * [+--> 0x01 0x01 (0x00|0xFF) // refreshDeletes
191 * +--> 0x31 L8 // SET OF syncUUIDs
192 * |
193 * [+--> 0x04 L9 abcd] // syncUUID public static final int AND_FILTER_TAG = 0xA0;
194
195 public static final int OR_FILTER_TAG = 0xA1;
196
197 public static final int NOT_FILTER_TAG = 0xA2;
198
199 public static final int BIND_REQUEST_SASL_TAG = 0xA3;
200
201 */
202 public int computeLength()
203 {
204 // The mode length
205 syncInfoValueLength = 0;
206
207 switch ( type )
208 {
209 case NEW_COOKIE :
210 if ( cookie != null )
211 {
212 syncInfoValueLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
213 }
214 else
215 {
216 syncInfoValueLength = 1 + 1;
217 }
218
219 return syncInfoValueLength;
220
221 case REFRESH_DELETE :
222 case REFRESH_PRESENT :
223 if ( cookie != null )
224 {
225 syncInfoValueLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
226 }
227
228 // The refreshDone flag
229 syncInfoValueLength += 1 + 1 + 1;
230 break;
231
232 case SYNC_ID_SET :
233 if ( cookie != null )
234 {
235 syncInfoValueLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
236 }
237
238 // The refreshDeletes flag
239 syncInfoValueLength += 1 + 1 + 1;
240
241 // The syncUUIDs if any
242 syncUUIDsLength = 0;
243
244 if ( syncUUIDs.size() != 0 )
245 {
246 for ( byte[] syncUUID:syncUUIDs )
247 {
248 int uuidLength = 1 + TLV.getNbBytes( syncUUID.length ) + syncUUID.length;
249
250 syncUUIDsLength += 1 + TLV.getNbBytes( uuidLength ) + uuidLength;
251 }
252
253 // Add the tag and compute the length
254 syncUUIDsLength += 1 + TLV.getNbBytes( syncUUIDsLength ) + syncUUIDsLength;
255 }
256
257 syncInfoValueLength += 1 + TLV.getNbBytes( syncUUIDsLength ) + syncUUIDsLength;
258
259 break;
260 }
261
262 return 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
263 }
264
265
266 /**
267 * Encode the SyncInfoValue control
268 *
269 * @param buffer The encoded sink
270 * @return A ByteBuffer that contains the encoded PDU
271 * @throws EncoderException If anything goes wrong.
272 */
273 public ByteBuffer encode( ByteBuffer bb ) throws EncoderException
274 {
275 // Allocate the bytes buffer.
276 if ( bb == null )
277 {
278 bb = ByteBuffer.allocate( computeLength() );
279 }
280
281 switch ( type )
282 {
283 case NEW_COOKIE :
284 // The first case : newCookie
285 bb.put( (byte)SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
286
287 // As the OCTET_STRING is absorbed by the Application tag,
288 // we have to store the L and V separately
289 if ( ( cookie == null ) || ( cookie.length == 0 ) )
290 {
291 bb.put( ( byte ) 0 );
292 }
293 else
294 {
295 bb.put( TLV.getBytes( cookie.length ) );
296 bb.put( cookie );
297 }
298
299 break;
300
301 case REFRESH_DELETE :
302 // The second case : refreshDelete
303 bb.put( (byte)SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
304 bb.put( TLV.getBytes( syncInfoValueLength ) );
305
306 // The cookie, if any
307 if ( cookie != null )
308 {
309 Value.encode( bb, cookie );
310 }
311
312 // The refreshDone flag
313 Value.encode( bb, refreshDone );
314 break;
315
316 case REFRESH_PRESENT :
317 // The third case : refreshPresent
318 bb.put( (byte)SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
319 bb.put( TLV.getBytes( syncInfoValueLength ) );
320
321 // The cookie, if any
322 if ( cookie != null )
323 {
324 Value.encode( bb, cookie );
325 }
326
327 // The refreshDone flag
328 Value.encode( bb, refreshDone );
329 break;
330
331 case SYNC_ID_SET :
332 // The last case : syncIdSet
333 bb.put( (byte)SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
334 bb.put( TLV.getBytes( syncInfoValueLength ) );
335
336 // The cookie, if any
337 if ( cookie != null )
338 {
339 Value.encode( bb, cookie );
340 }
341
342 // The refreshDeletes flag
343 Value.encode( bb, refreshDeletes );
344
345 // The syncUUIDs
346 bb.put( UniversalTag.SET_TAG );
347 bb.put( TLV.getBytes( syncUUIDsLength ) );
348
349 // Loop on the UUIDs if any
350 if ( syncUUIDs.size() != 0 )
351 {
352 for ( byte[] syncUUID:syncUUIDs )
353 {
354 Value.encode( bb , syncUUID );
355 }
356 }
357 }
358
359 return bb;
360 }
361
362
363 /**
364 * @see Object#toString()
365 */
366 public String toString()
367 {
368 StringBuilder sb = new StringBuilder();
369
370 sb.append( " SyncInfoValue control :\n" );
371
372 switch ( type )
373 {
374 case NEW_COOKIE :
375 sb.append( " newCookie : '" ).
376 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
377 break;
378
379 case REFRESH_DELETE :
380 sb.append( " refreshDelete : \n" );
381
382 if ( cookie != null )
383 {
384 sb.append( " cookie : '" ).
385 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
386 }
387
388 sb.append( " refreshDone : " ).append( refreshDone ).append( '\n' );
389 break;
390
391 case REFRESH_PRESENT :
392 sb.append( " refreshPresent : \n" );
393
394 if ( cookie != null )
395 {
396 sb.append( " cookie : '" ).
397 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
398 }
399
400 sb.append( " refreshDone : " ).append( refreshDone ).append( '\n' );
401 break;
402
403 case SYNC_ID_SET :
404 sb.append( " syncIdSet : \n" );
405
406 if ( cookie != null )
407 {
408 sb.append( " cookie : '" ).
409 append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
410 }
411
412 sb.append( " refreshDeletes : " ).append( refreshDeletes ).append( '\n' );
413 sb.append( " syncUUIDS : " );
414
415 if ( syncUUIDs.size() != 0 )
416 {
417 boolean isFirst = true;
418
419 for ( byte[] syncUUID:syncUUIDs )
420 {
421 if ( isFirst )
422 {
423 isFirst = false;
424 }
425 else
426 {
427 sb.append( ", " );
428 }
429
430 sb.append( syncUUID );
431 }
432
433 sb.append( '\n' );
434 }
435 else
436 {
437 sb.append( "empty\n" );
438 }
439
440 break;
441 }
442
443 return sb.toString();
444 }
445 }