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}