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