001/* 002 * Copyright 2012-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2012-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2012-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.extensions; 037 038 039 040import java.util.ArrayList; 041import java.util.Collection; 042import java.util.Collections; 043import java.util.Iterator; 044import java.util.List; 045 046import com.unboundid.asn1.ASN1Element; 047import com.unboundid.asn1.ASN1OctetString; 048import com.unboundid.asn1.ASN1Sequence; 049import com.unboundid.ldap.sdk.Control; 050import com.unboundid.ldap.sdk.ExtendedResult; 051import com.unboundid.ldap.sdk.LDAPException; 052import com.unboundid.ldap.sdk.ResultCode; 053import com.unboundid.util.Debug; 054import com.unboundid.util.NotMutable; 055import com.unboundid.util.NotNull; 056import com.unboundid.util.Nullable; 057import com.unboundid.util.StaticUtils; 058import com.unboundid.util.ThreadSafety; 059import com.unboundid.util.ThreadSafetyLevel; 060 061import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 062 063 064 065/** 066 * This class provides an implementation of an extended result that can be used 067 * to provide information about the notification subscriptions defined in the 068 * target server. 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 OID for this result is 1.3.6.1.4.1.30221.2.6.41, and the value (if 081 * present) should have the following encoding: 082 * <BR><BR> 083 * <PRE> 084 * ListNotificationSubscriptionsResponse ::= SEQUENCE OF SEQUENCE { 085 * notificationDestinationID OCTET STRING, 086 * destinationDetails SEQUENCE OF OCTET STRING, 087 * subscriptions SEQUENCE OF SEQUENCE { 088 * subscriptionID OCTET STRING, 089 * subscriptionDetails SEQUENCE OF OCTET STRING } } 090 * </PRE> 091 */ 092@NotMutable() 093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 094public final class ListNotificationSubscriptionsExtendedResult 095 extends ExtendedResult 096{ 097 /** 098 * The OID (1.3.6.1.4.1.30221.2.6.41) for the list notification subscriptions 099 * extended result. 100 */ 101 @NotNull public static final String 102 LIST_NOTIFICATION_SUBSCRIPTIONS_RESULT_OID = 103 "1.3.6.1.4.1.30221.2.6.41"; 104 105 106 107 /** 108 * The serial version UID for this serializable class. 109 */ 110 private static final long serialVersionUID = 8876370324325619149L; 111 112 113 114 // The notification destination details for this result. 115 @NotNull private final List<NotificationDestinationDetails> destinations; 116 117 118 119 /** 120 * Creates a new list notification subscriptions extended result from the 121 * provided extended result. 122 * 123 * @param extendedResult The extended result to be decoded as a list 124 * notification subscriptions extended result. 125 * 126 * @throws LDAPException If a problem is encountered while attempting to 127 * decode the provided extended result as a 128 * multi-update result. 129 */ 130 public ListNotificationSubscriptionsExtendedResult( 131 @NotNull final ExtendedResult extendedResult) 132 throws LDAPException 133 { 134 super(extendedResult); 135 136 final ASN1OctetString value = extendedResult.getValue(); 137 if (value == null) 138 { 139 destinations = Collections.emptyList(); 140 return; 141 } 142 143 try 144 { 145 final ASN1Element[] destsElements = 146 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 147 final ArrayList<NotificationDestinationDetails> destList = 148 new ArrayList<>(destsElements.length); 149 for (final ASN1Element destElement : destsElements) 150 { 151 final ASN1Element[] destElements = 152 ASN1Sequence.decodeAsSequence(destElement).elements(); 153 final String destID = 154 ASN1OctetString.decodeAsOctetString(destElements[0]).stringValue(); 155 156 final ASN1Element[] destDetailsElements = 157 ASN1Sequence.decodeAsSequence(destElements[1]).elements(); 158 final ArrayList<ASN1OctetString> destDetailsList = 159 new ArrayList<>(destDetailsElements.length); 160 for (final ASN1Element e : destDetailsElements) 161 { 162 destDetailsList.add(ASN1OctetString.decodeAsOctetString(e)); 163 } 164 165 final ASN1Element[] subElements = 166 ASN1Sequence.decodeAsSequence(destElements[2]).elements(); 167 final ArrayList<NotificationSubscriptionDetails> subscriptions = 168 new ArrayList<>(subElements.length); 169 for (final ASN1Element e : subElements) 170 { 171 final ASN1Element[] sElements = 172 ASN1Sequence.decodeAsSequence(e).elements(); 173 final String subID = 174 ASN1OctetString.decodeAsOctetString(sElements[0]).stringValue(); 175 176 final ASN1Element[] subDetailsElements = 177 ASN1Sequence.decodeAsSequence(sElements[1]).elements(); 178 final ArrayList<ASN1OctetString> subDetails = 179 new ArrayList<>(subDetailsElements.length); 180 for (final ASN1Element sde : subDetailsElements) 181 { 182 subDetails.add(ASN1OctetString.decodeAsOctetString(sde)); 183 } 184 subscriptions.add( 185 new NotificationSubscriptionDetails(subID, subDetails)); 186 } 187 188 destList.add(new NotificationDestinationDetails(destID, destDetailsList, 189 subscriptions)); 190 } 191 192 destinations = Collections.unmodifiableList(destList); 193 } 194 catch (final Exception e) 195 { 196 Debug.debugException(e); 197 throw new LDAPException(ResultCode.DECODING_ERROR, 198 ERR_LIST_NOTIFICATION_SUBS_RESULT_CANNOT_DECODE_VALUE.get( 199 StaticUtils.getExceptionMessage(e)), 200 e); 201 } 202 } 203 204 205 206 /** 207 * Creates a new list notification subscriptions extended request with the 208 * provided information. 209 * 210 * @param messageID The message ID for this extended result. 211 * @param resultCode The result code for this result. It must not be 212 * {@code null}. 213 * @param diagnosticMessage The diagnostic message to include in the result. 214 * It may be {@code null} if no diagnostic message 215 * should be included. 216 * @param matchedDN The matched DN to include in the result. It may 217 * be {@code null} if no matched DN should be 218 * included. 219 * @param referralURLs The set of referral URLs to include in the 220 * result. It may be {@code null} or empty if no 221 * referral URLs should be included. 222 * @param destinations The notification destination details for this 223 * result. It may be {@code null} or empty for a 224 * non-success result. 225 * @param controls The set of controls to include in the 226 * multi-update result. It may be {@code null} or 227 * empty if no controls should be included. 228 * 229 * @throws LDAPException If any of the results are for an inappropriate 230 * operation type. 231 */ 232 public ListNotificationSubscriptionsExtendedResult(final int messageID, 233 @NotNull final ResultCode resultCode, 234 @Nullable final String diagnosticMessage, 235 @Nullable final String matchedDN, 236 @Nullable final String[] referralURLs, 237 @Nullable final Collection<NotificationDestinationDetails> destinations, 238 @Nullable final Control... controls) 239 throws LDAPException 240 { 241 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 242 LIST_NOTIFICATION_SUBSCRIPTIONS_RESULT_OID, encodeValue(destinations), 243 controls); 244 245 if (destinations == null) 246 { 247 this.destinations = Collections.emptyList(); 248 } 249 else 250 { 251 this.destinations = 252 Collections.unmodifiableList(new ArrayList<>(destinations)); 253 } 254 } 255 256 257 258 /** 259 * Encodes the information from the provided set of results into a form 260 * suitable for use as the value of the extended result. 261 * 262 * @param destinations The notification destination details for the result. 263 * It may be {@code null} or empty for a non-success 264 * result. 265 * 266 * @return An ASN.1 element suitable for use as the value of the extended 267 * result. 268 */ 269 @Nullable() 270 private static ASN1OctetString encodeValue( 271 @Nullable final Collection<NotificationDestinationDetails> destinations) 272 { 273 if ((destinations == null) || destinations.isEmpty()) 274 { 275 return null; 276 } 277 278 final ArrayList<ASN1Element> elements = 279 new ArrayList<>(destinations.size()); 280 for (final NotificationDestinationDetails destDetails : destinations) 281 { 282 final ArrayList<ASN1Element> destElements = new ArrayList<>(3); 283 destElements.add(new ASN1OctetString(destDetails.getID())); 284 destElements.add(new ASN1Sequence(destDetails.getDetails())); 285 286 final ArrayList<ASN1Element> subElements = 287 new ArrayList<>(destDetails.getSubscriptions().size()); 288 for (final NotificationSubscriptionDetails subDetails : 289 destDetails.getSubscriptions()) 290 { 291 subElements.add(new ASN1Sequence( 292 new ASN1OctetString(subDetails.getID()), 293 new ASN1Sequence(subDetails.getDetails()))); 294 } 295 destElements.add(new ASN1Sequence(subElements)); 296 elements.add(new ASN1Sequence(destElements)); 297 } 298 299 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 300 } 301 302 303 304 /** 305 * Retrieves a list of the defined notification destinations and their 306 * associated subscriptions. 307 * 308 * @return A list of the defined notification destinations and their 309 * associated subscriptions. 310 */ 311 @NotNull() 312 public List<NotificationDestinationDetails> getDestinations() 313 { 314 return destinations; 315 } 316 317 318 319 /** 320 * {@inheritDoc} 321 */ 322 @Override() 323 @NotNull() 324 public String getExtendedResultName() 325 { 326 return INFO_EXTENDED_RESULT_NAME_LIST_NOTIFICATION_SUBS.get(); 327 } 328 329 330 331 /** 332 * Appends a string representation of this extended result to the provided 333 * buffer. 334 * 335 * @param buffer The buffer to which a string representation of this 336 * extended result will be appended. 337 */ 338 @Override() 339 public void toString(@NotNull final StringBuilder buffer) 340 { 341 buffer.append("ListNotificationSubscriptionsExtendedResult(resultCode="); 342 buffer.append(getResultCode()); 343 344 final int messageID = getMessageID(); 345 if (messageID >= 0) 346 { 347 buffer.append(", messageID="); 348 buffer.append(messageID); 349 } 350 351 buffer.append(", notificationDestinations={"); 352 final Iterator<NotificationDestinationDetails> destIterator = 353 destinations.iterator(); 354 while (destIterator.hasNext()) 355 { 356 destIterator.next().toString(buffer); 357 if (destIterator.hasNext()) 358 { 359 buffer.append(", "); 360 } 361 } 362 buffer.append('}'); 363 364 final String diagnosticMessage = getDiagnosticMessage(); 365 if (diagnosticMessage != null) 366 { 367 buffer.append(", diagnosticMessage='"); 368 buffer.append(diagnosticMessage); 369 buffer.append('\''); 370 } 371 372 final String matchedDN = getMatchedDN(); 373 if (matchedDN != null) 374 { 375 buffer.append(", matchedDN='"); 376 buffer.append(matchedDN); 377 buffer.append('\''); 378 } 379 380 final String[] referralURLs = getReferralURLs(); 381 if (referralURLs.length > 0) 382 { 383 buffer.append(", referralURLs={"); 384 for (int i=0; i < referralURLs.length; i++) 385 { 386 if (i > 0) 387 { 388 buffer.append(", "); 389 } 390 391 buffer.append('\''); 392 buffer.append(referralURLs[i]); 393 buffer.append('\''); 394 } 395 buffer.append('}'); 396 } 397 398 final Control[] responseControls = getResponseControls(); 399 if (responseControls.length > 0) 400 { 401 buffer.append(", responseControls={"); 402 for (int i=0; i < responseControls.length; i++) 403 { 404 if (i > 0) 405 { 406 buffer.append(", "); 407 } 408 409 buffer.append(responseControls[i]); 410 } 411 buffer.append('}'); 412 } 413 414 buffer.append(')'); 415 } 416}