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 2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014 ForgeRock AS
026 */
027
028package org.opends.server.tools;
029
030import java.io.Closeable;
031import java.io.IOException;
032import java.net.Socket;
033
034import org.forgerock.i18n.slf4j.LocalizedLogger;
035import org.forgerock.opendj.io.ASN1;
036import org.forgerock.opendj.io.ASN1Reader;
037import org.forgerock.opendj.ldap.ByteString;
038import org.forgerock.opendj.ldap.DecodeException;
039import org.opends.server.protocols.ldap.LDAPMessage;
040import org.opends.server.types.LDAPException;
041import org.opends.server.types.RecordingInputStream;
042import org.opends.server.util.ServerConstants;
043import org.opends.server.util.StaticUtils;
044
045/**
046 * This class defines a utility that can be used to read LDAP messages from a
047 * provided socket.
048 */
049public class LDAPReader implements Closeable
050{
051  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
052
053  private Socket socket;
054  private ASN1Reader asn1Reader;
055  private RecordingInputStream debugInputStream;
056
057  /**
058   * Creates a new LDAP reader that will read messages from the provided
059   * socket and trace the messages using a provided tracer.
060   *
061   * @param  socket   The socket from which to read the LDAP messages.
062   *
063   * @throws  IOException  If a problem occurs while attempting to obtain an
064   *                       input stream for the socket.
065   */
066  public LDAPReader(Socket socket)
067       throws IOException
068  {
069    this.socket = socket;
070    this.debugInputStream = new RecordingInputStream(socket.getInputStream());
071    this.asn1Reader = ASN1.getReader(debugInputStream);
072  }
073
074  /**
075   * Reads an LDAP message from the associated input stream.
076   *
077   * @return  The LDAP message read from the associated input stream, or
078   *          <CODE>null</CODE> if the end of the stream has been reached.
079   *
080   * @throws  IOException  If a problem occurs while attempting to read from the
081   *                       input stream.
082   *
083   * @throws  DecodeException  If a problem occurs while attempting to decode the
084   *                         data read as an ASN.1 sequence.
085
086   * @throws  LDAPException  If a problem occurs while attempting to decode the
087   *                         LDAP message.
088   */
089  public LDAPMessage readMessage()
090       throws IOException, DecodeException, LDAPException
091  {
092    debugInputStream.setRecordingEnabled(logger.isTraceEnabled());
093
094    if(!asn1Reader.hasNextElement())
095    {
096      // EOF was reached...
097      return null;
098    }
099
100    LDAPMessage message =
101        org.opends.server.protocols.ldap.LDAPReader.readMessage(asn1Reader);
102
103    if(debugInputStream.isRecordingEnabled())
104    {
105      ByteString bytesRead = debugInputStream.getRecordedBytes();
106      debugInputStream.clearRecordedBytes();
107
108      logger.trace("bytes read from wire(len=" + bytesRead.length() + "):"
109          + ServerConstants.EOL + bytesRead.toHexPlusAsciiString(4));
110      logger.trace(message.toString());
111    }
112
113    return message;
114  }
115
116  /**
117   * Closes this LDAP reader and the underlying socket.
118   */
119  @Override
120  public void close()
121  {
122    StaticUtils.close(asn1Reader);
123    StaticUtils.close(socket);
124  }
125}