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