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