Package org.apache.directory.ldapstudio.dsmlv2.engine

Source Code of org.apache.directory.ldapstudio.dsmlv2.engine.Dsmlv2Engine

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*    http://www.apache.org/licenses/LICENSE-2.0
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*/

package org.apache.directory.ldapstudio.dsmlv2.engine;


import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

import javax.naming.NamingException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;

import org.apache.directory.ldapstudio.dsmlv2.Dsmlv2Parser;
import org.apache.directory.ldapstudio.dsmlv2.reponse.AddResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.AuthResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.CompareResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.DelResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.ErrorResponse;
import org.apache.directory.ldapstudio.dsmlv2.reponse.ExtendedResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.ModDNResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.ModifyResponseDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.SearchResultDoneDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.SearchResultEntryDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.SearchResultReferenceDsml;
import org.apache.directory.ldapstudio.dsmlv2.reponse.ErrorResponse.ErrorResponseType;
import org.apache.directory.ldapstudio.dsmlv2.request.BatchRequest;
import org.apache.directory.ldapstudio.dsmlv2.request.BatchRequest.OnError;
import org.apache.directory.ldapstudio.dsmlv2.request.BatchRequest.Processing;
import org.apache.directory.ldapstudio.dsmlv2.request.BatchRequest.ResponseOrder;
import org.apache.directory.shared.asn1.ber.Asn1Decoder;
import org.apache.directory.shared.asn1.ber.IAsn1Container;
import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
import org.apache.directory.shared.asn1.codec.DecoderException;
import org.apache.directory.shared.asn1.codec.EncoderException;
import org.apache.directory.shared.ldap.codec.LdapConstants;
import org.apache.directory.shared.ldap.codec.LdapDecoder;
import org.apache.directory.shared.ldap.codec.LdapMessage;
import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
import org.apache.directory.shared.ldap.codec.LdapResponse;
import org.apache.directory.shared.ldap.codec.bind.BindRequest;
import org.apache.directory.shared.ldap.codec.bind.BindResponse;
import org.apache.directory.shared.ldap.codec.bind.LdapAuthentication;
import org.apache.directory.shared.ldap.codec.bind.SimpleAuthentication;
import org.apache.directory.shared.ldap.codec.extended.ExtendedResponse;
import org.apache.directory.shared.ldap.message.ResultCodeEnum;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.util.StringTools;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
import org.xmlpull.v1.XmlPullParserException;


/**
* This is the DSMLv2Engine. It can be use to execute operations on a LDAP Server and get the results of these operations.
* The format used for request and responses is the DSMLv2 format.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$, $Date$
*/
public class Dsmlv2Engine
{
    /** Socket used to connect to the server */
    private SocketChannel channel;
    private SocketAddress serverAddress;

    // server configuration
    private int port;
    private String host;
    private String user;
    private String password;

    private Asn1Decoder ldapDecoder = new LdapDecoder();

    private IAsn1Container ldapMessageContainer = new LdapMessageContainer();

    private Dsmlv2Parser parser;

    private boolean continueOnError;
    private boolean exit = false;

    private int bbLimit;

    private int bbposition;
    private Document xmlResponse;
    private BatchRequest batchRequest;


    /**
     * Creates a new instance of Dsmlv2Engine.
     *
     * @param host
     *      the server host
     * @param port
     *      the server port
     * @param user
     *      the server admin DN
     * @param password
     *      the server admin's password
     */
    public Dsmlv2Engine( String host, int port, String user, String password )
    {
        this.host = host;
        this.port = port;
        this.user = user;
        this.password = password;
    }


    /**
     * Processes the file given and return the result of the operations
     *
     * @param dsmlInput
     *      the DSMLv2 formatted request input
     * @return
     *      the XML response in DSMLv2 Format
     * @throws XmlPullParserException
     *      if an error occurs in the parser
     */
    public String processDSML( String dsmlInput ) throws XmlPullParserException
    {
        parser = new Dsmlv2Parser();
        parser.setInput( dsmlInput );
        return processDSML();
    }


    /**
     * Processes the file given and return the result of the operations
     *
     * @param fileName
     *      the path to the file
     * @return
     *      the XML response in DSMLv2 Format
     * @throws XmlPullParserException
     *      if an error occurs in the parser
     * @throws FileNotFoundException
     *      if the file does not exist
     */
    public String processDSMLFile( String fileName ) throws XmlPullParserException, FileNotFoundException
    {
        parser = new Dsmlv2Parser();
        parser.setInputFile( fileName );
        return processDSML();
    }


    /**
     * Processes the file given and return the result of the operations
     *
     * @param inputStream
     *      contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null).
     * @param inputEncoding
     *      if not null it MUST be used as encoding for inputStream
     * @return
     *      the XML response in DSMLv2 Format
     * @throws XmlPullParserException
     *      if an error occurs in the parser
     */
    public String processDSML( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
    {
        parser = new Dsmlv2Parser();
        parser.setInput( inputStream, inputEncoding );
        return processDSML();
    }


    /**
     * Processes the Request document
     *
     * @return
     *      the XML response in DSMLv2 Format
     */
    private String processDSML()
    {
        // Creating XML Document and root Element 'batchResponse'
        xmlResponse = DocumentHelper.createDocument();
        xmlResponse.addElement( "batchResponse" );

        // Binding to LDAP Server
        try
        {
            bind( 1 );
        }
        catch ( Exception e )
        {
            // Unable to connect to server
            // We create a new ErrorResponse and return the XML response.
            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.COULD_NOT_CONNECT, e.getMessage() );

            errorResponse.toDsml( xmlResponse.getRootElement() );
            return styleDocument( xmlResponse, "DSMLv2.xslt" ).asXML();
        }

        // Processing BatchRequest:
        //    - Parsing and Getting BatchRequest
        //    - Getting and registering options from BatchRequest
        try
        {
            processBatchRequest();
        }
        catch ( XmlPullParserException e )
        {
            // We create a new ErrorResponse and return the XML response.
            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, e.getMessage()
                + " - Line " + e.getLineNumber() + " - Column " + e.getColumnNumber() );

            errorResponse.toDsml( xmlResponse.getRootElement() );
            return styleDocument( xmlResponse, "DSMLv2.xslt" ).asXML();
        }

        // Processing each request:
        //    - Getting a new request
        //    - Checking if the request is well formed
        //    - Sending the request to the server
        //    - Getting and converting reponse(s) as XML
        //    - Looping until last request
        LdapMessage request = null;
        try
        {
            request = parser.getNextRequest();
        }
        catch ( XmlPullParserException e )
        {
            // We create a new ErrorResponse and return the XML response.
            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, e.getMessage()
                + " - Line " + e.getLineNumber() + " - Column " + e.getColumnNumber() );

            errorResponse.toDsml( xmlResponse.getRootElement() );
            return styleDocument( xmlResponse, "DSMLv2.xslt" ).asXML();
        }

        while ( request != null ) // (Request == null when there's no more request to process)
        {
            // Checking the request has a requestID attribute if Processing = Parallel and ResponseOrder = Unordered
            if ( ( batchRequest.getProcessing().equals( Processing.PARALLEL ) )
                && ( batchRequest.getResponseOrder().equals( ResponseOrder.UNORDERED ) )
                && ( request.getMessageId() == 0 ) )
            {
                // Then we have to send an errorResponse
                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST,
                    "A requestID must be specified to each request when Processing is Parallel and ReponseOrder is Unordered." );

                errorResponse.toDsml( xmlResponse.getRootElement() );
                return xmlResponse.asXML();
            }

            try
            {
                processRequest( request );
            }
            catch ( Exception e )
            {
                // We create a new ErrorResponse and return the XML response.
                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.GATEWAY_INTERNAL_ERROR,
                    "Internal Error: " + e.getMessage() );

                errorResponse.toDsml( xmlResponse.getRootElement() );
                return styleDocument( xmlResponse, "DSMLv2.xslt" ).asXML();
            }

            // Checking if we need to exit processing (if an error has ocurred if onError == Exit)
            if ( exit )
            {
                break;
            }

            // Getting next request
            try
            {
                request = parser.getNextRequest();
            }
            catch ( XmlPullParserException e )
            {
                // We create a new ErrorResponse and return the XML response.
                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, e.getMessage()
                    + " - Line " + e.getLineNumber() + " - Column " + e.getColumnNumber() );

                errorResponse.toDsml( xmlResponse.getRootElement() );
                return styleDocument( xmlResponse, "DSMLv2.xslt" ).asXML();
            }
        }

        return styleDocument( xmlResponse, "DSMLv2.xslt" ).asXML();
    }


    /**
     * Processes a single request
     *
     * @param request
     *      the request to process
     * @throws EncoderException
     * @throws IOException
     * @throws NamingException
     * @throws DecoderException
     */
    private void processRequest( LdapMessage request ) throws EncoderException, IOException, DecoderException, NamingException
    {
        LdapMessage message = new LdapMessage();

        message.setProtocolOP( request );

        message.setMessageId( request.getMessageId() );

        ByteBuffer bb = null;

        bb = message.encode( null );

        bb.flip();

        sendMessage( bb );

        bb.clear();
        bb.position( bb.capacity() );
        // Get the response
        LdapMessage response = null;

        response = readResponse( bb );

        if ( LdapConstants.ADD_RESPONSE == response.getMessageType() )
        {
            AddResponseDsml addResponseDsml = new AddResponseDsml( response );
            addResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( LdapConstants.BIND_RESPONSE == response.getMessageType() )
        {
            AuthResponseDsml authResponseDsml = new AuthResponseDsml( response );
            authResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( LdapConstants.COMPARE_RESPONSE == response.getMessageType() )
        {
            CompareResponseDsml authResponseDsml = new CompareResponseDsml( response );
            authResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( LdapConstants.DEL_RESPONSE == response.getMessageType() )
        {
            DelResponseDsml delResponseDsml = new DelResponseDsml( response );
            delResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( LdapConstants.MODIFY_RESPONSE == response.getMessageType() )
        {
            ModifyResponseDsml modifyResponseDsml = new ModifyResponseDsml( response );
            modifyResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( LdapConstants.MODIFYDN_RESPONSE == response.getMessageType() )
        {
            ModDNResponseDsml modDNResponseDsml = new ModDNResponseDsml( response );
            modDNResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( LdapConstants.EXTENDED_RESPONSE == response.getMessageType() )
        {
            ExtendedResponseDsml extendedResponseDsml = new ExtendedResponseDsml( response );
            extendedResponseDsml.toDsml( xmlResponse.getRootElement() );
        }
        else if ( ( LdapConstants.SEARCH_RESULT_ENTRY == response.getMessageType() )
            || ( LdapConstants.SEARCH_RESULT_REFERENCE == response.getMessageType() )
            || ( LdapConstants.SEARCH_RESULT_DONE == response.getMessageType() ) )
        {
            // A SearchResponse can contains multiple responses of 3 types:
            //     - 0 to n SearchResultEntry
            //     - O to n SearchResultReference
            //     - 1 (only) SearchResultDone
            // So we have to include those individual reponses in a "General" SearchResponse
            Element searchResponse = xmlResponse.getRootElement().addElement( "searchResponse" );

            // RequestID
            int requestID = response.getMessageId();
            if ( requestID != 0 )
            {
                searchResponse.addAttribute( "requestID", "" + requestID );
            }

            while ( LdapConstants.SEARCH_RESULT_DONE != response.getMessageType() )
            {
                if ( LdapConstants.SEARCH_RESULT_ENTRY == response.getMessageType() )
                {
                    SearchResultEntryDsml searchResultEntryDsml = new SearchResultEntryDsml( response );
                    searchResultEntryDsml.toDsml( searchResponse );
                }
                else if ( LdapConstants.SEARCH_RESULT_REFERENCE == response.getMessageType() )
                {
                    SearchResultReferenceDsml searchResultReferenceDsml = new SearchResultReferenceDsml( response );
                    searchResultReferenceDsml.toDsml( searchResponse );
                }

                response = readResponse( bb );
            }

            SearchResultDoneDsml searchResultDoneDsml = new SearchResultDoneDsml( response );
            searchResultDoneDsml.toDsml( searchResponse );
        }

        LdapResponse realResponse = response.getLdapResponse();

        if ( !continueOnError )
        {
            if ( ( realResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
                && ( realResponse.getLdapResult().getResultCode() != ResultCodeEnum.COMPARE_TRUE )
                && ( realResponse.getLdapResult().getResultCode() != ResultCodeEnum.COMPARE_FALSE )
                && ( realResponse.getLdapResult().getResultCode() != ResultCodeEnum.REFERRAL ) )
            {
                // Turning on Exit flag
                exit = true;
            }
        }

    }


    /**
     * Processes the BatchRequest
     * <ul>
     *     <li>Parsing and Getting BatchRequest</li>
     *     <li>Getting and registering options from BatchRequest</li>
     * </ul>
     *    
     * @throws XmlPullParserException
     *      if an error occurs in the parser
     */
    private void processBatchRequest() throws XmlPullParserException
    {
        // Parsing BatchRequest
        parser.parseBatchRequest();

        // Getting BatchRequest
        batchRequest = parser.getBatchRequest();

        if ( OnError.RESUME.equals( batchRequest.getOnError() ) )
        {
            continueOnError = true;
        }
        else if ( OnError.EXIT.equals( batchRequest.getOnError() ) )
        {
            continueOnError = false;
        }

        if ( batchRequest.getRequestID() != 0 )
        {
            xmlResponse.getRootElement().addAttribute( "requestID", "" + batchRequest.getRequestID() );
        }
    }


    /**
     * XML Pretty Printer XSLT Tranformation
     *
     * @param document
     *      the Dom4j Document
     * @param stylesheet
     *      the stylesheet to use
     * @return
     */
    public Document styleDocument( Document document, String stylesheet )
    {
        // load the transformer using JAXP
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = null;
        try
        {
            transformer = factory
                .newTransformer( new StreamSource( Dsmlv2Engine.class.getResourceAsStream( stylesheet ) ) );
        }
        catch ( TransformerConfigurationException e1 )
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        // now lets style the given document
        DocumentSource source = new DocumentSource( document );
        DocumentResult result = new DocumentResult();
        try
        {
            transformer.transform( source, result );
        }
        catch ( TransformerException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // return the transformed document
        Document transformedDoc = result.getDocument();
        return transformedDoc;
    }


    /**
     * Connect to the LDAP server through a socket and establish the Input and
     * Output Streams. All the required information for the connection should be
     * in the options from the command line, or the default values.
     *
     * @throws UnknownHostException
     *      if the hostname or the Address of server could not be found
     * @throws IOException
     *      if there was a error opening or establishing the socket
     */
    private void connect() throws UnknownHostException, IOException
    {
        serverAddress = new InetSocketAddress( host, port );
        channel = SocketChannel.open( serverAddress );
        channel.configureBlocking( true );
    }


    /**
     * Sends a message
     *
     * @param bb
     *      the message as a byte buffer
     * @throws IOException
     *      if the message could not be sent
     */
    private void sendMessage( ByteBuffer bb ) throws IOException
    {
        channel.write( bb );
        bb.clear();
    }


    /**
     * Reads the response to a request
     *
     * @param bb
     *      the response as a byte buffer
     * @return the response
     *      the response as a LDAP message
     * @throws IOException
     * @throws DecoderException
     * @throws NamingException
     */
    private LdapMessage readResponse( ByteBuffer bb ) throws IOException, DecoderException, NamingException
    {

        LdapMessage messageResp = null;

        if ( bb.hasRemaining() )
        {
            bb.position( bbposition );
            bb.limit( bbLimit );
            ldapDecoder.decode( bb, ldapMessageContainer );
            bbposition = bb.position();
            bbLimit = bb.limit();
        }
        bb.flip();
        while ( ldapMessageContainer.getState() != TLVStateEnum.PDU_DECODED )
        {

            int nbRead = channel.read( bb );

            if ( nbRead == -1 )
            {
                System.err.println( "fsdfsdfsdfsd" );
            }

            bb.flip();
            ldapDecoder.decode( bb, ldapMessageContainer );
            bbposition = bb.position();
            bbLimit = bb.limit();
            bb.flip();
        }

        messageResp = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage();

        if ( messageResp instanceof BindResponse )
        {
            BindResponse resp = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage().getBindResponse();

            if ( resp.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
            {
                System.err.println( "Error : " + resp.getLdapResult().getErrorMessage() );
            }
        }
        else if ( messageResp instanceof ExtendedResponse )
        {
            ExtendedResponse resp = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage()
                .getExtendedResponse();

            if ( resp.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
            {
                System.err.println( "Error : " + resp.getLdapResult().getErrorMessage() );
            }
        }

        ( ( LdapMessageContainer ) ldapMessageContainer ).clean();

        return messageResp;
    }


    /**
     * Binds to the ldap server
     *
     * @param messageId
     *      the message Id
     * @throws EncoderException
     * @throws DecoderException
     * @throws IOException
     * @throws NamingException
     */
    private void bind( int messageId ) throws EncoderException, DecoderException, IOException, NamingException
    {
        BindRequest bindRequest = new BindRequest();
        LdapMessage message = new LdapMessage();
        LdapAuthentication authentication = new SimpleAuthentication();
        ( ( SimpleAuthentication ) authentication ).setSimple( StringTools.getBytesUtf8( password ) );

        bindRequest.setAuthentication( authentication );
        bindRequest.setName( new LdapDN( user ) );
        bindRequest.setVersion( 3 );

        message.setProtocolOP( bindRequest );
        message.setMessageId( messageId );

        // Encode and send the bind request
        ByteBuffer bb = message.encode( null );
        bb.flip();

        connect();
        sendMessage( bb );

        bb.clear();

        bb.position( bb.limit() );

        readResponse( bb );
    }
}
TOP

Related Classes of org.apache.directory.ldapstudio.dsmlv2.engine.Dsmlv2Engine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.