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