001 /*
002 * Copyright 2007-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2013 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.controls;
022
023
024
025 import com.unboundid.asn1.ASN1Element;
026 import com.unboundid.asn1.ASN1Enumerated;
027 import com.unboundid.asn1.ASN1Exception;
028 import com.unboundid.asn1.ASN1OctetString;
029 import com.unboundid.asn1.ASN1Sequence;
030 import com.unboundid.ldap.sdk.Control;
031 import com.unboundid.ldap.sdk.DecodeableControl;
032 import com.unboundid.ldap.sdk.LDAPException;
033 import com.unboundid.ldap.sdk.ResultCode;
034 import com.unboundid.ldap.sdk.SearchResult;
035 import com.unboundid.util.NotMutable;
036 import com.unboundid.util.ThreadSafety;
037 import com.unboundid.util.ThreadSafetyLevel;
038
039 import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
040 import static com.unboundid.util.Debug.*;
041
042
043
044 /**
045 * This class provides an implementation of the server-side sort response
046 * control, as defined in
047 * <A HREF="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</A>. It may be used
048 * to provide information about the result of server-side sort processing. If
049 * the corresponding search request included the
050 * {@link ServerSideSortRequestControl}, then the search result done message
051 * may include this response control to provide information about the state of
052 * the sorting.
053 */
054 @NotMutable()
055 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
056 public final class ServerSideSortResponseControl
057 extends Control
058 implements DecodeableControl
059 {
060 /**
061 * The OID (1.2.840.113556.1.4.474) for the server-side sort response control.
062 */
063 public static final String SERVER_SIDE_SORT_RESPONSE_OID =
064 "1.2.840.113556.1.4.474";
065
066
067
068 /**
069 * The BER type to use for the element that holds the attribute type.
070 */
071 private static final byte TYPE_ATTRIBUTE_TYPE = (byte) 0x80;
072
073
074
075 /**
076 * The serial version UID for this serializable class.
077 */
078 private static final long serialVersionUID = -8707533262822875822L;
079
080
081
082 // The result code for this server-side sort response control.
083 private final ResultCode resultCode;
084
085 // The name of the attribute associated with this result, if available.
086 private final String attributeName;
087
088
089
090 /**
091 * Creates a new empty control instance that is intended to be used only for
092 * decoding controls via the {@code DecodeableControl} interface.
093 */
094 ServerSideSortResponseControl()
095 {
096 resultCode = null;
097 attributeName = null;
098 }
099
100
101
102 /**
103 * Creates a new server-side sort response control with the provided
104 * information.
105 *
106 * @param resultCode The result code for this server-side sort response.
107 * @param attributeName The name of the attribute associated with this
108 * result. It may be {@code null} if there is no
109 * associated attribute name.
110 * @param isCritical Indicates whether this control should be marked
111 * critical.
112 */
113 public ServerSideSortResponseControl(final ResultCode resultCode,
114 final String attributeName,
115 final boolean isCritical)
116 {
117 super(SERVER_SIDE_SORT_RESPONSE_OID, isCritical,
118 encodeValue(resultCode, attributeName));
119
120 this.resultCode = resultCode;
121 this.attributeName = attributeName;
122 }
123
124
125
126 /**
127 * Creates a new server-side sort response control from the information
128 * contained in the provided control.
129 *
130 * @param oid The OID for the control.
131 * @param isCritical Indicates whether the control should be marked
132 * critical.
133 * @param value The encoded value for the control. This may be
134 * {@code null} if no value was provided.
135 *
136 * @throws LDAPException If a problem occurs while attempting to decode the
137 * provided control as a server-side sort response
138 * control.
139 */
140 public ServerSideSortResponseControl(final String oid,
141 final boolean isCritical,
142 final ASN1OctetString value)
143 throws LDAPException
144 {
145 super(oid, isCritical, value);
146
147 if (value == null)
148 {
149 throw new LDAPException(ResultCode.DECODING_ERROR,
150 ERR_SORT_RESPONSE_NO_VALUE.get());
151 }
152
153 final ASN1Sequence valueSequence;
154 try
155 {
156 final ASN1Element valueElement =
157 ASN1Element.decode(value.getValue());
158 valueSequence = ASN1Sequence.decodeAsSequence(valueElement);
159 }
160 catch (final ASN1Exception ae)
161 {
162 debugException(ae);
163 throw new LDAPException(ResultCode.DECODING_ERROR,
164 ERR_SORT_RESPONSE_VALUE_NOT_SEQUENCE.get(ae), ae);
165 }
166
167 final ASN1Element[] valueElements = valueSequence.elements();
168 if ((valueElements.length < 1) || (valueElements.length > 2))
169 {
170 throw new LDAPException(ResultCode.DECODING_ERROR,
171 ERR_SORT_RESPONSE_INVALID_ELEMENT_COUNT.get(
172 valueElements.length));
173 }
174
175 try
176 {
177 final int rc =
178 ASN1Enumerated.decodeAsEnumerated(valueElements[0]).intValue();
179 resultCode = ResultCode.valueOf(rc);
180 }
181 catch (final ASN1Exception ae)
182 {
183 debugException(ae);
184 throw new LDAPException(ResultCode.DECODING_ERROR,
185 ERR_SORT_RESPONSE_FIRST_NOT_ENUM.get(ae), ae);
186 }
187
188 if (valueElements.length == 2)
189 {
190 attributeName =
191 ASN1OctetString.decodeAsOctetString(valueElements[1]).stringValue();
192 }
193 else
194 {
195 attributeName = null;
196 }
197 }
198
199
200
201 /**
202 * {@inheritDoc}
203 */
204 public ServerSideSortResponseControl
205 decodeControl(final String oid, final boolean isCritical,
206 final ASN1OctetString value)
207 throws LDAPException
208 {
209 return new ServerSideSortResponseControl(oid, isCritical, value);
210 }
211
212
213
214 /**
215 * Extracts a server-side sort response control from the provided result.
216 *
217 * @param result The result from which to retrieve the server-side sort
218 * response control.
219 *
220 * @return The server-side sort response control contained in the provided
221 * result, or {@code null} if the result did not contain a
222 * server-side sort response control.
223 *
224 * @throws LDAPException If a problem is encountered while attempting to
225 * decode the server-side sort response control
226 * contained in the provided result.
227 */
228 public static ServerSideSortResponseControl get(final SearchResult result)
229 throws LDAPException
230 {
231 final Control c = result.getResponseControl(SERVER_SIDE_SORT_RESPONSE_OID);
232 if (c == null)
233 {
234 return null;
235 }
236
237 if (c instanceof ServerSideSortResponseControl)
238 {
239 return (ServerSideSortResponseControl) c;
240 }
241 else
242 {
243 return new ServerSideSortResponseControl(c.getOID(), c.isCritical(),
244 c.getValue());
245 }
246 }
247
248
249
250 /**
251 * Encodes the provided information into an octet string that can be used as
252 * the value for this control.
253 *
254 * @param resultCode The result code for this server-side sort response
255 * control.
256 * @param attributeName The attribute name to include in the control, or
257 * {@code null} if it should not be provided.
258 *
259 * @return An ASN.1 octet string that can be used as the value for this
260 * control.
261 */
262 private static ASN1OctetString encodeValue(final ResultCode resultCode,
263 final String attributeName)
264 {
265 final ASN1Element[] valueElements;
266 if (attributeName == null)
267 {
268 valueElements = new ASN1Element[]
269 {
270 new ASN1Enumerated(resultCode.intValue())
271 };
272 }
273 else
274 {
275 valueElements = new ASN1Element[]
276 {
277 new ASN1Enumerated(resultCode.intValue()),
278 new ASN1OctetString(TYPE_ATTRIBUTE_TYPE, attributeName)
279 };
280 }
281
282 return new ASN1OctetString(new ASN1Sequence(valueElements).encode());
283 }
284
285
286
287 /**
288 * Retrieves the result code for this server-side sort response control.
289 *
290 * @return The result code for this server-side sort response control.
291 */
292 public ResultCode getResultCode()
293 {
294 return resultCode;
295 }
296
297
298
299 /**
300 * Retrieves the attribute name for this server-side sort response control, if
301 * available.
302 *
303 * @return The attribute name for this server-side sort response control, or
304 * {@code null} if none was provided.
305 */
306 public String getAttributeName()
307 {
308 return attributeName;
309 }
310
311
312
313 /**
314 * {@inheritDoc}
315 */
316 @Override()
317 public String getControlName()
318 {
319 return INFO_CONTROL_NAME_SORT_RESPONSE.get();
320 }
321
322
323
324 /**
325 * {@inheritDoc}
326 */
327 @Override()
328 public void toString(final StringBuilder buffer)
329 {
330 buffer.append("ServerSideSortResponseControl(resultCode=");
331 buffer.append(resultCode);
332
333 if (attributeName != null)
334 {
335 buffer.append(", attributeName='");
336 buffer.append(attributeName);
337 buffer.append('\'');
338 }
339
340 buffer.append(')');
341 }
342 }