001/* 002 * Copyright 2014-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2019 Ping Identity Corporation 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 */ 021package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.LinkedHashSet; 030import java.util.List; 031import java.util.Set; 032 033import com.unboundid.asn1.ASN1Element; 034import com.unboundid.asn1.ASN1OctetString; 035import com.unboundid.asn1.ASN1Sequence; 036import com.unboundid.asn1.ASN1Set; 037import com.unboundid.ldap.sdk.Control; 038import com.unboundid.ldap.sdk.DecodeableControl; 039import com.unboundid.ldap.sdk.ExtendedResult; 040import com.unboundid.ldap.sdk.LDAPException; 041import com.unboundid.ldap.sdk.LDAPResult; 042import com.unboundid.ldap.sdk.ResultCode; 043import com.unboundid.ldap.sdk.SearchResultEntry; 044import com.unboundid.util.Debug; 045import com.unboundid.util.NotMutable; 046import com.unboundid.util.StaticUtils; 047import com.unboundid.util.ThreadSafety; 048import com.unboundid.util.ThreadSafetyLevel; 049import com.unboundid.util.Validator; 050 051import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 052 053 054 055/** 056 * This class provides a response control that may be used to provide the 057 * backend set ID(s) for any relevant backend sets accessed during the course 058 * of processing an operation. It may be returned in response to a request 059 * containing either the get backend set ID request control or the route to 060 * backend set request control. For add, simple bind, compare, delete, 061 * modify, and modify DN operations, the LDAP result message for the operation 062 * may contain zero or one get backend set ID response control. For extended 063 * operations, the extended result message may contain zero, one, or multiple 064 * get backend set ID response controls. For search operations, each search 065 * result entry may contain zero or one get backend set ID response control, 066 * while the search result done message will not contain any such control. See 067 * the {@link GetBackendSetIDRequestControl} class documentation for a more 068 * complete description of the usage for these controls. 069 * <BR> 070 * <BLOCKQUOTE> 071 * <B>NOTE:</B> This class, and other classes within the 072 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 073 * supported for use against Ping Identity, UnboundID, and 074 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 075 * for proprietary functionality or for external specifications that are not 076 * considered stable or mature enough to be guaranteed to work in an 077 * interoperable way with other types of LDAP servers. 078 * </BLOCKQUOTE> 079 * <BR> 080 * The get backend set ID response control has an OID of 081 * "1.3.6.1.4.1.30221.2.5.34", a criticality of false, and a value with the 082 * following encoding: 083 * <PRE> 084 * GET_BACKEND_SET_ID_RESPONSE_VALUE ::= SEQUENCE { 085 * entryBalancingRequestProcessorID OCTET STRING, 086 * backendSetIDs SET SIZE (1..MAX) OF OCTET STRING, 087 * ... } 088 * </PRE> 089 * 090 * @see GetBackendSetIDRequestControl 091 * @see RouteToBackendSetRequestControl 092 */ 093@NotMutable() 094@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 095public final class GetBackendSetIDResponseControl 096 extends Control 097 implements DecodeableControl 098{ 099 /** 100 * The OID (1.3.6.1.4.1.30221.2.5.34) for the get backend set ID response 101 * control. 102 */ 103 public static final String GET_BACKEND_SET_ID_RESPONSE_OID = 104 "1.3.6.1.4.1.30221.2.5.34"; 105 106 107 108 /** 109 * The serial version UID for this serializable class. 110 */ 111 private static final long serialVersionUID = 117359364981309726L; 112 113 114 115 // The backend set IDs for backend sets used during processing. 116 private final Set<String> backendSetIDs; 117 118 // The identifier for the entry-balancing request processor with which the 119 // backend set IDs are associated. 120 private final String entryBalancingRequestProcessorID; 121 122 123 124 /** 125 * Creates a new empty control instance that is intended to be used only for 126 * decoding controls via the {@code DecodeableControl} interface. 127 */ 128 GetBackendSetIDResponseControl() 129 { 130 entryBalancingRequestProcessorID = null; 131 backendSetIDs = null; 132 } 133 134 135 136 /** 137 * Creates a new get backend set ID response control with the provided 138 * information. 139 * 140 * @param entryBalancingRequestProcessorID The identifier for the 141 * entry-balancing request processor 142 * with which the backend set IDs 143 * are associated. It must not be 144 * {@code null}. 145 * @param backendSetID The backend set ID for the 146 * backend set used during 147 * processing. It must not be 148 * {@code null}. 149 */ 150 public GetBackendSetIDResponseControl( 151 final String entryBalancingRequestProcessorID, 152 final String backendSetID) 153 { 154 this(entryBalancingRequestProcessorID, 155 Collections.singletonList(backendSetID)); 156 } 157 158 159 160 /** 161 * Creates a new get backend set ID response control with the provided 162 * information. 163 * 164 * @param entryBalancingRequestProcessorID The identifier for the 165 * entry-balancing request processor 166 * with which the backend set IDs 167 * are associated. It must not be 168 * {@code null}. 169 * @param backendSetIDs The backend set IDs for backend 170 * sets used during processing. It 171 * must not be {@code null} or 172 * empty. 173 */ 174 public GetBackendSetIDResponseControl( 175 final String entryBalancingRequestProcessorID, 176 final Collection<String> backendSetIDs) 177 { 178 super(GET_BACKEND_SET_ID_RESPONSE_OID, false, 179 encodeValue(entryBalancingRequestProcessorID, backendSetIDs)); 180 181 this.entryBalancingRequestProcessorID = entryBalancingRequestProcessorID; 182 this.backendSetIDs = 183 Collections.unmodifiableSet(new LinkedHashSet<>(backendSetIDs)); 184 } 185 186 187 188 /** 189 * Creates a new get backend set ID response control decoded from the given 190 * generic control contents. 191 * 192 * @param oid The OID for the control. 193 * @param isCritical Indicates whether this control should be marked 194 * critical. 195 * @param value The encoded value for the control. 196 * 197 * @throws LDAPException If a problem occurs while attempting to decode the 198 * generic control as a get backend set ID response 199 * control. 200 */ 201 public GetBackendSetIDResponseControl(final String oid, 202 final boolean isCritical, 203 final ASN1OctetString value) 204 throws LDAPException 205 { 206 super(oid, isCritical, value); 207 208 if (value == null) 209 { 210 throw new LDAPException(ResultCode.DECODING_ERROR, 211 ERR_GET_BACKEND_SET_ID_RESPONSE_MISSING_VALUE.get()); 212 } 213 214 try 215 { 216 final ASN1Element[] elements = 217 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 218 entryBalancingRequestProcessorID = 219 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 220 221 final ASN1Element[] backendSetIDElements = 222 ASN1Set.decodeAsSet(elements[1]).elements(); 223 final LinkedHashSet<String> setIDs = new LinkedHashSet<>( 224 StaticUtils.computeMapCapacity(backendSetIDElements.length)); 225 for (final ASN1Element e : backendSetIDElements) 226 { 227 setIDs.add(ASN1OctetString.decodeAsOctetString(e).stringValue()); 228 } 229 backendSetIDs = Collections.unmodifiableSet(setIDs); 230 } 231 catch (final Exception e) 232 { 233 Debug.debugException(e); 234 throw new LDAPException(ResultCode.DECODING_ERROR, 235 ERR_GET_BACKEND_SET_ID_RESPONSE_CANNOT_DECODE.get( 236 StaticUtils.getExceptionMessage(e)), 237 e); 238 } 239 } 240 241 242 243 /** 244 * Encodes the provided information into an octet string suitable for use as 245 * the value of this control. 246 * 247 * @param entryBalancingRequestProcessorID The identifier for the 248 * entry-balancing request processor 249 * with which the backend set IDs 250 * are associated. It must not be 251 * {@code null}. 252 * @param backendSetIDs The backend set IDs for backend 253 * sets used during processing. It 254 * must not be {@code null} or 255 * empty. 256 * 257 * @return The encoded representation of the control value. 258 */ 259 private static ASN1OctetString encodeValue( 260 final String entryBalancingRequestProcessorID, 261 final Collection<String> backendSetIDs) 262 { 263 Validator.ensureNotNull(entryBalancingRequestProcessorID); 264 Validator.ensureNotNull(backendSetIDs); 265 Validator.ensureFalse(backendSetIDs.isEmpty()); 266 267 final ArrayList<ASN1Element> backendSetIDElements = 268 new ArrayList<>(backendSetIDs.size()); 269 for (final String s : backendSetIDs) 270 { 271 backendSetIDElements.add(new ASN1OctetString(s)); 272 } 273 274 final ASN1Sequence valueSequence = new ASN1Sequence( 275 new ASN1OctetString(entryBalancingRequestProcessorID), 276 new ASN1Set(backendSetIDElements)); 277 return new ASN1OctetString(valueSequence.encode()); 278 } 279 280 281 282 /** 283 * {@inheritDoc} 284 */ 285 @Override() 286 public GetBackendSetIDResponseControl decodeControl(final String oid, 287 final boolean isCritical, 288 final ASN1OctetString value) 289 throws LDAPException 290 { 291 return new GetBackendSetIDResponseControl(oid, isCritical, value); 292 } 293 294 295 296 /** 297 * Retrieves the identifier for the entry-balancing request processor with 298 * which the backend sets IDs are associated. 299 * 300 * @return The identifier for the entry-balancing request processor with 301 * which the backend set IDs are associated. 302 */ 303 public String getEntryBalancingRequestProcessorID() 304 { 305 return entryBalancingRequestProcessorID; 306 } 307 308 309 310 /** 311 * Retrieves the backend set IDs for the backend sets used during processing. 312 * 313 * @return The backend set IDs for the backend sets used during processing. 314 */ 315 public Set<String> getBackendSetIDs() 316 { 317 return backendSetIDs; 318 } 319 320 321 322 /** 323 * Extracts a get backend set ID response control from the provided result. 324 * 325 * @param result The result from which to retrieve the get backend set ID 326 * response control. 327 * 328 * @return The get backend set ID response control contained in the provided 329 * result, or {@code null} if the result did not contain a get 330 * backend set ID response control. 331 * 332 * @throws LDAPException If a problem is encountered while attempting to 333 * decode the get backend set ID response control 334 * contained in the provided result. 335 */ 336 public static GetBackendSetIDResponseControl get(final LDAPResult result) 337 throws LDAPException 338 { 339 final Control c = 340 result.getResponseControl(GET_BACKEND_SET_ID_RESPONSE_OID); 341 if (c == null) 342 { 343 return null; 344 } 345 346 if (c instanceof GetBackendSetIDResponseControl) 347 { 348 return (GetBackendSetIDResponseControl) c; 349 } 350 else 351 { 352 return new GetBackendSetIDResponseControl(c.getOID(), c.isCritical(), 353 c.getValue()); 354 } 355 } 356 357 358 359 /** 360 * Extracts a get backend set ID response control from the provided search 361 * result entry. 362 * 363 * @param entry The entry from which to retrieve the get backend set ID 364 * response control. 365 * 366 * @return The get backend set ID response control contained in the provided 367 * entry, or {@code null} if the entry did not contain a get backend 368 * set ID response control. 369 * 370 * @throws LDAPException If a problem is encountered while attempting to 371 * decode the get backend set ID response control 372 * contained in the provided result. 373 */ 374 public static GetBackendSetIDResponseControl 375 get(final SearchResultEntry entry) 376 throws LDAPException 377 { 378 final Control c = entry.getControl(GET_BACKEND_SET_ID_RESPONSE_OID); 379 if (c == null) 380 { 381 return null; 382 } 383 384 if (c instanceof GetBackendSetIDResponseControl) 385 { 386 return (GetBackendSetIDResponseControl) c; 387 } 388 else 389 { 390 return new GetBackendSetIDResponseControl(c.getOID(), c.isCritical(), 391 c.getValue()); 392 } 393 } 394 395 396 397 /** 398 * Extracts any get backend set ID response controls from the provided 399 * extended result. 400 * 401 * @param result The extended result from which to retrieve the get backend 402 * set ID response control(s). 403 * 404 * @return A list of get backend set ID response controls contained in the 405 * provided extended result, or an empty list if the result did not 406 * contain a get any backend set ID response controls. 407 * 408 * @throws LDAPException If a problem is encountered while attempting to 409 * decode the any backend set ID response control 410 * contained in the provided result. 411 */ 412 public static List<GetBackendSetIDResponseControl> 413 get(final ExtendedResult result) 414 throws LDAPException 415 { 416 final Control[] controls = result.getResponseControls(); 417 if (controls.length == 0) 418 { 419 return Collections.emptyList(); 420 } 421 422 final ArrayList<GetBackendSetIDResponseControl> decodedControls = 423 new ArrayList<>(controls.length); 424 for (final Control c : controls) 425 { 426 if (c instanceof GetBackendSetIDResponseControl) 427 { 428 decodedControls.add((GetBackendSetIDResponseControl) c); 429 } 430 else if (c.getOID().equals(GET_BACKEND_SET_ID_RESPONSE_OID)) 431 { 432 decodedControls.add(new GetBackendSetIDResponseControl(c.getOID(), 433 c.isCritical(), c.getValue())); 434 } 435 } 436 437 return Collections.unmodifiableList(decodedControls); 438 } 439 440 441 442 /** 443 * {@inheritDoc} 444 */ 445 @Override() 446 public String getControlName() 447 { 448 return INFO_CONTROL_NAME_GET_BACKEND_SET_ID_RESPONSE.get(); 449 } 450 451 452 453 /** 454 * {@inheritDoc} 455 */ 456 @Override() 457 public void toString(final StringBuilder buffer) 458 { 459 buffer.append("GetBackendSetIDResponseControl(" + 460 "entryBalancingRequestProcessorID='"); 461 buffer.append(entryBalancingRequestProcessorID); 462 buffer.append("', backendSetIDs={"); 463 464 final Iterator<String> iterator = backendSetIDs.iterator(); 465 while (iterator.hasNext()) 466 { 467 buffer.append('\''); 468 buffer.append(iterator.next()); 469 buffer.append('\''); 470 471 if (iterator.hasNext()) 472 { 473 buffer.append(", "); 474 } 475 } 476 477 buffer.append("})"); 478 } 479}