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