001 /*
002 * Copyright 2008-2015 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.unboundidds.controls;
022
023
024
025 import java.io.Serializable;
026 import java.util.ArrayList;
027
028 import com.unboundid.asn1.ASN1Boolean;
029 import com.unboundid.asn1.ASN1Constants;
030 import com.unboundid.asn1.ASN1Element;
031 import com.unboundid.asn1.ASN1OctetString;
032 import com.unboundid.asn1.ASN1Sequence;
033 import com.unboundid.ldap.sdk.LDAPException;
034 import com.unboundid.ldap.sdk.ResultCode;
035 import com.unboundid.util.NotMutable;
036 import com.unboundid.util.ThreadSafety;
037 import com.unboundid.util.ThreadSafetyLevel;
038
039 import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
040 import static com.unboundid.util.Debug.*;
041 import static com.unboundid.util.StaticUtils.*;
042
043
044
045 /**
046 * <BLOCKQUOTE>
047 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
048 * LDAP SDK for Java. It is not available for use in applications that
049 * include only the Standard Edition of the LDAP SDK, and is not supported for
050 * use in conjunction with non-UnboundID products.
051 * </BLOCKQUOTE>
052 * This class implements a data structure which encapsulates the value of an
053 * intermediate client request value. It may recursively embed intermediate
054 * client request values from downstream clients.
055 * <BR><BR>
056 * See the documentation in the {@link IntermediateClientRequestControl} class
057 * for an example of using the intermediate client request and response
058 * controls.
059 */
060 @NotMutable()
061 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
062 public final class IntermediateClientRequestValue
063 implements Serializable
064 {
065 /**
066 * The BER type for the downstreamRequest element.
067 */
068 private static final byte TYPE_DOWNSTREAM_REQUEST = (byte) 0xA0;
069
070
071
072 /**
073 * The BER type for the downstreamClientAddress element.
074 */
075 private static final byte TYPE_DOWNSTREAM_CLIENT_ADDRESS = (byte) 0x81;
076
077
078
079 /**
080 * The BER type for the downstreamClientSecure element.
081 */
082 private static final byte TYPE_DOWNSTREAM_CLIENT_SECURE = (byte) 0x82;
083
084
085
086 /**
087 * The BER type for the clientIdentity element.
088 */
089 private static final byte TYPE_CLIENT_IDENTITY = (byte) 0x83;
090
091
092
093 /**
094 * The BER type for the clientName element.
095 */
096 private static final byte TYPE_CLIENT_NAME = (byte) 0x84;
097
098
099
100 /**
101 * The BER type for the clientSessionID element.
102 */
103 private static final byte TYPE_CLIENT_SESSION_ID = (byte) 0x85;
104
105
106
107 /**
108 * The BER type for the clientRequestID element.
109 */
110 private static final byte TYPE_CLIENT_REQUEST_ID = (byte) 0x86;
111
112
113
114 /**
115 * The serial version UID for this serializable class.
116 */
117 private static final long serialVersionUID = -794887520013838259L;
118
119
120
121 // Indicates whether the communication with the downstream client is secure.
122 private final Boolean downstreamClientSecure;
123
124 // The downstream request value, if present.
125 private final IntermediateClientRequestValue downstreamRequest;
126
127 // The requested client authorization identity, if present.
128 private final String clientIdentity;
129
130 // The downstream client address, if present.
131 private final String downstreamClientAddress;
132
133 // The client name, which describes the client application, if present.
134 private final String clientName;
135
136 // The client request ID, if present.
137 private final String clientRequestID;
138
139 // The client session ID, if present.
140 private final String clientSessionID;
141
142
143
144 /**
145 * Creates a new intermediate client request value with the provided
146 * information.
147 *
148 * @param downstreamRequest A wrapped intermediate client request from
149 * a downstream client. It may be
150 * {@code null} if there is no downstream
151 * request.
152 * @param downstreamClientAddress The IP address or resolvable name of the
153 * downstream client system. It may be
154 * {@code null} if there is no downstream
155 * client or its address is not available.
156 * @param downstreamClientSecure Indicates whether communication with the
157 * downstream client is secure. It may be
158 * {@code null} if there is no downstream
159 * client or it is not known whether the
160 * communication is secure.
161 * @param clientIdentity The requested client authorization
162 * identity. It may be {@code null} if there
163 * is no requested authorization identity.
164 * @param clientName An identifier string that summarizes the
165 * client application that created this
166 * intermediate client request. It may be
167 * {@code null} if that information is not
168 * available.
169 * @param clientSessionID A string that may be used to identify the
170 * session in the client application. It may
171 * be {@code null} if there is no available
172 * session identifier.
173 * @param clientRequestID A string that may be used to identify the
174 * request in the client application. It may
175 * be {@code null} if there is no available
176 * request identifier.
177 */
178 public IntermediateClientRequestValue(
179 final IntermediateClientRequestValue downstreamRequest,
180 final String downstreamClientAddress,
181 final Boolean downstreamClientSecure, final String clientIdentity,
182 final String clientName, final String clientSessionID,
183 final String clientRequestID)
184 {
185 this.downstreamRequest = downstreamRequest;
186 this.downstreamClientAddress = downstreamClientAddress;
187 this.downstreamClientSecure = downstreamClientSecure;
188 this.clientIdentity = clientIdentity;
189 this.clientName = clientName;
190 this.clientSessionID = clientSessionID;
191 this.clientRequestID = clientRequestID;
192 }
193
194
195
196 /**
197 * Retrieves the wrapped request from a downstream client, if available.
198 *
199 * @return The wrapped request from a downstream client, or {@code null} if
200 * there is none.
201 */
202 public IntermediateClientRequestValue getDownstreamRequest()
203 {
204 return downstreamRequest;
205 }
206
207
208
209 /**
210 * Retrieves the requested client authorization identity, if available.
211 *
212 * @return The requested client authorization identity, or {@code null} if
213 * there is none.
214 */
215 public String getClientIdentity()
216 {
217 return clientIdentity;
218 }
219
220
221
222 /**
223 * Retrieves the IP address or resolvable name of the downstream client
224 * system, if available.
225 *
226 * @return The IP address or resolvable name of the downstream client system,
227 * or {@code null} if there is no downstream client or its address is
228 * not available.
229 */
230 public String getDownstreamClientAddress()
231 {
232 return downstreamClientAddress;
233 }
234
235
236
237 /**
238 * Indicates whether the communication with the communication with the
239 * downstream client is secure (i.e., whether communication between the
240 * client application and the downstream client is safe from interpretation or
241 * undetectable alteration by a third party observer or interceptor).
242 *
243 *
244 * @return {@code Boolean.TRUE} if communication with the downstream client
245 * is secure, {@code Boolean.FALSE} if it is not secure, or
246 * {@code null} if there is no downstream client or it is not known
247 * whether the communication is secure.
248 */
249 public Boolean downstreamClientSecure()
250 {
251 return downstreamClientSecure;
252 }
253
254
255
256 /**
257 * Retrieves a string that identifies the client application that created this
258 * intermediate client request value.
259 *
260 * @return A string that may be used to identify the client application that
261 * created this intermediate client request value.
262 */
263 public String getClientName()
264 {
265 return clientName;
266 }
267
268
269
270 /**
271 * Retrieves a string that may be used to identify the session in the client
272 * application.
273 *
274 * @return A string that may be used to identify the session in the client
275 * application, or {@code null} if there is none.
276 */
277 public String getClientSessionID()
278 {
279 return clientSessionID;
280 }
281
282
283
284 /**
285 * Retrieves a string that may be used to identify the request in the client
286 * application.
287 *
288 * @return A string that may be used to identify the request in the client
289 * application, or {@code null} if there is none.
290 */
291 public String getClientRequestID()
292 {
293 return clientRequestID;
294 }
295
296
297
298 /**
299 * Encodes this intermediate client request value to a form that may be
300 * included in the request control.
301 *
302 * @return An ASN.1 octet string containing the encoded client request value.
303 */
304 public ASN1Sequence encode()
305 {
306 return encode(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
307 }
308
309
310
311 /**
312 * Encodes this intermediate client request value to a form that may be
313 * included in the request control.
314 *
315 * @param type The BER type to use for this element.
316 *
317 * @return An ASN.1 octet string containing the encoded client request value.
318 */
319 private ASN1Sequence encode(final byte type)
320 {
321 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(7);
322
323 if (downstreamRequest != null)
324 {
325 elements.add(downstreamRequest.encode(TYPE_DOWNSTREAM_REQUEST));
326 }
327
328 if (downstreamClientAddress != null)
329 {
330 elements.add(new ASN1OctetString(TYPE_DOWNSTREAM_CLIENT_ADDRESS,
331 downstreamClientAddress));
332 }
333
334 if (downstreamClientSecure != null)
335 {
336 elements.add(new ASN1Boolean(TYPE_DOWNSTREAM_CLIENT_SECURE,
337 downstreamClientSecure));
338 }
339
340 if (clientIdentity != null)
341 {
342 elements.add(new ASN1OctetString(TYPE_CLIENT_IDENTITY, clientIdentity));
343 }
344
345 if (clientName != null)
346 {
347 elements.add(new ASN1OctetString(TYPE_CLIENT_NAME, clientName));
348 }
349
350 if (clientSessionID != null)
351 {
352 elements.add(new ASN1OctetString(TYPE_CLIENT_SESSION_ID,
353 clientSessionID));
354 }
355
356 if (clientRequestID != null)
357 {
358 elements.add(new ASN1OctetString(TYPE_CLIENT_REQUEST_ID,
359 clientRequestID));
360 }
361
362 return new ASN1Sequence(type, elements);
363 }
364
365
366
367 /**
368 * Decodes the provided ASN.1 sequence as an intermediate client request
369 * value.
370 *
371 * @param sequence The sequence to be decoded as an intermediate client
372 * request value.
373 *
374 * @return The decoded intermediate client request value.
375 *
376 * @throws LDAPException If the provided sequence cannot be decoded as an
377 * intermediate client request value.
378 */
379 public static IntermediateClientRequestValue
380 decode(final ASN1Sequence sequence)
381 throws LDAPException
382 {
383 Boolean downstreamClientSecure = null;
384 IntermediateClientRequestValue downstreamRequest = null;
385 String clientIdentity = null;
386 String downstreamClientAddress = null;
387 String clientName = null;
388 String clientRequestID = null;
389 String clientSessionID = null;
390
391 for (final ASN1Element element : sequence.elements())
392 {
393 switch (element.getType())
394 {
395 case TYPE_DOWNSTREAM_REQUEST:
396 try
397 {
398 final ASN1Sequence s = ASN1Sequence.decodeAsSequence(element);
399 downstreamRequest = decode(s);
400 }
401 catch (LDAPException le)
402 {
403 debugException(le);
404 throw new LDAPException(ResultCode.DECODING_ERROR,
405 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get(
406 le.getMessage()), le);
407 }
408 catch (Exception e)
409 {
410 debugException(e);
411 throw new LDAPException(ResultCode.DECODING_ERROR,
412 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_REQUEST.get(
413 String.valueOf(e)), e);
414 }
415 break;
416
417 case TYPE_DOWNSTREAM_CLIENT_ADDRESS:
418 downstreamClientAddress =
419 ASN1OctetString.decodeAsOctetString(element).stringValue();
420 break;
421
422 case TYPE_DOWNSTREAM_CLIENT_SECURE:
423 try
424 {
425 downstreamClientSecure =
426 ASN1Boolean.decodeAsBoolean(element).booleanValue();
427 }
428 catch (Exception e)
429 {
430 debugException(e);
431 throw new LDAPException(ResultCode.DECODING_ERROR,
432 ERR_ICREQ_CANNOT_DECODE_DOWNSTREAM_SECURE.get(
433 String.valueOf(e)), e);
434 }
435 break;
436
437 case TYPE_CLIENT_IDENTITY:
438 clientIdentity =
439 ASN1OctetString.decodeAsOctetString(element).stringValue();
440 break;
441
442 case TYPE_CLIENT_NAME:
443 clientName =
444 ASN1OctetString.decodeAsOctetString(element).stringValue();
445 break;
446
447 case TYPE_CLIENT_SESSION_ID:
448 clientSessionID =
449 ASN1OctetString.decodeAsOctetString(element).stringValue();
450 break;
451
452 case TYPE_CLIENT_REQUEST_ID:
453 clientRequestID =
454 ASN1OctetString.decodeAsOctetString(element).stringValue();
455 break;
456
457 default:
458 throw new LDAPException(ResultCode.DECODING_ERROR,
459 ERR_ICREQ_INVALID_ELEMENT_TYPE.get(toHex(element.getType())));
460 }
461 }
462
463 return new IntermediateClientRequestValue(downstreamRequest,
464 downstreamClientAddress,
465 downstreamClientSecure,
466 clientIdentity, clientName,
467 clientSessionID, clientRequestID);
468 }
469
470
471
472 /**
473 * Generates a hash code for this intermediate client request value.
474 *
475 * @return A hash code for this intermediate client request value.
476 */
477 @Override()
478 public int hashCode()
479 {
480 int hashCode = 0;
481
482 if (downstreamRequest != null)
483 {
484 hashCode += downstreamRequest.hashCode();
485 }
486
487 if (downstreamClientAddress != null)
488 {
489 hashCode += downstreamClientAddress.hashCode();
490 }
491
492 if (downstreamClientSecure != null)
493 {
494 hashCode += downstreamClientSecure.hashCode();
495 }
496
497 if (clientIdentity != null)
498 {
499 hashCode += clientIdentity.hashCode();
500 }
501
502 if (clientName != null)
503 {
504 hashCode += clientName.hashCode();
505 }
506
507 if (clientSessionID != null)
508 {
509 hashCode += clientSessionID.hashCode();
510 }
511
512 if (clientRequestID != null)
513 {
514 hashCode += clientRequestID.hashCode();
515 }
516
517 return hashCode;
518 }
519
520
521
522 /**
523 * Indicates whether the provided object is equal to this intermediate client
524 * request value. It will only be considered equal if the provided object is
525 * also an intermediate client request value with all the same fields.
526 *
527 * @param o The object for which to make the determination.
528 *
529 * @return {@code true} if the provided object is considered equal to this
530 * intermediate client request value, or {@code false} if not.
531 */
532 @Override()
533 public boolean equals(final Object o)
534 {
535 if (o == this)
536 {
537 return true;
538 }
539 else if (o == null)
540 {
541 return false;
542 }
543 else if (! (o instanceof IntermediateClientRequestValue))
544 {
545 return false;
546 }
547
548 final IntermediateClientRequestValue v = (IntermediateClientRequestValue) o;
549
550 if (downstreamRequest == null)
551 {
552 if (v.downstreamRequest != null)
553 {
554 return false;
555 }
556 }
557 else
558 {
559 if (! downstreamRequest.equals(v.downstreamRequest))
560 {
561 return false;
562 }
563 }
564
565 if (downstreamClientAddress == null)
566 {
567 if (v.downstreamClientAddress != null)
568 {
569 return false;
570 }
571 }
572 else
573 {
574 if (! downstreamClientAddress.equals(v.downstreamClientAddress))
575 {
576 return false;
577 }
578 }
579
580 if (downstreamClientSecure == null)
581 {
582 if (v.downstreamClientSecure != null)
583 {
584 return false;
585 }
586 }
587 else
588 {
589 if (! downstreamClientSecure.equals(v.downstreamClientSecure))
590 {
591 return false;
592 }
593 }
594
595 if (clientIdentity == null)
596 {
597 if (v.clientIdentity != null)
598 {
599 return false;
600 }
601 }
602 else
603 {
604 if (! clientIdentity.equals(v.clientIdentity))
605 {
606 return false;
607 }
608 }
609
610 if (clientName == null)
611 {
612 if (v.clientName != null)
613 {
614 return false;
615 }
616 }
617 else
618 {
619 if (! clientName.equals(v.clientName))
620 {
621 return false;
622 }
623 }
624
625 if (clientSessionID == null)
626 {
627 if (v.clientSessionID != null)
628 {
629 return false;
630 }
631 }
632 else
633 {
634 if (! clientSessionID.equals(v.clientSessionID))
635 {
636 return false;
637 }
638 }
639
640 if (clientRequestID == null)
641 {
642 if (v.clientRequestID != null)
643 {
644 return false;
645 }
646 }
647 else
648 {
649 if (! clientRequestID.equals(v.clientRequestID))
650 {
651 return false;
652 }
653 }
654
655 return true;
656 }
657
658
659
660 /**
661 * Retrieves a string representation of this intermediate client request
662 * value.
663 *
664 * @return A string representation of this intermediate client request value.
665 */
666 @Override()
667 public String toString()
668 {
669 final StringBuilder buffer = new StringBuilder();
670 toString(buffer);
671 return buffer.toString();
672 }
673
674
675
676 /**
677 * Appends a string representation of this intermediate client request value
678 * to the provided buffer.
679 *
680 * @param buffer The buffer to which the information is to be appended.
681 */
682 public void toString(final StringBuilder buffer)
683 {
684 buffer.append("IntermediateClientRequestValue(");
685
686 boolean added = false;
687 if (downstreamRequest != null)
688 {
689 buffer.append("downstreamRequest=");
690 downstreamRequest.toString(buffer);
691 added = true;
692 }
693
694 if (clientIdentity != null)
695 {
696 if (added)
697 {
698 buffer.append(", ");
699 }
700 else
701 {
702 added = true;
703 }
704
705 buffer.append("clientIdentity='");
706 buffer.append(clientIdentity);
707 buffer.append('\'');
708 }
709
710 if (downstreamClientAddress != null)
711 {
712 if (added)
713 {
714 buffer.append(", ");
715 }
716 else
717 {
718 added = true;
719 }
720
721 buffer.append("downstreamClientAddress='");
722 buffer.append(downstreamClientAddress);
723 buffer.append('\'');
724 }
725
726 if (downstreamClientSecure != null)
727 {
728 if (added)
729 {
730 buffer.append(", ");
731 }
732 else
733 {
734 added = true;
735 }
736
737 buffer.append("downstreamClientSecure='");
738 buffer.append(downstreamClientSecure);
739 buffer.append('\'');
740 }
741
742 if (clientName != null)
743 {
744 if (added)
745 {
746 buffer.append(", ");
747 }
748 else
749 {
750 added = true;
751 }
752
753 buffer.append("clientName='");
754 buffer.append(clientName);
755 buffer.append('\'');
756 }
757
758 if (clientSessionID != null)
759 {
760 if (added)
761 {
762 buffer.append(", ");
763 }
764 else
765 {
766 added = true;
767 }
768
769 buffer.append("clientSessionID='");
770 buffer.append(clientSessionID);
771 buffer.append('\'');
772 }
773
774 if (clientRequestID != null)
775 {
776 if (added)
777 {
778 buffer.append(", ");
779 }
780 else
781 {
782 added = true;
783 }
784
785 buffer.append("clientRequestID='");
786 buffer.append(clientRequestID);
787 buffer.append('\'');
788 }
789
790 buffer.append(')');
791 }
792 }