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.i18n.I18n;
034 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
035 import org.apache.directory.shared.ldap.name.DN;
036 import org.apache.directory.shared.ldap.util.LdapURL;
037 import org.apache.directory.shared.ldap.util.StringTools;
038
039
040 /**
041 * A ldapObject to store the LdapResult
042 *
043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044 * @version $Rev: 921600 $, $Date: 2010-03-10 23:37:30 +0100 (Mer, 10 mar 2010) $,
045 */
046 public class LdapResultCodec extends AbstractAsn1Object
047 {
048 // ~ Instance fields
049 // ----------------------------------------------------------------------------
050
051 /**
052 * The result code. The different values are :
053 *
054 * success (0),
055 * operationsError (1),
056 * protocolError (2),
057 * timeLimitExceeded (3),
058 * sizeLimitExceeded (4),
059 * compareFalse (5),
060 * compareTrue (6),
061 * authMethodNotSupported (7),
062 * strongAuthRequired (8),
063 * -- 9 reserved --
064 * referral (10),
065 * adminLimitExceeded (11),
066 * unavailableCriticalExtension (12),
067 * confidentialityRequired (13),
068 * saslBindInProgress (14),
069 * noSuchAttribute (16),
070 * undefinedAttributeType (17),
071 * inappropriateMatching (18),
072 * constraintViolation (19),
073 * attributeOrValueExists (20),
074 * invalidAttributeSyntax (21),
075 * -- 22-31 unused --
076 * noSuchObject (32),
077 * aliasProblem (33),
078 * invalidDNSyntax (34),
079 * -- 35 reserved for undefined isLeaf --
080 * aliasDereferencingProblem (36),
081 * -- 37-47 unused --
082 * inappropriateAuthentication (48),
083 * invalidCredentials (49),
084 * insufficientAccessRights (50),
085 * busy (51),
086 * unavailable (52),
087 * unwillingToPerform (53),
088 * loopDetect (54),
089 * -- 55-63 unused --
090 * namingViolation (64),
091 * objectClassViolation (65),
092 * notAllowedOnNonLeaf (66),
093 * notAllowedOnRDN (67),
094 * entryAlreadyExists (68),
095 * objectClassModsProhibited (69),
096 * -- 70 reserved for CLDAP --
097 * affectsMultipleDSAs (71), -- new
098 * -- 72-79 unused --
099 * other (80),
100 * ...
101 * }
102 */
103 private ResultCodeEnum resultCode;
104
105 /** The DN that is matched by the Bind */
106 private DN matchedDN;
107
108 /** Temporary storage of the byte[] representing the matchedDN */
109 private byte[] matchedDNBytes;
110
111 /** The error message */
112 private String errorMessage;
113
114 /** Temporary storage for message bytes */
115 private byte[] errorMessageBytes;
116
117 /** The referrals, if any. This is an optional element */
118 private List<LdapURL> referrals;
119
120 /** The inner size of the referrals sequence */
121 private int referralsLength;
122
123
124 // ~ Constructors
125 // -------------------------------------------------------------------------------
126
127 /**
128 * Creates a new LdapResult object.
129 */
130 public LdapResultCodec()
131 {
132 super();
133 }
134
135
136 // ~ Methods
137 // ------------------------------------------------------------------------------------
138
139 /**
140 * Initialize the referrals list
141 */
142 public void initReferrals()
143 {
144 referrals = new ArrayList<LdapURL>();
145 }
146
147 /**
148 * Get the error message
149 *
150 * @return Returns the errorMessage.
151 */
152 public String getErrorMessage()
153 {
154 return errorMessage;
155 }
156
157
158 /**
159 * Set the error message
160 *
161 * @param errorMessage The errorMessage to set.
162 */
163 public void setErrorMessage( String errorMessage )
164 {
165 this.errorMessage = errorMessage;
166 }
167
168
169 /**
170 * Get the matched DN
171 *
172 * @return Returns the matchedDN.
173 */
174 public String getMatchedDN()
175 {
176 return ( ( matchedDN == null ) ? "" : matchedDN.getNormName() );
177 }
178
179
180 /**
181 * Set the Matched DN
182 *
183 * @param matchedDN The matchedDN to set.
184 */
185 public void setMatchedDN( DN matchedDN )
186 {
187 this.matchedDN = matchedDN;
188 }
189
190
191 /**
192 * Get the referrals
193 *
194 * @return Returns the referrals.
195 */
196 public List<LdapURL> getReferrals()
197 {
198 return referrals;
199 }
200
201
202 /**
203 * Add a referral
204 *
205 * @param referral The referral to add.
206 */
207 public void addReferral( LdapURL referral )
208 {
209 referrals.add( referral );
210 }
211
212
213 /**
214 * Get the result code
215 *
216 * @return Returns the resultCode.
217 */
218 public ResultCodeEnum getResultCode()
219 {
220 return resultCode;
221 }
222
223
224 /**
225 * Set the result code
226 *
227 * @param resultCode The resultCode to set.
228 */
229 public void setResultCode( ResultCodeEnum resultCode )
230 {
231 this.resultCode = resultCode;
232 }
233
234
235 /**
236 * Compute the LdapResult length
237 *
238 * LdapResult :
239 * 0x0A 01 resultCode (0..80)
240 * 0x04 L1 matchedDN (L1 = Length(matchedDN))
241 * 0x04 L2 errorMessage (L2 = Length(errorMessage))
242 * [0x83 L3] referrals
243 * |
244 * +--> 0x04 L4 referral
245 * +--> 0x04 L5 referral
246 * +--> ...
247 * +--> 0x04 Li referral
248 * +--> ...
249 * +--> 0x04 Ln referral
250 *
251 * L1 = Length(matchedDN)
252 * L2 = Length(errorMessage)
253 * L3 = n*Length(0x04) + sum(Length(L4) .. Length(Ln)) + sum(L4..Ln)
254 * L4..n = Length(0x04) + Length(Li) + Li
255 * Length(LdapResult) = Length(0x0x0A) +
256 * Length(0x01) + 1 + Length(0x04) + Length(L1) + L1 + Length(0x04) +
257 * Length(L2) + L2 + Length(0x83) + Length(L3) + L3
258 */
259 public int computeLength()
260 {
261 int ldapResultLength = 0;
262
263 // The result code : always 3 bytes
264 ldapResultLength = 1 + 1 + 1;
265
266 // The matchedDN length
267 if ( matchedDN == null )
268 {
269 ldapResultLength += 1 + 1;
270 }
271 else
272 {
273 matchedDNBytes = StringTools.getBytesUtf8( StringTools.trimLeft( matchedDN.getName() ) );
274 ldapResultLength += 1 + TLV.getNbBytes( matchedDNBytes.length ) + matchedDNBytes.length;
275 }
276
277 // The errorMessage length
278 errorMessageBytes = StringTools.getBytesUtf8( errorMessage );
279 ldapResultLength += 1 + TLV.getNbBytes( errorMessageBytes.length ) + errorMessageBytes.length;
280
281 if ( ( referrals != null ) && ( referrals.size() != 0 ) )
282 {
283 referralsLength = 0;
284
285 // Each referral
286 for ( LdapURL referral:referrals )
287 {
288 referralsLength += 1 + TLV.getNbBytes( referral.getNbBytes() ) + referral.getNbBytes();
289 }
290
291 // The referrals
292 ldapResultLength += 1 + TLV.getNbBytes( referralsLength ) + referralsLength;
293 }
294
295 return ldapResultLength;
296 }
297
298
299 /**
300 * Encode the LdapResult message to a PDU.
301 *
302 * @param buffer The buffer where to put the PDU
303 * @return The PDU.
304 */
305 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
306 {
307 if ( buffer == null )
308 {
309 throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
310 }
311
312 try
313 {
314 // The result code
315 buffer.put( UniversalTag.ENUMERATED_TAG );
316 buffer.put( ( byte ) 1 );
317 buffer.put( ( byte ) resultCode.getValue() );
318 }
319 catch ( BufferOverflowException boe )
320 {
321 throw new EncoderException( I18n.err( I18n.ERR_04005 ) );
322 }
323
324 // The matchedDN
325 Value.encode( buffer, matchedDNBytes );
326
327 // The error message
328 Value.encode( buffer, errorMessageBytes );
329
330 // The referrals, if any
331 if ( ( referrals != null ) && ( referrals.size() != 0 ) )
332 {
333 // Encode the referrals sequence
334 // The referrals length MUST have been computed before !
335 buffer.put( ( byte ) LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG );
336 buffer.put( TLV.getBytes( referralsLength ) );
337
338 // Each referral
339 for ( LdapURL referral:referrals )
340 {
341 // Encode the current referral
342 Value.encode( buffer, referral.getBytesReference() );
343 }
344 }
345
346 return buffer;
347 }
348
349
350 /**
351 * Get a String representation of a LdapResult
352 *
353 * @return A LdapResult String
354 */
355 public String toString()
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 }