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