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.extensions; 022 023 024 025 import java.util.ArrayList; 026 import java.util.Collection; 027 import java.util.Collections; 028 import java.util.Date; 029 import java.util.Iterator; 030 import java.util.List; 031 032 import com.unboundid.asn1.ASN1Element; 033 import com.unboundid.asn1.ASN1Enumerated; 034 import com.unboundid.asn1.ASN1OctetString; 035 import com.unboundid.asn1.ASN1Sequence; 036 import com.unboundid.ldap.sdk.Control; 037 import com.unboundid.ldap.sdk.ExtendedResult; 038 import com.unboundid.ldap.sdk.LDAPException; 039 import com.unboundid.ldap.sdk.ResultCode; 040 import com.unboundid.util.NotMutable; 041 import com.unboundid.util.StaticUtils; 042 import com.unboundid.util.ThreadSafety; 043 import com.unboundid.util.ThreadSafetyLevel; 044 045 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 046 import static com.unboundid.util.Debug.*; 047 048 049 050 /** 051 * <BLOCKQUOTE> 052 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 053 * LDAP SDK for Java. It is not available for use in applications that 054 * include only the Standard Edition of the LDAP SDK, and is not supported for 055 * use in conjunction with non-UnboundID products. 056 * </BLOCKQUOTE> 057 * This class provides an implementation of an extended result that holds 058 * information about the response returned from a 059 * {@link GetSubtreeAccessibilityExtendedRequest}. It has an OID of 060 * 1.3.6.1.4.1.30221.1.6.21, and successful responses will have a value with the 061 * following encoding: 062 * <BR><BR> 063 * <PRE> 064 * GetSubtreeAccessibilityResultValue ::= SEQUENCE OF SEQUENCE { 065 * subtreeBaseDN [0] LDAPDN, 066 * subtreeAccessibility [1] ENUMERATED { 067 * accessible (0), 068 * read-only-bind-allowed (1), 069 * read-only-bind-denied (2), 070 * hidden (3), 071 * ... }, 072 * bypassUserDN [2] LDAPDN OPTIONAL, 073 * effectiveTime [3] OCTET STRING, 074 * ... } 075 * </PRE> 076 */ 077 @NotMutable() 078 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 079 public final class GetSubtreeAccessibilityExtendedResult 080 extends ExtendedResult 081 { 082 /** 083 * The OID (1.3.6.1.4.1.30221.1.6.21) for the get subtree accessibility 084 * extended result. 085 */ 086 public static final String GET_SUBTREE_ACCESSIBILITY_RESULT_OID = 087 "1.3.6.1.4.1.30221.1.6.21"; 088 089 090 091 /** 092 * The BER type for the element that holds the base DN for a subtree 093 * accessibility restriction. 094 */ 095 private static final byte TYPE_BASE_DN = (byte) 0x80; 096 097 098 099 /** 100 * The BER type for the element that holds the accessibility state for a 101 * subtree accessibility restriction. 102 */ 103 private static final byte TYPE_STATE = (byte) 0x81; 104 105 106 107 /** 108 * The BER type for the element that holds the bypass user DN for a subtree 109 * accessibility restriction. 110 */ 111 private static final byte TYPE_BYPASS_USER = (byte) 0x82; 112 113 114 115 /** 116 * The BER type for the element that holds the effective time for a subtree 117 * accessibility restriction. 118 */ 119 private static final byte TYPE_EFFECTIVE_TIME = (byte) 0x83; 120 121 122 123 /** 124 * The serial version UID for this serializable class. 125 */ 126 private static final long serialVersionUID = -3163306122775326749L; 127 128 129 130 // A list of the subtree accessibility restrictions defined in the server. 131 private final List<SubtreeAccessibilityRestriction> accessibilityRestrictions; 132 133 134 135 /** 136 * Creates a new get subtree accessibility extended result from the provided 137 * generic extended result. 138 * 139 * @param extendedResult The generic extended result to be decoded. 140 * 141 * @throws LDAPException If a problem occurs while attempting to decode the 142 * provided extended result as a get connection ID 143 * result. 144 */ 145 public GetSubtreeAccessibilityExtendedResult( 146 final ExtendedResult extendedResult) 147 throws LDAPException 148 { 149 super(extendedResult); 150 151 final ASN1OctetString value = extendedResult.getValue(); 152 if (value == null) 153 { 154 accessibilityRestrictions = null; 155 return; 156 } 157 158 try 159 { 160 final ASN1Element[] restrictionElements = 161 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 162 final ArrayList<SubtreeAccessibilityRestriction> restrictionList = 163 new ArrayList<SubtreeAccessibilityRestriction>( 164 restrictionElements.length); 165 166 for (final ASN1Element e : restrictionElements) 167 { 168 String baseDN = null; 169 SubtreeAccessibilityState state = null; 170 String bypassDN = null; 171 Date effectiveTime = null; 172 173 for (final ASN1Element re : ASN1Sequence.decodeAsSequence(e).elements()) 174 { 175 switch (re.getType()) 176 { 177 case TYPE_BASE_DN: 178 baseDN = ASN1OctetString.decodeAsOctetString(re).stringValue(); 179 break; 180 case TYPE_STATE: 181 state = SubtreeAccessibilityState.valueOf( 182 ASN1Enumerated.decodeAsEnumerated(re).intValue()); 183 if (state == null) 184 { 185 throw new LDAPException(ResultCode.DECODING_ERROR, 186 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_UNEXPECTED_STATE.get( 187 ASN1Enumerated.decodeAsEnumerated(re).intValue())); 188 } 189 break; 190 case TYPE_BYPASS_USER: 191 bypassDN = ASN1OctetString.decodeAsOctetString(re).stringValue(); 192 break; 193 case TYPE_EFFECTIVE_TIME: 194 effectiveTime = StaticUtils.decodeGeneralizedTime( 195 ASN1OctetString.decodeAsOctetString(re).stringValue()); 196 break; 197 default: 198 throw new LDAPException(ResultCode.DECODING_ERROR, 199 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_UNEXPECTED_TYPE.get( 200 StaticUtils.toHex(re.getType()))); 201 } 202 } 203 204 if (baseDN == null) 205 { 206 throw new LDAPException(ResultCode.DECODING_ERROR, 207 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_MISSING_BASE.get()); 208 } 209 210 if (state == null) 211 { 212 throw new LDAPException(ResultCode.DECODING_ERROR, 213 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_MISSING_STATE.get()); 214 } 215 216 if (effectiveTime == null) 217 { 218 throw new LDAPException(ResultCode.DECODING_ERROR, 219 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_MISSING_TIME.get()); 220 } 221 222 restrictionList.add(new SubtreeAccessibilityRestriction(baseDN, state, 223 bypassDN, effectiveTime)); 224 } 225 226 accessibilityRestrictions = Collections.unmodifiableList(restrictionList); 227 } 228 catch (final LDAPException le) 229 { 230 debugException(le); 231 throw le; 232 } 233 catch (Exception e) 234 { 235 debugException(e); 236 throw new LDAPException(ResultCode.DECODING_ERROR, 237 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_DECODE_ERROR.get( 238 StaticUtils.getExceptionMessage(e)), 239 e); 240 } 241 } 242 243 244 245 /** 246 * Creates a new get subtree accessibility extended result with the provided 247 * information. 248 * 249 * @param messageID The message ID for the LDAP message that is 250 * associated with this LDAP result. 251 * @param resultCode The result code from the response. 252 * @param diagnosticMessage The diagnostic message from the response, if 253 * available. 254 * @param matchedDN The matched DN from the response, if available. 255 * @param referralURLs The set of referral URLs from the response, if 256 * available. 257 * @param restrictions The set of subtree accessibility restrictions 258 * to include in the response. It may be 259 * {@code null} if this represents an error 260 * response, or it may be empty if there are no 261 * subtree accessibility restrictions defined in 262 * the server. 263 * @param responseControls The set of controls from the response, if 264 * available. 265 */ 266 public GetSubtreeAccessibilityExtendedResult(final int messageID, 267 final ResultCode resultCode, final String diagnosticMessage, 268 final String matchedDN, final String[] referralURLs, 269 final Collection<SubtreeAccessibilityRestriction> restrictions, 270 final Control... responseControls) 271 { 272 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 273 null, encodeValue(restrictions), responseControls); 274 275 if (restrictions == null) 276 { 277 accessibilityRestrictions = null; 278 } 279 else 280 { 281 accessibilityRestrictions = Collections.unmodifiableList( 282 new ArrayList<SubtreeAccessibilityRestriction>(restrictions)); 283 } 284 } 285 286 287 288 /** 289 * Encodes the value for this extended result using the provided information. 290 * 291 * @param restrictions The set of subtree accessibility restrictions to 292 * include in the response. It may be {@code null} if 293 * this represents an error response, or it may be empty 294 * if there are no subtree accessibility restrictions 295 * defined in the server. 296 * 297 * @return An ASN.1 octet string containing the properly-encoded value, or 298 * {@code null} if there should be no value. 299 */ 300 private static ASN1OctetString encodeValue( 301 final Collection<SubtreeAccessibilityRestriction> restrictions) 302 { 303 if (restrictions == null) 304 { 305 return null; 306 } 307 308 final ArrayList<ASN1Element> elements = 309 new ArrayList<ASN1Element>(restrictions.size()); 310 for (final SubtreeAccessibilityRestriction r : restrictions) 311 { 312 final ArrayList<ASN1Element> restrictionElements = 313 new ArrayList<ASN1Element>(4); 314 restrictionElements.add(new ASN1OctetString(TYPE_BASE_DN, 315 r.getSubtreeBaseDN())); 316 restrictionElements.add(new ASN1Enumerated(TYPE_STATE, 317 r.getAccessibilityState().intValue())); 318 319 if (r.getBypassUserDN() != null) 320 { 321 restrictionElements.add(new ASN1OctetString(TYPE_BYPASS_USER, 322 r.getBypassUserDN())); 323 } 324 325 restrictionElements.add(new ASN1OctetString(TYPE_EFFECTIVE_TIME, 326 StaticUtils.encodeGeneralizedTime(r.getEffectiveTime()))); 327 328 elements.add(new ASN1Sequence(restrictionElements)); 329 } 330 331 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 332 } 333 334 335 336 /** 337 * Retrieves a list of the subtree accessibility restrictions defined in the 338 * server. 339 * 340 * @return A list of the subtree accessibility restrictions defined in the 341 * server, an empty list if there are no restrictions defined, or 342 * {@code null} if no restriction data was included in the response 343 * from the server (e.g., because it was an error response). 344 */ 345 public List<SubtreeAccessibilityRestriction> getAccessibilityRestrictions() 346 { 347 return accessibilityRestrictions; 348 } 349 350 351 352 /** 353 * {@inheritDoc} 354 */ 355 @Override() 356 public String getExtendedResultName() 357 { 358 return INFO_EXTENDED_RESULT_NAME_GET_SUBTREE_ACCESSIBILITY.get(); 359 } 360 361 362 363 /** 364 * {@inheritDoc} 365 */ 366 @Override() 367 public void toString(final StringBuilder buffer) 368 { 369 buffer.append("GetSubtreeAccessibilityExtendedResult(resultCode="); 370 buffer.append(getResultCode()); 371 372 final int messageID = getMessageID(); 373 if (messageID >= 0) 374 { 375 buffer.append(", messageID="); 376 buffer.append(messageID); 377 } 378 379 final String diagnosticMessage = getDiagnosticMessage(); 380 if (diagnosticMessage != null) 381 { 382 buffer.append(", diagnosticMessage='"); 383 buffer.append(diagnosticMessage); 384 buffer.append('\''); 385 } 386 387 final String matchedDN = getMatchedDN(); 388 if (matchedDN != null) 389 { 390 buffer.append(", matchedDN='"); 391 buffer.append(matchedDN); 392 buffer.append('\''); 393 } 394 395 final String[] referralURLs = getReferralURLs(); 396 if ((referralURLs != null) && (referralURLs.length > 0)) 397 { 398 buffer.append(", referralURLs={ '"); 399 for (int i=0; i < referralURLs.length; i++) 400 { 401 if (i > 0) 402 { 403 buffer.append("', '"); 404 } 405 buffer.append(referralURLs[i]); 406 } 407 408 buffer.append("' }"); 409 } 410 411 if (accessibilityRestrictions != null) 412 { 413 buffer.append(", accessibilityRestrictions={"); 414 415 final Iterator<SubtreeAccessibilityRestriction> iterator = 416 accessibilityRestrictions.iterator(); 417 while (iterator.hasNext()) 418 { 419 iterator.next().toString(buffer); 420 if (iterator.hasNext()) 421 { 422 buffer.append(", "); 423 } 424 } 425 426 buffer.append('}'); 427 } 428 429 final Control[] controls = getResponseControls(); 430 if (controls.length > 0) 431 { 432 buffer.append(", controls={"); 433 for (int i=0; i < controls.length; i++) 434 { 435 if (i > 0) 436 { 437 buffer.append(", "); 438 } 439 440 buffer.append(controls[i]); 441 } 442 buffer.append('}'); 443 } 444 445 buffer.append(')'); 446 } 447 }