001/* 002 * Copyright 2009-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2009-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) 2009-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.protocol; 037 038 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.Iterator; 043import java.util.List; 044 045import com.unboundid.asn1.ASN1Buffer; 046import com.unboundid.asn1.ASN1BufferSequence; 047import com.unboundid.asn1.ASN1Element; 048import com.unboundid.asn1.ASN1OctetString; 049import com.unboundid.asn1.ASN1Sequence; 050import com.unboundid.asn1.ASN1StreamReader; 051import com.unboundid.asn1.ASN1StreamReaderSequence; 052import com.unboundid.ldap.sdk.Control; 053import com.unboundid.ldap.sdk.LDAPException; 054import com.unboundid.ldap.sdk.ResultCode; 055import com.unboundid.ldap.sdk.SearchResultReference; 056import com.unboundid.util.Debug; 057import com.unboundid.util.InternalUseOnly; 058import com.unboundid.util.NotMutable; 059import com.unboundid.util.NotNull; 060import com.unboundid.util.Nullable; 061import com.unboundid.util.StaticUtils; 062import com.unboundid.util.ThreadSafety; 063import com.unboundid.util.ThreadSafetyLevel; 064 065import static com.unboundid.ldap.protocol.ProtocolMessages.*; 066 067 068 069/** 070 * This class provides an implementation of an LDAP search result reference 071 * protocol op. 072 */ 073@InternalUseOnly() 074@NotMutable() 075@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 076public final class SearchResultReferenceProtocolOp 077 implements ProtocolOp 078{ 079 /** 080 * The serial version UID for this serializable class. 081 */ 082 private static final long serialVersionUID = -1526778443581862609L; 083 084 085 086 // The list of referral URLs for this search result reference. 087 @NotNull private final List<String> referralURLs; 088 089 090 091 /** 092 * Creates a new search result reference protocol op with the provided 093 * information. 094 * 095 * @param referralURLs The list of referral URLs for this search result 096 * reference. 097 */ 098 public SearchResultReferenceProtocolOp( 099 @NotNull final List<String> referralURLs) 100 { 101 this.referralURLs = Collections.unmodifiableList(referralURLs); 102 } 103 104 105 106 /** 107 * Creates a new search result reference protocol op from the provided search 108 * result reference. 109 * 110 * @param reference The search result reference to use to create this 111 * protocol op. 112 */ 113 public SearchResultReferenceProtocolOp( 114 @NotNull final SearchResultReference reference) 115 { 116 referralURLs = StaticUtils.toList(reference.getReferralURLs()); 117 } 118 119 120 121 /** 122 * Creates a new search result reference protocol op read from the provided 123 * ASN.1 stream reader. 124 * 125 * @param reader The ASN.1 stream reader from which to read the search 126 * result reference protocol op. 127 * 128 * @throws LDAPException If a problem occurs while reading or parsing the 129 * search result reference. 130 */ 131 SearchResultReferenceProtocolOp(@NotNull final ASN1StreamReader reader) 132 throws LDAPException 133 { 134 try 135 { 136 final ArrayList<String> refs = new ArrayList<>(5); 137 final ASN1StreamReaderSequence refSequence = reader.beginSequence(); 138 while (refSequence.hasMoreElements()) 139 { 140 refs.add(reader.readString()); 141 } 142 143 referralURLs = Collections.unmodifiableList(refs); 144 } 145 catch (final Exception e) 146 { 147 Debug.debugException(e); 148 149 throw new LDAPException(ResultCode.DECODING_ERROR, 150 ERR_SEARCH_REFERENCE_CANNOT_DECODE.get( 151 StaticUtils.getExceptionMessage(e)), 152 e); 153 } 154 } 155 156 157 158 /** 159 * Retrieves the list of referral URLs for this search result reference. 160 * 161 * @return The list of referral URLs for this search result reference. 162 */ 163 @NotNull() 164 public List<String> getReferralURLs() 165 { 166 return referralURLs; 167 } 168 169 170 171 /** 172 * {@inheritDoc} 173 */ 174 @Override() 175 public byte getProtocolOpType() 176 { 177 return LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE; 178 } 179 180 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override() 186 @NotNull() 187 public ASN1Element encodeProtocolOp() 188 { 189 final ArrayList<ASN1Element> urlElements = 190 new ArrayList<>(referralURLs.size()); 191 for (final String url : referralURLs) 192 { 193 urlElements.add(new ASN1OctetString(url)); 194 } 195 196 return new ASN1Sequence( 197 LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE, 198 urlElements); 199 } 200 201 202 203 /** 204 * Decodes the provided ASN.1 element as a search result reference protocol 205 * op. 206 * 207 * @param element The ASN.1 element to be decoded. 208 * 209 * @return The decoded search result reference protocol op. 210 * 211 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 212 * a search result reference protocol op. 213 */ 214 @NotNull() 215 public static SearchResultReferenceProtocolOp decodeProtocolOp( 216 @NotNull final ASN1Element element) 217 throws LDAPException 218 { 219 try 220 { 221 final ASN1Element[] urlElements = 222 ASN1Sequence.decodeAsSequence(element).elements(); 223 final ArrayList<String> referralURLs = 224 new ArrayList<>(urlElements.length); 225 for (final ASN1Element e : urlElements) 226 { 227 referralURLs.add(ASN1OctetString.decodeAsOctetString(e).stringValue()); 228 } 229 230 return new SearchResultReferenceProtocolOp(referralURLs); 231 } 232 catch (final Exception e) 233 { 234 Debug.debugException(e); 235 throw new LDAPException(ResultCode.DECODING_ERROR, 236 ERR_SEARCH_REFERENCE_CANNOT_DECODE.get( 237 StaticUtils.getExceptionMessage(e)), 238 e); 239 } 240 } 241 242 243 244 /** 245 * {@inheritDoc} 246 */ 247 @Override() 248 public void writeTo(@NotNull final ASN1Buffer buffer) 249 { 250 final ASN1BufferSequence opSequence = buffer.beginSequence( 251 LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE); 252 for (final String s : referralURLs) 253 { 254 buffer.addOctetString(s); 255 } 256 opSequence.end(); 257 } 258 259 260 261 /** 262 * Creates a search result reference from this protocol op. 263 * 264 * @param controls The set of controls to include in the search result 265 * reference. It may be empty or {@code null} if no 266 * controls should be included. 267 * 268 * @return The search result reference that was created. 269 */ 270 @NotNull() 271 public SearchResultReference toSearchResultReference( 272 @Nullable final Control... controls) 273 { 274 final String[] referralArray = new String[referralURLs.size()]; 275 referralURLs.toArray(referralArray); 276 277 return new SearchResultReference(referralArray, controls); 278 } 279 280 281 282 /** 283 * Retrieves a string representation of this protocol op. 284 * 285 * @return A string representation of this protocol op. 286 */ 287 @Override() 288 @NotNull() 289 public String toString() 290 { 291 final StringBuilder buffer = new StringBuilder(); 292 toString(buffer); 293 return buffer.toString(); 294 } 295 296 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override() 302 public void toString(@NotNull final StringBuilder buffer) 303 { 304 buffer.append("SearchResultReferenceProtocolOp(referralURLs={"); 305 306 final Iterator<String> iterator = referralURLs.iterator(); 307 while (iterator.hasNext()) 308 { 309 buffer.append('\''); 310 buffer.append(iterator.next()); 311 buffer.append('\''); 312 if (iterator.hasNext()) 313 { 314 buffer.append(','); 315 } 316 } 317 318 buffer.append("})"); 319 } 320}