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 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.controls;
028import org.forgerock.i18n.LocalizableMessage;
029
030
031import java.io.IOException;
032
033import org.forgerock.opendj.io.*;
034import org.opends.server.types.Control;
035import org.opends.server.types.DirectoryException;
036import org.forgerock.opendj.ldap.ByteString;
037import org.forgerock.opendj.ldap.ResultCode;
038
039import static org.opends.messages.ProtocolMessages.*;
040import static org.opends.server.util.ServerConstants.*;
041import static org.opends.server.util.StaticUtils.*;
042
043
044
045/**
046 * This class implements the server-side sort response control as defined in RFC
047 * 2891 section 1.2.  The ASN.1 description for the control value is:
048 * <BR><BR>
049 * <PRE>
050 * SortResult ::= SEQUENCE {
051 *    sortResult  ENUMERATED {
052 *        success                   (0), -- results are sorted
053 *        operationsError           (1), -- server internal failure
054 *        timeLimitExceeded         (3), -- timelimit reached before
055 *                                       -- sorting was completed
056 *        strongAuthRequired        (8), -- refused to return sorted
057 *                                       -- results via insecure
058 *                                       -- protocol
059 *        adminLimitExceeded       (11), -- too many matching entries
060 *                                       -- for the server to sort
061 *        noSuchAttribute          (16), -- unrecognized attribute
062 *                                       -- type in sort key
063 *        inappropriateMatching    (18), -- unrecognized or
064 *                                       -- inappropriate matching
065 *                                       -- rule in sort key
066 *        insufficientAccessRights (50), -- refused to return sorted
067 *                                       -- results to this client
068 *        busy                     (51), -- too busy to process
069 *        unwillingToPerform       (53), -- unable to sort
070 *        other                    (80)
071 *        },
072 *  attributeType [0] AttributeDescription OPTIONAL }
073 * </PRE>
074 */
075public class ServerSideSortResponseControl
076       extends Control
077{
078  /**
079   * ControlDecoder implementation to decode this control from a ByteString.
080   */
081  private static final class Decoder
082      implements ControlDecoder<ServerSideSortResponseControl>
083  {
084    /** {@inheritDoc} */
085    public ServerSideSortResponseControl decode(boolean isCritical,
086                                                ByteString value)
087        throws DirectoryException
088    {
089      if (value == null)
090      {
091        LocalizableMessage message = INFO_SORTRES_CONTROL_NO_VALUE.get();
092        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
093      }
094
095      ASN1Reader reader = ASN1.getReader(value);
096      try
097      {
098        reader.readStartSequence();
099        int resultCode = (int)reader.readInteger();
100
101        String attributeType = null;
102        if(reader.hasNextElement())
103        {
104          attributeType = reader.readOctetStringAsString();
105        }
106
107        return new ServerSideSortResponseControl(isCritical,
108            resultCode,
109            attributeType);
110      }
111      catch (Exception e)
112      {
113        LocalizableMessage message =
114            INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE.get(
115                getExceptionMessage(e));
116        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
117      }
118    }
119
120    public String getOID()
121    {
122      return OID_SERVER_SIDE_SORT_RESPONSE_CONTROL;
123    }
124
125  }
126
127  /**
128   * The Control Decoder that can be used to decode this control.
129   */
130  public static final ControlDecoder<ServerSideSortResponseControl> DECODER =
131    new Decoder();
132
133  /**
134   * The BER type to use when encoding the attribute type element.
135   */
136  private static final byte TYPE_ATTRIBUTE_TYPE = (byte) 0x80;
137
138
139
140  /** The result code for the sort result. */
141  private int resultCode;
142
143  /** The attribute type for the sort result. */
144  private String attributeType;
145
146
147
148  /**
149   * Creates a new server-side sort response control based on the provided
150   * result code and attribute type.
151   *
152   * @param  resultCode     The result code for the sort result.
153   * @param  attributeType  The attribute type for the sort result (or
154   *                        {@code null} if there is none).
155   */
156  public ServerSideSortResponseControl(int resultCode, String attributeType)
157  {
158    this(false, resultCode, attributeType);
159  }
160
161
162
163  /**
164   * Creates a new server-side sort response control with the provided
165   * information.
166   *
167   * @param  isCritical     Indicates whether support for this control should be
168   *                        considered a critical part of the server processing.
169   * @param  resultCode     The result code for the sort result.
170   * @param  attributeType  The attribute type for the sort result.
171   */
172  public ServerSideSortResponseControl(boolean isCritical,
173                                       int resultCode,
174                                       String attributeType)
175  {
176    super(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL, isCritical);
177
178    this.resultCode    = resultCode;
179    this.attributeType = attributeType;
180  }
181
182
183
184  /**
185   * Retrieves the result code for this sort result.
186   *
187   * @return  The result code for this sort result.
188   */
189  public int getResultCode()
190  {
191    return resultCode;
192  }
193
194
195
196  /**
197   * Retrieves the attribute type for this sort result.
198   *
199   * @return  The attribute type for this sort result, or {@code null} if there
200   *          is none.
201   */
202  public String getAttributeType()
203  {
204    return attributeType;
205  }
206
207
208
209  /**
210   * Writes this control's value to an ASN.1 writer. The value (if any) must be
211   * written as an ASN1OctetString.
212   *
213   * @param writer The ASN.1 writer to use.
214   * @throws IOException If a problem occurs while writing to the stream.
215   */
216  @Override
217  protected void writeValue(ASN1Writer writer) throws IOException {
218    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
219
220    writer.writeStartSequence();
221    writer.writeEnumerated(resultCode);
222    if (attributeType != null)
223    {
224      writer.writeOctetString(TYPE_ATTRIBUTE_TYPE, attributeType);
225    }
226    writer.writeEndSequence();
227
228    writer.writeEndSequence();
229  }
230
231
232
233  /**
234   * Appends a string representation of this server-side sort response control
235   * to the provided buffer.
236   *
237   * @param  buffer  The buffer to which the information should be appended.
238   */
239  @Override
240  public void toString(StringBuilder buffer)
241  {
242    buffer.append("ServerSideSortResponseControl(resultCode=");
243    buffer.append(resultCode);
244
245    if (attributeType != null)
246    {
247      buffer.append(", attributeType=");
248      buffer.append(attributeType);
249    }
250
251    buffer.append(")");
252  }
253}
254