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-2016 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  /** ControlDecoder implementation to decode this control from a ByteString. */
050  private static final class Decoder implements
051      ControlDecoder<LDAPPostReadRequestControl>
052  {
053    @Override
054    public LDAPPostReadRequestControl decode(boolean isCritical,
055        ByteString value) throws DirectoryException
056    {
057      if (value == null)
058      {
059        LocalizableMessage message = ERR_POSTREADREQ_NO_CONTROL_VALUE.get();
060        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
061      }
062
063      ASN1Reader reader = ASN1.getReader(value);
064      LinkedHashSet<String> rawAttributes = new LinkedHashSet<>();
065      try
066      {
067        reader.readStartSequence();
068        while (reader.hasNextElement())
069        {
070          rawAttributes.add(reader.readOctetStringAsString());
071        }
072        reader.readEndSequence();
073      }
074      catch (Exception ae)
075      {
076        logger.traceException(ae);
077
078        LocalizableMessage message = ERR_POSTREADREQ_CANNOT_DECODE_VALUE.get(ae
079            .getMessage());
080        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, ae);
081      }
082
083      return new LDAPPostReadRequestControl(isCritical, rawAttributes);
084    }
085
086
087
088    @Override
089    public String getOID()
090    {
091      return OID_LDAP_READENTRY_POSTREAD;
092    }
093
094  }
095
096
097
098  /** The Control Decoder that can be used to decode this control. */
099  public static final ControlDecoder<LDAPPostReadRequestControl> DECODER =
100      new Decoder();
101  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
102
103  /** The set of raw attributes to return in the entry. */
104  private Set<String> rawAttributes;
105
106  /** The set of processed attributes to return in the entry. */
107  private Set<String> requestedAttributes;
108
109
110
111  /**
112   * Creates a new instance of this LDAP post-read request control with the
113   * provided information.
114   *
115   * @param isCritical
116   *          Indicates whether support for this control should be considered a
117   *          critical part of the server processing.
118   * @param rawAttributes
119   *          The set of raw attributes to return in the entry. A null or empty
120   *          set will indicates that all user attributes should be returned.
121   */
122  public LDAPPostReadRequestControl(boolean isCritical,
123      Set<String> rawAttributes)
124  {
125    super(OID_LDAP_READENTRY_POSTREAD, isCritical);
126    if (rawAttributes == null)
127    {
128      this.rawAttributes = new LinkedHashSet<>(0);
129    }
130    else
131    {
132      this.rawAttributes = rawAttributes;
133    }
134    requestedAttributes = null;
135  }
136
137
138
139  /**
140   * Creates a new instance of this LDAP post-read request control with the
141   * provided information.
142   *
143   * @param oid
144   *          The OID to use for this control.
145   * @param isCritical
146   *          Indicates whether support for this control should be considered a
147   *          critical part of the server processing.
148   * @param rawAttributes
149   *          The set of raw attributes to return in the entry. A null or empty
150   *          set will indicates that all user attributes should be returned.
151   */
152  public LDAPPostReadRequestControl(String oid, boolean isCritical,
153      Set<String> rawAttributes)
154  {
155    super(oid, isCritical);
156    if (rawAttributes == null)
157    {
158      this.rawAttributes = new LinkedHashSet<>(0);
159    }
160    else
161    {
162      this.rawAttributes = rawAttributes;
163    }
164    requestedAttributes = null;
165  }
166
167
168
169  /**
170   * Writes this control's value to an ASN.1 writer. The value (if any) must be
171   * written as an ASN1OctetString.
172   *
173   * @param writer
174   *          The ASN.1 output stream to write to.
175   * @throws IOException
176   *           If a problem occurs while writing to the stream.
177   */
178  @Override
179  public void writeValue(ASN1Writer writer) throws IOException
180  {
181    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
182    {
183      writer.writeStartSequence();
184      if (rawAttributes != null)
185      {
186        for (String attr : rawAttributes)
187        {
188          writer.writeOctetString(attr);
189        }
190      }
191      writer.writeEndSequence();
192    }
193    writer.writeEndSequence();
194  }
195
196
197
198  /**
199   * Retrieves the raw, unprocessed set of requested attributes. It must not be
200   * altered by the caller without calling <CODE>setRawAttributes</CODE> with
201   * the updated set.
202   *
203   * @return The raw, unprocessed set of attributes.
204   */
205  public Set<String> getRawAttributes()
206  {
207    return rawAttributes;
208  }
209
210
211
212  /**
213   * Retrieves the set of processed attributes that have been requested for
214   * inclusion in the entry that is returned.
215   *
216   * @return The set of processed attributes that have been requested for
217   *         inclusion in the entry that is returned.
218   */
219  public Set<String> getRequestedAttributes()
220  {
221    if (requestedAttributes == null)
222    {
223      requestedAttributes = normalizedObjectClasses(rawAttributes);
224    }
225    return requestedAttributes;
226  }
227
228
229
230  /**
231   * Appends a string representation of this LDAP post-read request control to
232   * the provided buffer.
233   *
234   * @param buffer
235   *          The buffer to which the information should be appended.
236   */
237  @Override
238  public void toString(StringBuilder buffer)
239  {
240    buffer.append("LDAPPostReadRequestControl(criticality=");
241    buffer.append(isCritical());
242    buffer.append(",attrs=\"");
243
244    if (!rawAttributes.isEmpty())
245    {
246      Iterator<String> iterator = rawAttributes.iterator();
247      buffer.append(iterator.next());
248
249      while (iterator.hasNext())
250      {
251        buffer.append(",");
252        buffer.append(iterator.next());
253      }
254    }
255
256    buffer.append("\")");
257  }
258}