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
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.protocols.ldap;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033
034 import org.opends.server.protocols.asn1.ASN1Boolean;
035 import org.opends.server.protocols.asn1.ASN1Element;
036 import org.opends.server.protocols.asn1.ASN1OctetString;
037 import org.opends.server.protocols.asn1.ASN1Sequence;
038 import org.opends.server.types.Control;
039 import org.opends.server.types.DebugLogLevel;
040 import org.opends.server.types.LDAPException;
041
042 import static org.opends.server.loggers.debug.DebugLogger.*;
043 import org.opends.server.loggers.debug.DebugTracer;
044 import static org.opends.messages.ProtocolMessages.*;
045 import static org.opends.server.protocols.asn1.ASN1Constants.*;
046 import static org.opends.server.protocols.ldap.LDAPConstants.*;
047 import static org.opends.server.protocols.ldap.LDAPResultCode.*;
048 import static org.opends.server.util.ServerConstants.*;
049
050
051
052 /**
053 * This class defines the data structures and methods to use when interacting
054 * with a generic LDAP control or set of controls.
055 */
056 public class LDAPControl
057 {
058 /**
059 * The tracer object for the debug logger.
060 */
061 private static final DebugTracer TRACER = getTracer();
062
063 // The control wrapped by this LDAP control.
064 private Control control;
065
066
067
068 /**
069 * Creates a new LDAP control with the information in the provided control.
070 *
071 * @param control The control to use to create this LDAP control.
072 */
073 public LDAPControl(Control control)
074 {
075 this.control = control;
076 }
077
078
079
080 /**
081 * Creates a new LDAP control with the specified OID. It will not be
082 * critical, and will not have a value.
083 *
084 * @param oid The OID for this LDAP control.
085 */
086 public LDAPControl(String oid)
087 {
088 control = new Control(oid, false);
089 }
090
091
092
093 /**
094 * Creates a new LDAP control with the specified OID and criticality. It will
095 * not have a value.
096 *
097 * @param oid The OID for this LDAP control.
098 * @param isCritical Indicates whether this control should be considered
099 * critical.
100 */
101 public LDAPControl(String oid, boolean isCritical)
102 {
103 control = new Control(oid, isCritical);
104 }
105
106
107
108 /**
109 * Creates a new LDAP control with the specified OID, criticality, and value.
110 *
111 * @param oid The OID for this LDAP control.
112 * @param isCritical Indicates whether this control should be considered
113 * critical.
114 * @param value The value for this LDAP control.
115 */
116 public LDAPControl(String oid, boolean isCritical, ASN1OctetString value)
117 {
118 control = new Control(oid, isCritical, value);
119 }
120
121
122
123 /**
124 * Retrieves the control wrapped by this LDAP control.
125 *
126 * @return The control wrapped by this LDAP control.
127 */
128 public Control getControl()
129 {
130 return control;
131 }
132
133
134
135 /**
136 * Encodes this control to an ASN.1 element.
137 *
138 * @return The ASN.1 element containing the encoded control.
139 */
140 public ASN1Element encode()
141 {
142 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
143 elements.add(new ASN1OctetString(control.getOID()));
144
145 if (control.isCritical())
146 {
147 elements.add(new ASN1Boolean(control.isCritical()));
148 }
149
150 ASN1OctetString value = control.getValue();
151 if (value != null)
152 {
153 elements.add(value);
154 }
155
156 return new ASN1Sequence(elements);
157 }
158
159
160
161 /**
162 * Encodes the provided set of controls into an ASN.1 sequence.
163 *
164 * @param controls The set of controls to encode.
165 *
166 * @return The ASN.1 element containing the encoded set of controls.
167 */
168 public static ASN1Element encodeControls(ArrayList<LDAPControl> controls)
169 {
170 ArrayList<ASN1Element> elements =
171 new ArrayList<ASN1Element>(controls.size());
172 for (LDAPControl c : controls)
173 {
174 elements.add(c.encode());
175 }
176
177 return new ASN1Sequence(TYPE_CONTROL_SEQUENCE, elements);
178 }
179
180
181
182 /**
183 * Decodes the provided ASN.1 element as an LDAP control.
184 *
185 * @param element The ASN.1 element to decode.
186 *
187 * @return The decoded LDAP control.
188 *
189 * @throws LDAPException If a problem occurs while attempting to decode the
190 * provided ASN.1 element as an LDAP control.
191 */
192 public static LDAPControl decode(ASN1Element element)
193 throws LDAPException
194 {
195 if (element == null)
196 {
197 Message message = ERR_LDAP_CONTROL_DECODE_NULL.get();
198 throw new LDAPException(PROTOCOL_ERROR, message);
199 }
200
201
202 ArrayList<ASN1Element> elements;
203 try
204 {
205 elements = element.decodeAsSequence().elements();
206 }
207 catch (Exception e)
208 {
209 if (debugEnabled())
210 {
211 TRACER.debugCaught(DebugLogLevel.ERROR, e);
212 }
213
214 Message message = ERR_LDAP_CONTROL_DECODE_SEQUENCE.get(String.valueOf(e));
215 throw new LDAPException(PROTOCOL_ERROR, message, e);
216 }
217
218
219 int numElements = elements.size();
220 if ((numElements < 1) || (numElements > 3))
221 {
222 Message message =
223 ERR_LDAP_CONTROL_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
224 throw new LDAPException(PROTOCOL_ERROR, message);
225 }
226
227
228 String oid;
229 try
230 {
231 oid = elements.get(0).decodeAsOctetString().stringValue();
232 }
233 catch (Exception e)
234 {
235 if (debugEnabled())
236 {
237 TRACER.debugCaught(DebugLogLevel.ERROR, e);
238 }
239
240 Message message = ERR_LDAP_CONTROL_DECODE_OID.get(String.valueOf(e));
241 throw new LDAPException(PROTOCOL_ERROR, message, e);
242 }
243
244
245 if (numElements == 1)
246 {
247 return new LDAPControl(oid);
248 }
249 else if (numElements == 2)
250 {
251 boolean isCritical;
252 ASN1OctetString value;
253
254 ASN1Element e = elements.get(1);
255 switch (e.getType())
256 {
257 case UNIVERSAL_BOOLEAN_TYPE:
258 value = null;
259
260 try
261 {
262 isCritical = e.decodeAsBoolean().booleanValue();
263 }
264 catch (Exception e2)
265 {
266 if (debugEnabled())
267 {
268 TRACER.debugCaught(DebugLogLevel.ERROR, e2);
269 }
270
271 Message message =
272 ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e));
273 throw new LDAPException(PROTOCOL_ERROR, message, e2);
274 }
275 break;
276 case UNIVERSAL_OCTET_STRING_TYPE:
277 isCritical = false;
278
279 try
280 {
281 value = e.decodeAsOctetString();
282 }
283 catch (Exception e2)
284 {
285 if (debugEnabled())
286 {
287 TRACER.debugCaught(DebugLogLevel.ERROR, e2);
288 }
289
290 Message message =
291 ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e));
292 throw new LDAPException(PROTOCOL_ERROR, message, e2);
293 }
294 break;
295 default:
296 Message message =
297 ERR_LDAP_CONTROL_DECODE_INVALID_TYPE.get(e.getType());
298 throw new LDAPException(PROTOCOL_ERROR, message);
299 }
300
301 return new LDAPControl(oid, isCritical, value);
302 }
303 else
304 {
305 boolean isCritical;
306 try
307 {
308 isCritical = elements.get(1).decodeAsBoolean().booleanValue();
309 }
310 catch (Exception e)
311 {
312 if (debugEnabled())
313 {
314 TRACER.debugCaught(DebugLogLevel.ERROR, e);
315 }
316
317 Message message =
318 ERR_LDAP_CONTROL_DECODE_CRITICALITY.get(String.valueOf(e));
319 throw new LDAPException(PROTOCOL_ERROR, message, e);
320 }
321
322 ASN1OctetString value;
323 try
324 {
325 value = elements.get(2).decodeAsOctetString();
326 }
327 catch (Exception e)
328 {
329 if (debugEnabled())
330 {
331 TRACER.debugCaught(DebugLogLevel.ERROR, e);
332 }
333
334 Message message = ERR_LDAP_CONTROL_DECODE_VALUE.get(String.valueOf(e));
335 throw new LDAPException(PROTOCOL_ERROR, message, e);
336 }
337
338 return new LDAPControl(oid, isCritical, value);
339 }
340 }
341
342
343
344 /**
345 * Decodes the provided ASN.1 element as a set of controls.
346 *
347 * @param element The ASN.1 element containing the encoded set of controls.
348 *
349 * @return The decoded set of controls.
350 *
351 * @throws LDAPException If a problem occurs while attempting to decode the
352 * controls.
353 */
354 public static ArrayList<LDAPControl> decodeControls(ASN1Element element)
355 throws LDAPException
356 {
357 if (element == null)
358 {
359 Message message = ERR_LDAP_CONTROL_DECODE_CONTROLS_NULL.get();
360 throw new LDAPException(PROTOCOL_ERROR, message);
361 }
362
363
364 ArrayList<ASN1Element> elements;
365 try
366 {
367 elements = element.decodeAsSequence().elements();
368 }
369 catch (Exception e)
370 {
371 Message message =
372 ERR_LDAP_CONTROL_DECODE_CONTROLS_SEQUENCE.get(String.valueOf(e));
373 throw new LDAPException(PROTOCOL_ERROR, message, e);
374 }
375
376
377 ArrayList<LDAPControl> controls =
378 new ArrayList<LDAPControl>(elements.size());
379 for (ASN1Element e : elements)
380 {
381 controls.add(decode(e));
382 }
383
384 return controls;
385 }
386
387
388
389 /**
390 * Retrieves the OID for this control.
391 *
392 * @return The OID for this control.
393 */
394 public String getOID()
395 {
396 return control.getOID();
397 }
398
399
400
401 /**
402 * Indicates whether this control should be considered critical.
403 *
404 * @return <CODE>true</CODE> if this control should be considered critical,
405 * or <CODE>false</CODE> if not.
406 */
407 public boolean isCritical()
408 {
409 return control.isCritical();
410 }
411
412
413
414 /**
415 * Retrieves the value for this control.
416 *
417 * @return The value for this control, or <CODE>null</CODE> if there is none.
418 */
419 public ASN1OctetString getValue()
420 {
421 return control.getValue();
422 }
423
424
425
426 /**
427 * Retrieves a string representation of this LDAP control.
428 *
429 * @return A string representation of this LDAP control.
430 */
431 public String toString()
432 {
433 StringBuilder buffer = new StringBuilder();
434 toString(buffer);
435 return buffer.toString();
436 }
437
438
439
440 /**
441 * Appends a string representation of this LDAP control to the provided
442 * buffer.
443 *
444 * @param buffer The buffer to which the information should be appended.
445 */
446 public void toString(StringBuilder buffer)
447 {
448 buffer.append("LDAPControl(oid=");
449 buffer.append(control.getOID());
450 buffer.append(", criticality=");
451 buffer.append(control.isCritical());
452
453 ASN1OctetString value = control.getValue();
454 if (value != null)
455 {
456 buffer.append(", value=");
457 buffer.append(String.valueOf(value));
458 }
459
460 buffer.append(")");
461 }
462
463
464
465 /**
466 * Appends a multi-line string representation of this LDAP control to the
467 * provided buffer.
468 *
469 * @param buffer The buffer to which the information should be appended.
470 * @param indent The number of spaces to indent the information.
471 */
472 public void toString(StringBuilder buffer, int indent)
473 {
474 StringBuilder indentBuf = new StringBuilder(indent);
475 for (int i=0 ; i < indent; i++)
476 {
477 indentBuf.append(' ');
478 }
479
480 buffer.append(indentBuf);
481 buffer.append("LDAP Control");
482 buffer.append(EOL);
483
484 buffer.append(indentBuf);
485 buffer.append(" OID: ");
486 buffer.append(control.getOID());
487 buffer.append(EOL);
488
489 buffer.append(indentBuf);
490 buffer.append(" Criticality: ");
491 buffer.append(control.isCritical());
492 buffer.append(EOL);
493
494 ASN1OctetString value = control.getValue();
495 if (value != null)
496 {
497 buffer.append(indentBuf);
498 buffer.append(" Value:");
499 value.toString(buffer, indent+4);
500 }
501 }
502 }
503