001/* 002 * Copyright 2007-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 UnboundID Corp. 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; 022 023 024 025import java.io.Serializable; 026import java.util.ArrayList; 027 028import com.unboundid.asn1.ASN1StreamReader; 029import com.unboundid.asn1.ASN1StreamReaderSequence; 030import com.unboundid.ldap.protocol.LDAPResponse; 031import com.unboundid.util.NotMutable; 032import com.unboundid.util.ThreadSafety; 033import com.unboundid.util.ThreadSafetyLevel; 034 035import static com.unboundid.ldap.sdk.LDAPMessages.*; 036import static com.unboundid.util.Debug.*; 037import static com.unboundid.util.StaticUtils.*; 038import static com.unboundid.util.Validator.*; 039 040 041 042/** 043 * This class provides a data structure for representing an LDAP search result 044 * reference. A search result reference consists of a set of referral URLs and 045 * may also include zero or more controls. It describes an alternate location 046 * in which additional results for the search may be found. If there are 047 * multiple referral URLs, then they should all be considered equivalent ways 048 * to access the information (e.g., referrals referencing different servers that 049 * may be contacted). 050 */ 051@NotMutable() 052@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 053public final class SearchResultReference 054 implements Serializable, LDAPResponse 055{ 056 /** 057 * The serial version UID for this serializable class. 058 */ 059 private static final long serialVersionUID = 5675961266319346053L; 060 061 062 063 // The set of controls returned with this search result reference. 064 private final Control[] controls; 065 066 // The message ID for the LDAP message containing this response. 067 private final int messageID; 068 069 // The set of referral URLs for this search result reference. 070 private final String[] referralURLs; 071 072 073 074 /** 075 * Creates a new search result reference with the provided information. 076 * 077 * @param referralURLs The set of referral URLs for this search result 078 * reference. It must not be {@code null}. 079 * @param controls The set of controls returned with this search result 080 * reference. It must not be {@code null}. 081 */ 082 public SearchResultReference(final String[] referralURLs, 083 final Control[] controls) 084 { 085 this(-1, referralURLs, controls); 086 } 087 088 089 090 /** 091 * Creates a new search result reference with the provided information. 092 * 093 * @param messageID The message ID for the LDAP message containing this 094 * response. 095 * @param referralURLs The set of referral URLs for this search result 096 * reference. It must not be {@code null}. 097 * @param controls The set of controls returned with this search result 098 * reference. It must not be {@code null}. 099 */ 100 public SearchResultReference(final int messageID, final String[] referralURLs, 101 final Control[] controls) 102 { 103 ensureNotNull(referralURLs); 104 105 this.messageID = messageID; 106 this.referralURLs = referralURLs; 107 108 if (controls == null) 109 { 110 this.controls = NO_CONTROLS; 111 } 112 else 113 { 114 this.controls = controls; 115 } 116 } 117 118 119 120 /** 121 * Creates a new search result reference object with the protocol op and 122 * controls read from the given ASN.1 stream reader. 123 * 124 * @param messageID The message ID for the LDAP message containing 125 * this response. 126 * @param messageSequence The ASN.1 stream reader sequence used in the 127 * course of reading the LDAP message elements. 128 * @param reader The ASN.1 stream reader from which to read the 129 * protocol op and controls. 130 * 131 * @return The decoded search result reference object. 132 * 133 * @throws LDAPException If a problem occurs while reading or decoding data 134 * from the ASN.1 stream reader. 135 */ 136 static SearchResultReference readSearchReferenceFrom(final int messageID, 137 final ASN1StreamReaderSequence messageSequence, 138 final ASN1StreamReader reader) 139 throws LDAPException 140 { 141 try 142 { 143 final ArrayList<String> refList = new ArrayList<String>(5); 144 final ASN1StreamReaderSequence refSequence = reader.beginSequence(); 145 while (refSequence.hasMoreElements()) 146 { 147 refList.add(reader.readString()); 148 } 149 150 final String[] referralURLs = new String[refList.size()]; 151 refList.toArray(referralURLs); 152 153 Control[] controls = NO_CONTROLS; 154 if (messageSequence.hasMoreElements()) 155 { 156 final ArrayList<Control> controlList = new ArrayList<Control>(5); 157 final ASN1StreamReaderSequence controlSequence = reader.beginSequence(); 158 while (controlSequence.hasMoreElements()) 159 { 160 controlList.add(Control.readFrom(reader)); 161 } 162 163 controls = new Control[controlList.size()]; 164 controlList.toArray(controls); 165 } 166 167 return new SearchResultReference(messageID, referralURLs, controls); 168 } 169 catch (LDAPException le) 170 { 171 debugException(le); 172 throw le; 173 } 174 catch (Exception e) 175 { 176 debugException(e); 177 throw new LDAPException(ResultCode.DECODING_ERROR, 178 ERR_SEARCH_REFERENCE_CANNOT_DECODE.get(getExceptionMessage(e)), e); 179 } 180 } 181 182 183 184 /** 185 * {@inheritDoc} 186 */ 187 public int getMessageID() 188 { 189 return messageID; 190 } 191 192 193 194 /** 195 * Retrieves the set of referral URLs for this search result reference. 196 * 197 * @return The set of referral URLs for this search result reference. 198 */ 199 public String[] getReferralURLs() 200 { 201 return referralURLs; 202 } 203 204 205 206 /** 207 * Retrieves the set of controls returned with this search result reference. 208 * Individual response controls of a specific type may be retrieved and 209 * decoded using the {@code get} method in the response control class. 210 * 211 * @return The set of controls returned with this search result reference. 212 */ 213 public Control[] getControls() 214 { 215 return controls; 216 } 217 218 219 220 /** 221 * Retrieves the control with the specified OID. If there is more than one 222 * control with the given OID, then the first will be returned. 223 * 224 * @param oid The OID of the control to retrieve. 225 * 226 * @return The control with the requested OID, or {@code null} if there is no 227 * such control for this search result reference. 228 */ 229 public Control getControl(final String oid) 230 { 231 for (final Control c : controls) 232 { 233 if (c.getOID().equals(oid)) 234 { 235 return c; 236 } 237 } 238 239 return null; 240 } 241 242 243 244 /** 245 * Retrieves a string representation of this search result reference. 246 * 247 * @return A string representation of this search result reference. 248 */ 249 @Override() 250 public String toString() 251 { 252 final StringBuilder buffer = new StringBuilder(); 253 toString(buffer); 254 return buffer.toString(); 255 } 256 257 258 259 /** 260 * Appends a string representation of this search result reference to the 261 * provided buffer. 262 * 263 * @param buffer The buffer to which to append the string representation of 264 * this search result reference. 265 */ 266 public void toString(final StringBuilder buffer) 267 { 268 buffer.append("SearchResultReference(referralURLs={"); 269 for (int i=0; i < referralURLs.length; i++) 270 { 271 if (i > 0) 272 { 273 buffer.append(", "); 274 } 275 buffer.append(referralURLs[i]); 276 } 277 buffer.append('}'); 278 279 if (messageID >= 0) 280 { 281 buffer.append(", messageID="); 282 buffer.append(messageID); 283 } 284 285 buffer.append(", controls={"); 286 287 for (int i=0; i < controls.length; i++) 288 { 289 if (i > 0) 290 { 291 buffer.append(", "); 292 } 293 294 controls[i].toString(buffer); 295 } 296 297 buffer.append("})"); 298 } 299}