001/* 002 * Copyright 2014-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2018 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.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.Iterator; 030import java.util.LinkedHashSet; 031import java.util.List; 032import java.util.Set; 033 034import com.unboundid.asn1.ASN1Element; 035import com.unboundid.asn1.ASN1OctetString; 036import com.unboundid.asn1.ASN1Sequence; 037import com.unboundid.asn1.ASN1Set; 038import com.unboundid.ldap.sdk.Control; 039import com.unboundid.ldap.sdk.DecodeableControl; 040import com.unboundid.ldap.sdk.ExtendedResult; 041import com.unboundid.ldap.sdk.LDAPException; 042import com.unboundid.ldap.sdk.LDAPResult; 043import com.unboundid.ldap.sdk.ResultCode; 044import com.unboundid.ldap.sdk.SearchResultEntry; 045import com.unboundid.util.Debug; 046import com.unboundid.util.NotMutable; 047import com.unboundid.util.StaticUtils; 048import com.unboundid.util.ThreadSafety; 049import com.unboundid.util.ThreadSafetyLevel; 050import com.unboundid.util.Validator; 051 052import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 053 054 055 056/** 057 * This class provides a response control that may be used to provide the 058 * backend set ID(s) for any relevant backend sets accessed during the course 059 * of processing an operation. It may be returned in response to a request 060 * containing either the get backend set ID request control or the route to 061 * backend set request control. For add, simple bind, compare, delete, 062 * modify, and modify DN operations, the LDAP result message for the operation 063 * may contain zero or one get backend set ID response control. For extended 064 * operations, the extended result message may contain zero, one, or multiple 065 * get backend set ID response controls. For search operations, each search 066 * result entry may contain zero or one get backend set ID response control, 067 * while the search result done message will not contain any such control. See 068 * the {@link GetBackendSetIDRequestControl} class documentation for a more 069 * complete description of the usage for these controls. 070 * <BR> 071 * <BLOCKQUOTE> 072 * <B>NOTE:</B> This class, and other classes within the 073 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 074 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 075 * server products. These classes provide support for proprietary 076 * functionality or for external specifications that are not considered stable 077 * or mature enough to be guaranteed to work in an interoperable way with 078 * other types of LDAP servers. 079 * </BLOCKQUOTE> 080 * <BR> 081 * The get backend set ID response control has an OID of 082 * "1.3.6.1.4.1.30221.2.5.34", a criticality of false, and a value with the 083 * following encoding: 084 * <PRE> 085 * GET_BACKEND_SET_ID_RESPONSE_VALUE ::= SEQUENCE { 086 * entryBalancingRequestProcessorID OCTET STRING, 087 * backendSetIDs SET SIZE (1..MAX) OF OCTET STRING, 088 * ... } 089 * </PRE> 090 * 091 * @see GetBackendSetIDRequestControl 092 * @see RouteToBackendSetRequestControl 093 */ 094@NotMutable() 095@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 096public final class GetBackendSetIDResponseControl 097 extends Control 098 implements DecodeableControl 099{ 100 /** 101 * The OID (1.3.6.1.4.1.30221.2.5.34) for the get backend set ID response 102 * control. 103 */ 104 public static final String GET_BACKEND_SET_ID_RESPONSE_OID = 105 "1.3.6.1.4.1.30221.2.5.34"; 106 107 108 109 /** 110 * The serial version UID for this serializable class. 111 */ 112 private static final long serialVersionUID = 117359364981309726L; 113 114 115 116 // The backend set IDs for backend sets used during processing. 117 private final Set<String> backendSetIDs; 118 119 // The identifier for the entry-balancing request processor with which the 120 // backend set IDs are associated. 121 private final String entryBalancingRequestProcessorID; 122 123 124 125 /** 126 * Creates a new empty control instance that is intended to be used only for 127 * decoding controls via the {@code DecodeableControl} interface. 128 */ 129 GetBackendSetIDResponseControl() 130 { 131 entryBalancingRequestProcessorID = null; 132 backendSetIDs = null; 133 } 134 135 136 137 /** 138 * Creates a new get backend set ID response control with the provided 139 * information. 140 * 141 * @param entryBalancingRequestProcessorID The identifier for the 142 * entry-balancing request processor 143 * with which the backend set IDs 144 * are associated. It must not be 145 * {@code null}. 146 * @param backendSetID The backend set ID for the 147 * backend set used during 148 * processing. It must not be 149 * {@code null}. 150 */ 151 public GetBackendSetIDResponseControl( 152 final String entryBalancingRequestProcessorID, 153 final String backendSetID) 154 { 155 this(entryBalancingRequestProcessorID, Arrays.asList(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<String>(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 = 224 new LinkedHashSet<String>(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<ASN1Element>(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<GetBackendSetIDResponseControl>(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}