001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2015 ForgeRock AS. 016 */ 017package org.opends.server.controls; 018 019 020 021import org.forgerock.i18n.LocalizableMessage; 022 023import java.util.Iterator; 024import java.util.LinkedHashSet; 025import java.util.Set; 026import java.io.IOException; 027 028import org.forgerock.opendj.io.*; 029 030import static org.opends.server.plugins.LDAPADListPlugin.*; 031import org.forgerock.i18n.slf4j.LocalizedLogger; 032import org.opends.server.types.*; 033import org.forgerock.opendj.ldap.ResultCode; 034import org.forgerock.opendj.ldap.ByteString; 035import static org.opends.messages.ProtocolMessages.*; 036import static org.opends.server.util.ServerConstants.*; 037 038 039 040/** 041 * This class implements the post-read request control as defined in RFC 4527. 042 * This control makes it possible to retrieve an entry in the state that it held 043 * immediately after an add, modify, or modify DN operation. It may specify a 044 * specific set of attributes that should be included in that entry. The entry 045 * will be encoded in a corresponding response control. 046 */ 047public class LDAPPostReadRequestControl extends Control 048{ 049 /** 050 * ControlDecoder implementation to decode this control from a ByteString. 051 */ 052 private static final class Decoder implements 053 ControlDecoder<LDAPPostReadRequestControl> 054 { 055 /** {@inheritDoc} */ 056 public LDAPPostReadRequestControl decode(boolean isCritical, 057 ByteString value) throws DirectoryException 058 { 059 if (value == null) 060 { 061 LocalizableMessage message = ERR_POSTREADREQ_NO_CONTROL_VALUE.get(); 062 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 063 } 064 065 ASN1Reader reader = ASN1.getReader(value); 066 LinkedHashSet<String> rawAttributes = new LinkedHashSet<>(); 067 try 068 { 069 reader.readStartSequence(); 070 while (reader.hasNextElement()) 071 { 072 rawAttributes.add(reader.readOctetStringAsString()); 073 } 074 reader.readEndSequence(); 075 } 076 catch (Exception ae) 077 { 078 logger.traceException(ae); 079 080 LocalizableMessage message = ERR_POSTREADREQ_CANNOT_DECODE_VALUE.get(ae 081 .getMessage()); 082 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, ae); 083 } 084 085 return new LDAPPostReadRequestControl(isCritical, rawAttributes); 086 } 087 088 089 090 public String getOID() 091 { 092 return OID_LDAP_READENTRY_POSTREAD; 093 } 094 095 } 096 097 098 099 /** 100 * The Control Decoder that can be used to decode this control. 101 */ 102 public static final ControlDecoder<LDAPPostReadRequestControl> DECODER = 103 new Decoder(); 104 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 105 106 /** The set of raw attributes to return in the entry. */ 107 private Set<String> rawAttributes; 108 109 /** The set of processed attributes to return in the entry. */ 110 private Set<String> requestedAttributes; 111 112 113 114 /** 115 * Creates a new instance of this LDAP post-read request control with the 116 * provided information. 117 * 118 * @param isCritical 119 * Indicates whether support for this control should be considered a 120 * critical part of the server processing. 121 * @param rawAttributes 122 * The set of raw attributes to return in the entry. A null or empty 123 * set will indicates that all user attributes should be returned. 124 */ 125 public LDAPPostReadRequestControl(boolean isCritical, 126 Set<String> rawAttributes) 127 { 128 super(OID_LDAP_READENTRY_POSTREAD, isCritical); 129 if (rawAttributes == null) 130 { 131 this.rawAttributes = new LinkedHashSet<>(0); 132 } 133 else 134 { 135 this.rawAttributes = rawAttributes; 136 } 137 requestedAttributes = null; 138 } 139 140 141 142 /** 143 * Creates a new instance of this LDAP post-read request control with the 144 * provided information. 145 * 146 * @param oid 147 * The OID to use for this control. 148 * @param isCritical 149 * Indicates whether support for this control should be considered a 150 * critical part of the server processing. 151 * @param rawAttributes 152 * The set of raw attributes to return in the entry. A null or empty 153 * set will indicates that all user attributes should be returned. 154 */ 155 public LDAPPostReadRequestControl(String oid, boolean isCritical, 156 Set<String> rawAttributes) 157 { 158 super(oid, isCritical); 159 if (rawAttributes == null) 160 { 161 this.rawAttributes = new LinkedHashSet<>(0); 162 } 163 else 164 { 165 this.rawAttributes = rawAttributes; 166 } 167 requestedAttributes = null; 168 } 169 170 171 172 /** 173 * Writes this control's value to an ASN.1 writer. The value (if any) must be 174 * written as an ASN1OctetString. 175 * 176 * @param writer 177 * The ASN.1 output stream to write to. 178 * @throws IOException 179 * If a problem occurs while writing to the stream. 180 */ 181 @Override 182 public void writeValue(ASN1Writer writer) throws IOException 183 { 184 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 185 { 186 writer.writeStartSequence(); 187 if (rawAttributes != null) 188 { 189 for (String attr : rawAttributes) 190 { 191 writer.writeOctetString(attr); 192 } 193 } 194 writer.writeEndSequence(); 195 } 196 writer.writeEndSequence(); 197 } 198 199 200 201 /** 202 * Retrieves the raw, unprocessed set of requested attributes. It must not be 203 * altered by the caller without calling <CODE>setRawAttributes</CODE> with 204 * the updated set. 205 * 206 * @return The raw, unprocessed set of attributes. 207 */ 208 public Set<String> getRawAttributes() 209 { 210 return rawAttributes; 211 } 212 213 214 215 /** 216 * Retrieves the set of processed attributes that have been requested for 217 * inclusion in the entry that is returned. 218 * 219 * @return The set of processed attributes that have been requested for 220 * inclusion in the entry that is returned. 221 */ 222 public Set<String> getRequestedAttributes() 223 { 224 if (requestedAttributes == null) 225 { 226 requestedAttributes = normalizedObjectClasses(rawAttributes); 227 } 228 return requestedAttributes; 229 } 230 231 232 233 /** 234 * Appends a string representation of this LDAP post-read request control to 235 * the provided buffer. 236 * 237 * @param buffer 238 * The buffer to which the information should be appended. 239 */ 240 @Override 241 public void toString(StringBuilder buffer) 242 { 243 buffer.append("LDAPPostReadRequestControl(criticality="); 244 buffer.append(isCritical()); 245 buffer.append(",attrs=\""); 246 247 if (!rawAttributes.isEmpty()) 248 { 249 Iterator<String> iterator = rawAttributes.iterator(); 250 buffer.append(iterator.next()); 251 252 while (iterator.hasNext()) 253 { 254 buffer.append(","); 255 buffer.append(iterator.next()); 256 } 257 } 258 259 buffer.append("\")"); 260 } 261}