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}