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-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.server.protocols.ldap;
018
019
020import java.util.ArrayList;
021import java.util.Iterator;
022import java.util.List;
023import java.io.IOException;
024
025import org.opends.server.api.ProtocolElement;
026import org.forgerock.opendj.io.*;
027import org.opends.server.types.Control;
028
029import static org.opends.server.protocols.ldap.LDAPConstants.
030    TYPE_CONTROL_SEQUENCE;
031import static org.opends.server.util.ServerConstants.*;
032
033
034/**
035 * This class defines the data structures and methods to use when interacting
036 * with an LDAP message, which is the basic envelope used to hold LDAP requests
037 * and responses.
038 */
039public class LDAPMessage
040       implements ProtocolElement
041{
042  /** The set of controls for this LDAP message. */
043  private List<Control> controls;
044
045  /** The message ID for this LDAP message. */
046  private final int messageID;
047
048  /** The protocol op for this LDAP message. */
049  private final ProtocolOp protocolOp;
050
051
052
053  /**
054   * Creates a new LDAP message with the provided message ID and protocol op but
055   * no controls.
056   *
057   * @param  messageID   The message ID for this LDAP message.
058   * @param  protocolOp  The protocol op for this LDAP message.
059   */
060  public LDAPMessage(int messageID, ProtocolOp protocolOp)
061  {
062    this(messageID, protocolOp, null);
063  }
064
065
066
067  /**
068   * Creates a new LDAP message with the provided message ID, protocol op, and
069   * set of controls.
070   *
071   * @param  messageID   The message ID for this LDAP message.
072   * @param  protocolOp  The protocol op for this LDAP message.
073   * @param  controls    The set of controls for this LDAP message.
074   */
075  public LDAPMessage(int messageID, ProtocolOp protocolOp,
076                     List<Control> controls)
077  {
078    this.messageID  = messageID;
079    this.protocolOp = protocolOp;
080    this.controls = controls;
081  }
082
083
084
085  /**
086   * Retrieves the message ID for this LDAP message.
087   *
088   * @return  The message ID for this LDAP message.
089   */
090  public int getMessageID()
091  {
092    return messageID;
093  }
094
095
096
097  /**
098   * Retrieves the protocol op for this LDAP message.
099   *
100   * @return  The protocol op for this LDAP message.
101   */
102  public ProtocolOp getProtocolOp()
103  {
104    return protocolOp;
105  }
106
107
108
109  /**
110   * Retrieves the protocol op type for this LDAP message.
111   *
112   * @return  The protocol op type for this LDAP message.
113   */
114  public byte getProtocolOpType()
115  {
116    return protocolOp.getType();
117  }
118
119
120
121  /**
122   * Retrieves the protocol op name for this LDAP message.
123   *
124   * @return  The protocol op name for this LDAP message.
125   */
126  public String getProtocolOpName()
127  {
128    return protocolOp.getProtocolOpName();
129  }
130
131
132
133  /**
134   * Retrieves the protocol op for this LDAP message as an abandon request
135   * protocol op.
136   *
137   * @return  The protocol op for this LDAP message as an abandon request
138   *          protocol op.
139   *
140   * @throws  ClassCastException  If the protocol op is not an abandon request
141   *                              protocol op.
142   */
143  public AbandonRequestProtocolOp getAbandonRequestProtocolOp()
144         throws ClassCastException
145  {
146    return (AbandonRequestProtocolOp) protocolOp;
147  }
148
149
150
151  /**
152   * Retrieves the protocol op for this LDAP message as an add request protocol
153   * op.
154   *
155   * @return  The protocol op for this LDAP message as an add request protocol
156   *          op.
157   *
158   * @throws  ClassCastException  If the protocol op is not an add request
159   *                              protocol op.
160   */
161  public AddRequestProtocolOp getAddRequestProtocolOp()
162         throws ClassCastException
163  {
164    return (AddRequestProtocolOp) protocolOp;
165  }
166
167
168
169  /**
170   * Retrieves the protocol op for this LDAP message as an add response protocol
171   * op.
172   *
173   * @return  The protocol op for this LDAP message as an add response protocol
174   *          op.
175   *
176   * @throws  ClassCastException  If the protocol op is not an add response
177   *                              protocol op.
178   */
179  public AddResponseProtocolOp getAddResponseProtocolOp()
180         throws ClassCastException
181  {
182    return (AddResponseProtocolOp) protocolOp;
183  }
184
185
186
187  /**
188   * Retrieves the protocol op for this LDAP message as a bind request
189   * protocol op.
190   *
191   * @return  The protocol op for this LDAP message as a bind request
192   *          protocol op.
193   *
194   * @throws  ClassCastException  If the protocol op is not a bind request
195   *                              protocol op.
196   */
197  public BindRequestProtocolOp getBindRequestProtocolOp()
198         throws ClassCastException
199  {
200    return (BindRequestProtocolOp) protocolOp;
201  }
202
203
204
205  /**
206   * Retrieves the protocol op for this LDAP message as a bind response
207   * protocol op.
208   *
209   * @return  The protocol op for this LDAP message as a bind response
210   *          protocol op.
211   *
212   * @throws  ClassCastException  If the protocol op is not a bind response
213   *                              protocol op.
214   */
215  public BindResponseProtocolOp getBindResponseProtocolOp()
216         throws ClassCastException
217  {
218    return (BindResponseProtocolOp) protocolOp;
219  }
220
221
222
223  /**
224   * Retrieves the protocol op for this LDAP message as a compare request
225   * protocol op.
226   *
227   * @return  The protocol op for this LDAP message as a compare request
228   *          protocol op.
229   *
230   * @throws  ClassCastException  If the protocol op is not a compare request
231   *                              protocol op.
232   */
233  public CompareRequestProtocolOp getCompareRequestProtocolOp()
234         throws ClassCastException
235  {
236    return (CompareRequestProtocolOp) protocolOp;
237  }
238
239
240
241  /**
242   * Retrieves the protocol op for this LDAP message as a compare response
243   * protocol op.
244   *
245   * @return  The protocol op for this LDAP message as a compare response
246   *          protocol op.
247   *
248   * @throws  ClassCastException  If the protocol op is not a compare response
249   *                              protocol op.
250   */
251  public CompareResponseProtocolOp getCompareResponseProtocolOp()
252         throws ClassCastException
253  {
254    return (CompareResponseProtocolOp) protocolOp;
255  }
256
257
258
259  /**
260   * Retrieves the protocol op for this LDAP message as a delete request
261   * protocol op.
262   *
263   * @return  The protocol op for this LDAP message as a delete request
264   *          protocol op.
265   *
266   * @throws  ClassCastException  If the protocol op is not a delete request
267   *                              protocol op.
268   */
269  public DeleteRequestProtocolOp getDeleteRequestProtocolOp()
270         throws ClassCastException
271  {
272    return (DeleteRequestProtocolOp) protocolOp;
273  }
274
275
276
277  /**
278   * Retrieves the protocol op for this LDAP message as a delete response
279   * protocol op.
280   *
281   * @return  The protocol op for this LDAP message as a delete response
282   *          protocol op.
283   *
284   * @throws  ClassCastException  If the protocol op is not a delete response
285   *                              protocol op.
286   */
287  public DeleteResponseProtocolOp getDeleteResponseProtocolOp()
288         throws ClassCastException
289  {
290    return (DeleteResponseProtocolOp) protocolOp;
291  }
292
293
294
295  /**
296   * Retrieves the protocol op for this LDAP message as an extended request
297   * protocol op.
298   *
299   * @return  The protocol op for this LDAP message as an extended request
300   *          protocol op.
301   *
302   * @throws  ClassCastException  If the protocol op is not an extended request
303   *                              protocol op.
304   */
305  public ExtendedRequestProtocolOp getExtendedRequestProtocolOp()
306         throws ClassCastException
307  {
308    return (ExtendedRequestProtocolOp) protocolOp;
309  }
310
311
312
313  /**
314   * Retrieves the protocol op for this LDAP message as an extended response
315   * protocol op.
316   *
317   * @return  The protocol op for this LDAP message as an extended response
318   *          protocol op.
319   *
320   * @throws  ClassCastException  If the protocol op is not an extended response
321   *                              protocol op.
322   */
323  public ExtendedResponseProtocolOp getExtendedResponseProtocolOp()
324         throws ClassCastException
325  {
326    return (ExtendedResponseProtocolOp) protocolOp;
327  }
328
329
330
331  /**
332   * Retrieves the protocol op for this LDAP message as a modify request
333   * protocol op.
334   *
335   * @return  The protocol op for this LDAP message as a modify request
336   *          protocol op.
337   *
338   * @throws  ClassCastException  If the protocol op is not a modify request
339   *                              protocol op.
340   */
341  public ModifyRequestProtocolOp getModifyRequestProtocolOp()
342         throws ClassCastException
343  {
344    return (ModifyRequestProtocolOp) protocolOp;
345  }
346
347
348
349  /**
350   * Retrieves the protocol op for this LDAP message as a modify response
351   * protocol op.
352   *
353   * @return  The protocol op for this LDAP message as a modify response
354   *          protocol op.
355   *
356   * @throws  ClassCastException  If the protocol op is not a modify response
357   *                              protocol op.
358   */
359  public ModifyResponseProtocolOp getModifyResponseProtocolOp()
360         throws ClassCastException
361  {
362    return (ModifyResponseProtocolOp) protocolOp;
363  }
364
365
366
367  /**
368   * Retrieves the protocol op for this LDAP message as a modify DN request
369   * protocol op.
370   *
371   * @return  The protocol op for this LDAP message as a modify DN request
372   *          protocol op.
373   *
374   * @throws  ClassCastException  If the protocol op is not a modify DN request
375   *                              protocol op.
376   */
377  public ModifyDNRequestProtocolOp getModifyDNRequestProtocolOp()
378         throws ClassCastException
379  {
380    return (ModifyDNRequestProtocolOp) protocolOp;
381  }
382
383
384
385  /**
386   * Retrieves the protocol op for this LDAP message as a modify DN response
387   * protocol op.
388   *
389   * @return  The protocol op for this LDAP message as a modify DN response
390   *          protocol op.
391   *
392   * @throws  ClassCastException  If the protocol op is not a modify DN response
393   *                              protocol op.
394   */
395  public ModifyDNResponseProtocolOp getModifyDNResponseProtocolOp()
396         throws ClassCastException
397  {
398    return (ModifyDNResponseProtocolOp) protocolOp;
399  }
400
401
402
403  /**
404   * Retrieves the protocol op for this LDAP message as a search request
405   * protocol op.
406   *
407   * @return  The protocol op for this LDAP message as a search request
408   *          protocol op.
409   *
410   * @throws  ClassCastException  If the protocol op is not a search request
411   *                              protocol op.
412   */
413  public SearchRequestProtocolOp getSearchRequestProtocolOp()
414         throws ClassCastException
415  {
416    return (SearchRequestProtocolOp) protocolOp;
417  }
418
419
420
421  /**
422   * Retrieves the protocol op for this LDAP message as a search result done
423   * protocol op.
424   *
425   * @return  The protocol op for this LDAP message as a search result done
426   *          protocol op.
427   *
428   * @throws  ClassCastException  If the protocol op is not a search result done
429   *                              protocol op.
430   */
431  public SearchResultDoneProtocolOp getSearchResultDoneProtocolOp()
432         throws ClassCastException
433  {
434    return (SearchResultDoneProtocolOp) protocolOp;
435  }
436
437
438
439  /**
440   * Retrieves the protocol op for this LDAP message as a search result entry
441   * protocol op.
442   *
443   * @return  The protocol op for this LDAP message as a search result entry
444   *          protocol op.
445   *
446   * @throws  ClassCastException  If the protocol op is not a search result
447   *                              entry protocol op.
448   */
449  public SearchResultEntryProtocolOp getSearchResultEntryProtocolOp()
450         throws ClassCastException
451  {
452    return (SearchResultEntryProtocolOp) protocolOp;
453  }
454
455
456
457  /**
458   * Retrieves the protocol op for this LDAP message as a search result
459   * reference protocol op.
460   *
461   * @return  The protocol op for this LDAP message as a search result reference
462   *          protocol op.
463   *
464   * @throws  ClassCastException  If the protocol op is not a search result
465   *                              reference protocol op.
466   */
467  public SearchResultReferenceProtocolOp getSearchResultReferenceProtocolOp()
468         throws ClassCastException
469  {
470    return (SearchResultReferenceProtocolOp) protocolOp;
471  }
472
473
474
475  /**
476   * Retrieves the protocol op for this LDAP message as an unbind request
477   * protocol op.
478   *
479   * @return  The protocol op for this LDAP message as an unbind request
480   *          protocol op.
481   *
482   * @throws  ClassCastException  If the protocol op is not an unbind request
483   *                              protocol op.
484   */
485  public UnbindRequestProtocolOp getUnbindRequestProtocolOp()
486         throws ClassCastException
487  {
488    return (UnbindRequestProtocolOp) protocolOp;
489  }
490
491
492
493  /**
494   * Retrieves the set of controls for this LDAP message.  It may be modified by
495   * the caller.
496   *
497   * @return  The set of controls for this LDAP message.
498   */
499  public List<Control> getControls()
500  {
501    // This method is not thread-safe.
502    if (controls == null)
503    {
504      controls = new ArrayList<>(0);
505    }
506    return controls;
507  }
508
509  /**
510   * Writes this protocol op to an ASN.1 output stream.
511   *
512   * @param stream The ASN.1 output stream to write to.
513   * @throws IOException If a problem occurs while writing to the stream.
514   */
515  public void write(ASN1Writer stream) throws IOException
516  {
517    stream.writeStartSequence();
518    stream.writeInteger(messageID);
519    protocolOp.write(stream);
520
521    if(controls != null && !controls.isEmpty())
522    {
523      stream.writeStartSequence(TYPE_CONTROL_SEQUENCE);
524      for(Control control : controls)
525      {
526        control.write(stream);
527      }
528      stream.writeEndSequence();
529    }
530
531    stream.writeEndSequence();
532  }
533
534
535
536  /**
537   * Retrieves the name of the protocol associated with this protocol element.
538   *
539   * @return  The name of the protocol associated with this protocol element.
540   */
541  @Override
542  public String getProtocolElementName()
543  {
544    return "LDAP";
545  }
546
547
548
549  /**
550   * Retrieves a string representation of this LDAP message.
551   *
552   * @return  A string representation of this LDAP message.
553   */
554  @Override
555  public String toString()
556  {
557    StringBuilder buffer = new StringBuilder();
558    toString(buffer);
559    return buffer.toString();
560  }
561
562
563
564  /**
565   * Appends a string representation of this protocol element to the provided
566   * buffer.
567   *
568   * @param  buffer  The buffer into which the string representation should be
569   *                 written.
570   */
571  @Override
572  public void toString(StringBuilder buffer)
573  {
574    buffer.append("LDAPMessage(msgID=");
575    buffer.append(messageID);
576    buffer.append(", protocolOp=");
577    if (protocolOp != null) {
578      protocolOp.toString(buffer);
579    } else {
580      buffer.append("null");
581    }
582
583    if (controls != null && !controls.isEmpty())
584    {
585      buffer.append(", controls={ ");
586
587      Iterator<Control> iterator = controls.iterator();
588      iterator.next().toString(buffer);
589
590      while (iterator.hasNext())
591      {
592        buffer.append(", ");
593        iterator.next().toString(buffer);
594      }
595
596      buffer.append(" }");
597    }
598
599    buffer.append(")");
600  }
601
602
603
604  /**
605   * Appends a string representation of this protocol element to the provided
606   * buffer.
607   *
608   * @param  buffer  The buffer into which the string representation should be
609   *                 written.
610   * @param  indent  The number of spaces that should be used to indent the
611   *                 resulting string representation.
612   */
613  @Override
614  public void toString(StringBuilder buffer, int indent)
615  {
616    StringBuilder indentBuf = new StringBuilder(indent);
617    for (int i=0 ; i < indent; i++)
618    {
619      indentBuf.append(' ');
620    }
621
622    buffer.append(indentBuf);
623    buffer.append("LDAP LocalizableMessage");
624    buffer.append(EOL);
625
626    buffer.append(indentBuf);
627    buffer.append("  LocalizableMessage ID:  ");
628    buffer.append(messageID);
629    buffer.append(EOL);
630
631    buffer.append(indentBuf);
632    buffer.append("  Protocol Op:");
633    buffer.append(EOL);
634    protocolOp.toString(buffer, indent+4);
635
636    if (controls != null && !controls.isEmpty())
637    {
638      buffer.append(indentBuf);
639      buffer.append("  Controls:");
640
641      for (Control c : controls)
642      {
643        // TODO: Indent
644        c.toString(buffer);//, indent+4);
645      }
646    }
647  }
648}
649