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.opends.server.types.*;
042import org.forgerock.opendj.ldap.ResultCode;
043import org.forgerock.opendj.ldap.ByteString;
044import org.forgerock.i18n.slf4j.LocalizedLogger;
045import static org.opends.messages.ProtocolMessages.*;
046import static org.opends.server.util.ServerConstants.*;
047
048
049
050/**
051 * This class implements the pre-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 before a modify, delete, 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 LDAPPreReadRequestControl extends Control
058{
059  /**
060   * ControlDecoder implementation to decode this control from a ByteString.
061   */
062  private static final class Decoder implements
063      ControlDecoder<LDAPPreReadRequestControl>
064  {
065    /** {@inheritDoc} */
066    public LDAPPreReadRequestControl decode(boolean isCritical,
067        ByteString value) throws DirectoryException
068    {
069      if (value == null)
070      {
071        LocalizableMessage message = ERR_PREREADREQ_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_PREREADREQ_CANNOT_DECODE_VALUE.get(ae
091            .getMessage());
092        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, ae);
093      }
094
095      return new LDAPPreReadRequestControl(isCritical, rawAttributes);
096    }
097
098
099
100    public String getOID()
101    {
102      return OID_LDAP_READENTRY_PREREAD;
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<LDAPPreReadRequestControl> 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 pre-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 LDAPPreReadRequestControl(boolean isCritical,
136      Set<String> rawAttributes)
137  {
138    super(OID_LDAP_READENTRY_PREREAD, 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   * Writes this control's value to an ASN.1 writer. The value (if any) must be
154   * written as an ASN1OctetString.
155   *
156   * @param writer
157   *          The ASN.1 output stream to write to.
158   * @throws IOException
159   *           If a problem occurs while writing to the stream.
160   */
161  @Override
162  public void writeValue(ASN1Writer writer) throws IOException
163  {
164    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
165    {
166      writer.writeStartSequence();
167      if (rawAttributes != null)
168      {
169        for (String attr : rawAttributes)
170        {
171          writer.writeOctetString(attr);
172        }
173      }
174      writer.writeEndSequence();
175    }
176    writer.writeEndSequence();
177  }
178
179
180
181  /**
182   * Retrieves the raw, unprocessed set of requested attributes. It must not be
183   * altered by the caller without calling <CODE>setRawAttributes</CODE> with
184   * the updated set.
185   *
186   * @return The raw, unprocessed set of attributes.
187   */
188  public Set<String> getRawAttributes()
189  {
190    return rawAttributes;
191  }
192
193
194
195  /**
196   * Retrieves the set of processed attributes that have been requested for
197   * inclusion in the entry that is returned.
198   *
199   * @return The set of processed attributes that have been requested for
200   *         inclusion in the entry that is returned.
201   */
202  public Set<String> getRequestedAttributes()
203  {
204    if (requestedAttributes == null)
205    {
206      requestedAttributes = normalizedObjectClasses(rawAttributes);
207    }
208    return requestedAttributes;
209  }
210
211
212
213  /**
214   * Appends a string representation of this LDAP pre-read request control to
215   * the provided buffer.
216   *
217   * @param buffer
218   *          The buffer to which the information should be appended.
219   */
220  @Override
221  public void toString(StringBuilder buffer)
222  {
223    buffer.append("LDAPPreReadRequestControl(criticality=");
224    buffer.append(isCritical());
225    buffer.append(",attrs=\"");
226
227    if (!rawAttributes.isEmpty())
228    {
229      Iterator<String> iterator = rawAttributes.iterator();
230      buffer.append(iterator.next());
231
232      while (iterator.hasNext())
233      {
234        buffer.append(",");
235        buffer.append(iterator.next());
236      }
237    }
238
239    buffer.append("\")");
240  }
241}