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;
021
022
023 import java.nio.BufferOverflowException;
024 import java.nio.ByteBuffer;
025 import java.util.ArrayList;
026 import java.util.List;
027
028 import org.apache.directory.shared.asn1.AbstractAsn1Object;
029 import org.apache.directory.shared.asn1.ber.tlv.TLV;
030 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
031 import org.apache.directory.shared.asn1.ber.tlv.Value;
032 import org.apache.directory.shared.asn1.codec.EncoderException;
033 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
034 import org.apache.directory.shared.ldap.name.LdapDN;
035 import org.apache.directory.shared.ldap.util.LdapURL;
036 import org.apache.directory.shared.ldap.util.StringTools;
037
038
039 /**
040 * A ldapObject to store the LdapResult
041 *
042 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
043 * @version $Rev: 764131 $, $Date: 2009-04-11 03:03:00 +0200 (Sam, 11 avr 2009) $,
044 */
045 public class LdapResultCodec extends AbstractAsn1Object
046 {
047 // ~ Instance fields
048 // ----------------------------------------------------------------------------
049
050 /**
051 * The result code. The different values are :
052 *
053 * success (0),
054 * operationsError (1),
055 * protocolError (2),
056 * timeLimitExceeded (3),
057 * sizeLimitExceeded (4),
058 * compareFalse (5),
059 * compareTrue (6),
060 * authMethodNotSupported (7),
061 * strongAuthRequired (8),
062 * -- 9 reserved --
063 * referral (10),
064 * adminLimitExceeded (11),
065 * unavailableCriticalExtension (12),
066 * confidentialityRequired (13),
067 * saslBindInProgress (14),
068 * noSuchAttribute (16),
069 * undefinedAttributeType (17),
070 * inappropriateMatching (18),
071 * constraintViolation (19),
072 * attributeOrValueExists (20),
073 * invalidAttributeSyntax (21),
074 * -- 22-31 unused --
075 * noSuchObject (32),
076 * aliasProblem (33),
077 * invalidDNSyntax (34),
078 * -- 35 reserved for undefined isLeaf --
079 * aliasDereferencingProblem (36),
080 * -- 37-47 unused --
081 * inappropriateAuthentication (48),
082 * invalidCredentials (49),
083 * insufficientAccessRights (50),
084 * busy (51),
085 * unavailable (52),
086 * unwillingToPerform (53),
087 * loopDetect (54),
088 * -- 55-63 unused --
089 * namingViolation (64),
090 * objectClassViolation (65),
091 * notAllowedOnNonLeaf (66),
092 * notAllowedOnRDN (67),
093 * entryAlreadyExists (68),
094 * objectClassModsProhibited (69),
095 * -- 70 reserved for CLDAP --
096 * affectsMultipleDSAs (71), -- new
097 * -- 72-79 unused --
098 * other (80),
099 * ...
100 * }
101 */
102 private ResultCodeEnum resultCode;
103
104 /** The DN that is matched by the Bind */
105 private LdapDN matchedDN;
106
107 /** Temporary storage of the byte[] representing the matchedDN */
108 private byte[] matchedDNBytes;
109
110 /** The error message */
111 private String errorMessage;
112
113 /** Temporary storage for message bytes */
114 private byte[] errorMessageBytes;
115
116 /** The referrals, if any. This is an optional element */
117 private List<LdapURL> referrals;
118
119 /** The inner size of the referrals sequence */
120 private int referralsLength;
121
122
123 // ~ Constructors
124 // -------------------------------------------------------------------------------
125
126 /**
127 * Creates a new LdapResult object.
128 */
129 public LdapResultCodec()
130 {
131 super();
132 }
133
134
135 // ~ Methods
136 // ------------------------------------------------------------------------------------
137
138 /**
139 * Initialize the referrals list
140 */
141 public void initReferrals()
142 {
143 referrals = new ArrayList<LdapURL>();
144 }
145
146 /**
147 * Get the error message
148 *
149 * @return Returns the errorMessage.
150 */
151 public String getErrorMessage()
152 {
153 return errorMessage;
154 }
155
156
157 /**
158 * Set the error message
159 *
160 * @param errorMessage The errorMessage to set.
161 */
162 public void setErrorMessage( String errorMessage )
163 {
164 this.errorMessage = errorMessage;
165 }
166
167
168 /**
169 * Get the matched DN
170 *
171 * @return Returns the matchedDN.
172 */
173 public String getMatchedDN()
174 {
175 return ( ( matchedDN == null ) ? "" : matchedDN.toString() );
176 }
177
178
179 /**
180 * Set the Matched DN
181 *
182 * @param matchedDN The matchedDN to set.
183 */
184 public void setMatchedDN( LdapDN matchedDN )
185 {
186 this.matchedDN = matchedDN;
187 }
188
189
190 /**
191 * Get the referrals
192 *
193 * @return Returns the referrals.
194 */
195 public List<LdapURL> getReferrals()
196 {
197 return referrals;
198 }
199
200
201 /**
202 * Add a referral
203 *
204 * @param referral The referral to add.
205 */
206 public void addReferral( LdapURL referral )
207 {
208 referrals.add( referral );
209 }
210
211
212 /**
213 * Get the result code
214 *
215 * @return Returns the resultCode.
216 */
217 public ResultCodeEnum getResultCode()
218 {
219 return resultCode;
220 }
221
222
223 /**
224 * Set the result code
225 *
226 * @param resultCode The resultCode to set.
227 */
228 public void setResultCode( ResultCodeEnum resultCode )
229 {
230 this.resultCode = resultCode;
231 }
232
233
234 /**
235 * Compute the LdapResult length
236 *
237 * LdapResult :
238 * 0x0A 01 resultCode (0..80)
239 * 0x04 L1 matchedDN (L1 = Length(matchedDN))
240 * 0x04 L2 errorMessage (L2 = Length(errorMessage))
241 * [0x83 L3] referrals
242 * |
243 * +--> 0x04 L4 referral
244 * +--> 0x04 L5 referral
245 * +--> ...
246 * +--> 0x04 Li referral
247 * +--> ...
248 * +--> 0x04 Ln referral
249 *
250 * L1 = Length(matchedDN)
251 * L2 = Length(errorMessage)
252 * L3 = n*Length(0x04) + sum(Length(L4) .. Length(Ln)) + sum(L4..Ln)
253 * L4..n = Length(0x04) + Length(Li) + Li
254 * Length(LdapResult) = Length(0x0x0A) +
255 * Length(0x01) + 1 + Length(0x04) + Length(L1) + L1 + Length(0x04) +
256 * Length(L2) + L2 + Length(0x83) + Length(L3) + L3
257 */
258 public int computeLength()
259 {
260 int ldapResultLength = 0;
261
262 // The result code : always 3 bytes
263 ldapResultLength = 1 + 1 + 1;
264
265 // The matchedDN length
266 if ( matchedDN == null )
267 {
268 ldapResultLength += 1 + 1;
269 }
270 else
271 {
272 matchedDNBytes = StringTools.getBytesUtf8( StringTools.trimLeft( matchedDN.getUpName() ) );
273 ldapResultLength += 1 + TLV.getNbBytes( matchedDNBytes.length ) + matchedDNBytes.length;
274 }
275
276 // The errorMessage length
277 errorMessageBytes = StringTools.getBytesUtf8( errorMessage );
278 ldapResultLength += 1 + TLV.getNbBytes( errorMessageBytes.length ) + errorMessageBytes.length;
279
280 if ( ( referrals != null ) && ( referrals.size() != 0 ) )
281 {
282 referralsLength = 0;
283
284 // Each referral
285 for ( LdapURL referral:referrals )
286 {
287 referralsLength += 1 + TLV.getNbBytes( referral.getNbBytes() ) + referral.getNbBytes();
288 }
289
290 // The referrals
291 ldapResultLength += 1 + TLV.getNbBytes( referralsLength ) + referralsLength;
292 }
293
294 return ldapResultLength;
295 }
296
297
298 /**
299 * Encode the LdapResult message to a PDU.
300 *
301 * @param buffer The buffer where to put the PDU
302 * @return The PDU.
303 */
304 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
305 {
306 if ( buffer == null )
307 {
308 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
309 }
310
311 try
312 {
313 // The result code
314 buffer.put( UniversalTag.ENUMERATED_TAG );
315 buffer.put( ( byte ) 1 );
316 buffer.put( ( byte ) resultCode.getValue() );
317 }
318 catch ( BufferOverflowException boe )
319 {
320 throw new EncoderException( "The PDU buffer size is too small !" );
321 }
322
323 // The matchedDN
324 Value.encode( buffer, matchedDNBytes );
325
326 // The error message
327 Value.encode( buffer, errorMessageBytes );
328
329 // The referrals, if any
330 if ( ( referrals != null ) && ( referrals.size() != 0 ) )
331 {
332 // Encode the referrals sequence
333 // The referrals length MUST have been computed before !
334 buffer.put( ( byte ) LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG );
335 buffer.put( TLV.getBytes( referralsLength ) );
336
337 // Each referral
338 for ( LdapURL referral:referrals )
339 {
340 // Encode the current referral
341 Value.encode( buffer, referral.getBytesReference() );
342 }
343 }
344
345 return buffer;
346 }
347
348
349 /**
350 * Get a String representation of a LdapResult
351 *
352 * @return A LdapResult String
353 */
354 public String toString()
355 {
356
357 StringBuffer sb = new StringBuffer();
358
359 sb.append( " Ldap Result\n" );
360 sb.append( " Result code : (" ).append( resultCode ).append( ')' );
361
362 switch ( resultCode )
363 {
364
365 case SUCCESS:
366 sb.append( " success\n" );
367 break;
368
369 case OPERATIONS_ERROR:
370 sb.append( " operationsError\n" );
371 break;
372
373 case PROTOCOL_ERROR:
374 sb.append( " protocolError\n" );
375 break;
376
377 case TIME_LIMIT_EXCEEDED:
378 sb.append( " timeLimitExceeded\n" );
379 break;
380
381 case SIZE_LIMIT_EXCEEDED:
382 sb.append( " sizeLimitExceeded\n" );
383 break;
384
385 case COMPARE_FALSE:
386 sb.append( " compareFalse\n" );
387 break;
388
389 case COMPARE_TRUE:
390 sb.append( " compareTrue\n" );
391 break;
392
393 case AUTH_METHOD_NOT_SUPPORTED:
394 sb.append( " authMethodNotSupported\n" );
395 break;
396
397 case STRONG_AUTH_REQUIRED:
398 sb.append( " strongAuthRequired\n" );
399 break;
400
401 case REFERRAL:
402 sb.append( " referral -- new\n" );
403 break;
404
405 case ADMIN_LIMIT_EXCEEDED:
406 sb.append( " adminLimitExceeded -- new\n" );
407 break;
408
409 case UNAVAILABLE_CRITICAL_EXTENSION:
410 sb.append( " unavailableCriticalExtension -- new\n" );
411 break;
412
413 case CONFIDENTIALITY_REQUIRED:
414 sb.append( " confidentialityRequired -- new\n" );
415 break;
416
417 case SASL_BIND_IN_PROGRESS:
418 sb.append( " saslBindInProgress -- new\n" );
419 break;
420
421 case NO_SUCH_ATTRIBUTE:
422 sb.append( " noSuchAttribute\n" );
423 break;
424
425 case UNDEFINED_ATTRIBUTE_TYPE:
426 sb.append( " undefinedAttributeType\n" );
427 break;
428
429 case INAPPROPRIATE_MATCHING:
430 sb.append( " inappropriateMatching\n" );
431 break;
432
433 case CONSTRAINT_VIOLATION:
434 sb.append( " constraintViolation\n" );
435 break;
436
437 case ATTRIBUTE_OR_VALUE_EXISTS:
438 sb.append( " attributeOrValueExists\n" );
439 break;
440
441 case INVALID_ATTRIBUTE_SYNTAX:
442 sb.append( " invalidAttributeSyntax\n" );
443 break;
444
445 case NO_SUCH_OBJECT:
446 sb.append( " noSuchObject\n" );
447 break;
448
449 case ALIAS_PROBLEM:
450 sb.append( " aliasProblem\n" );
451 break;
452
453 case INVALID_DN_SYNTAX:
454 sb.append( " invalidDNSyntax\n" );
455 break;
456
457 case ALIAS_DEREFERENCING_PROBLEM:
458 sb.append( " aliasDereferencingProblem\n" );
459 break;
460
461 case INAPPROPRIATE_AUTHENTICATION:
462 sb.append( " inappropriateAuthentication\n" );
463 break;
464
465 case INVALID_CREDENTIALS:
466 sb.append( " invalidCredentials\n" );
467 break;
468
469 case INSUFFICIENT_ACCESS_RIGHTS:
470 sb.append( " insufficientAccessRights\n" );
471 break;
472
473 case BUSY:
474 sb.append( " busy\n" );
475 break;
476
477 case UNAVAILABLE:
478 sb.append( " unavailable\n" );
479 break;
480
481 case UNWILLING_TO_PERFORM:
482 sb.append( " unwillingToPerform\n" );
483 break;
484
485 case LOOP_DETECT:
486 sb.append( " loopDetect\n" );
487 break;
488
489 case NAMING_VIOLATION:
490 sb.append( " namingViolation\n" );
491 break;
492
493 case OBJECT_CLASS_VIOLATION:
494 sb.append( " objectClassViolation\n" );
495 break;
496
497 case NOT_ALLOWED_ON_NON_LEAF:
498 sb.append( " notAllowedOnNonLeaf\n" );
499 break;
500
501 case NOT_ALLOWED_ON_RDN:
502 sb.append( " notAllowedOnRDN\n" );
503 break;
504
505 case ENTRY_ALREADY_EXISTS:
506 sb.append( " entryAlreadyExists\n" );
507 break;
508
509 case OBJECT_CLASS_MODS_PROHIBITED:
510 sb.append( " objectClassModsProhibited\n" );
511 break;
512
513 case AFFECTS_MULTIPLE_DSAS:
514 sb.append( " affectsMultipleDSAs -- new\n" );
515 break;
516
517 case OTHER:
518 sb.append( " other\n" );
519 break;
520
521 default:
522 switch ( resultCode.getResultCode() )
523 {
524 case 9:
525 sb.append( " -- 9 reserved --\n" );
526 break;
527
528 case 22:
529 case 23:
530 case 24:
531 case 25:
532 case 26:
533 case 27:
534 case 28:
535 case 29:
536 case 30:
537 case 31:
538 sb.append( " -- 22-31 unused --\n" );
539 break;
540
541 case 35 :
542 sb.append( " -- 35 reserved for undefined isLeaf --\n" );
543 break;
544
545 case 37:
546 case 38:
547 case 39:
548 case 40:
549 case 41:
550 case 42:
551 case 43:
552 case 44:
553 case 45:
554 case 46:
555 case 47:
556 sb.append( " -- 37-47 unused --\n" );
557 break;
558
559 case 55:
560 case 56:
561 case 57:
562 case 58:
563 case 59:
564 case 60:
565 case 61:
566 case 62:
567 case 63:
568 sb.append( " -- 55-63 unused --\n" );
569 break;
570
571 case 70:
572 sb.append( " -- 70 reserved for CLDAP --\n" );
573 break;
574
575 case 72:
576 case 73:
577 case 74:
578 case 75:
579 case 76:
580 case 77:
581 case 78:
582 case 79:
583 sb.append( " -- 72-79 unused --\n" );
584 break;
585
586 case 81:
587 case 82:
588 case 83:
589 case 84:
590 case 85:
591 case 86:
592 case 87:
593 case 88:
594 case 89:
595 case 90:
596 sb.append( " -- 81-90 reserved for APIs --" );
597 break;
598
599 default :
600 sb.append( "Unknown error code : " ).append( resultCode );
601 break;
602 }
603
604 break;
605 }
606
607 sb.append( " Matched DN : '" ).append( matchedDN == null ? "": matchedDN.toString() ).append( "'\n" );
608 sb.append( " Error message : '" ).append( errorMessage == null ? "" : errorMessage ).append( "'\n" );
609
610
611 if ( ( referrals != null ) && ( referrals.size() != 0 ) )
612 {
613 sb.append( " Referrals :\n" );
614 int i = 0;
615
616 for ( LdapURL referral:referrals )
617 {
618
619 sb.append( " Referral[" ).
620 append( i++ ).
621 append( "] :" ).
622 append( referral ).
623 append( '\n' );
624 }
625 }
626
627 return sb.toString();
628 }
629 }