/*******************************************************************************

 * $Novell: SearchPersist.java,v 1.11 2003/08/21 11:46:07 $

 * Copyright (C) 1999, 2000, 2001 Novell, Inc. All Rights Reserved.

 *

 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND

 * TREATIES. USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE

 * AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS

 * THIS WORK. PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO

 * DEVELOPER A ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE

 * CODE IN ITS PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS

 * TO MARKET, DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF

 * DEVELOPER'S PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR

 * DEVELOPER'S CUSTOMERS WITH RESPECT TO THIS CODE.

 *

 * $name:         SearchPersist.java

 * $description:  The SearchPersist.java example shows how to perform a

 *                persistent search. The SearchPersist class performs a

 *                persistent search on the directory and receives notification

 *                of any changes to entries within the scope of the search's

 *                result set.

 ******************************************************************************/

import com.novell.ldap.*;

import com.novell.ldap.controls.*;

import java.io.IOException;

import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;



public class SearchPersist {



    static final String  QUIT_PROMPT =

                                  "\nMonitoring changes. Enter a 'q' to quit: ";



    public static void main(

        String[] args )

    {        

        if (args.length != 4) {

            System.err.println(

             "Usage:   java SearchPersist <host name> <login dn>" +

             " <password> <search base>");

            System.err.println(

             "Example: java SearchPersist Acme.com \"cn=admin,o=Acme\"" +

             " secret \"ou=sales,o=Acme\"");

            System.exit(0);

        }



        int ldapPort = LDAPConnection.DEFAULT_PORT;

        int ldapVersion  = LDAPConnection.LDAP_V3;        

        String ldapHost = args[0];

        String loginDN = args[1];

        String password = args[2];

        String searchBase = args[3];

        LDAPSearchQueue queue = null;

        LDAPSearchConstraints constraints;

        LDAPPersistSearchControl psCtrl;

        LDAPConnection lc = new LDAPConnection();

        constraints =  new LDAPSearchConstraints();



        try {

            // connect to the server

            lc.connect( ldapHost, ldapPort );

            // authenticate to the server

            lc.bind(ldapVersion, loginDN, password.getBytes("UTF8") );



            //Create the persistent search control

            psCtrl = new LDAPPersistSearchControl(

              LDAPPersistSearchControl.ANY, // any change

              true,                         //only get changes

              true,                         //return entry change controls

              true);                        //control is critcal



            // add the persistent search control to the search constraints

            constraints.setControls( psCtrl );



            // perform the search with no attributes returned

            String[] noAttrs = {LDAPConnection.NO_ATTRS};

            queue = lc.search(

               searchBase,                // container to search

               LDAPConnection.SCOPE_SUB,  // search container's subtree

               "(objectClass=*)",         // search filter, all objects

               noAttrs,                   // don't return attributes

               false,                     // return attrs and values, ignored

               null,                      // use default search queue

               constraints);              // use default search constraints

        }

        catch( LDAPException e ) {

            System.out.println( "Error: " + e.toString() );

            try { lc.disconnect(); } catch(LDAPException e2) {  }

            System.exit(1);

        }

        catch( UnsupportedEncodingException e ) {

            System.out.println( "Error: " + e.toString() );

        }



        // persistent search initiated without error, monitor the results

        // looping until the user quits by entering a 'q' or 'Q'



        BufferedReader in

            = new BufferedReader(new InputStreamReader(System.in));



        try {   //loop until the user quits by entering 'q' or 'Q'

            System.out.print(QUIT_PROMPT);

            String input;

            while (true) {

                if (in.ready()) {

                    input = in.readLine();

                    if ( input.startsWith("q") || input.startsWith("Q") )

                        break;

                    else

                        System.out.print(QUIT_PROMPT);

                }

                if (!checkForAChange(queue))

                    break;

                Thread.currentThread().sleep(10);

            }

        }

        catch (IOException e) {

            System.out.println(e.getMessage());

        }

        catch (InterruptedException e) {

        }



        //disconnect from the server before exiting

        try {

            lc.abandon(queue); //abandon the search

            lc.disconnect();

        }

        catch( LDAPException e ) {

            System.out.println();

            System.out.println( "Error: " + e.toString() );

        }



        System.exit(0);



    }// end main



    /**

     * Check the queue for a response. If a response has been received,

     * print the response information.

     */

    static private boolean checkForAChange(

        LDAPSearchQueue queue)

    {

        LDAPMessage message;

        boolean     result = true;



        try {

            //check if a response has been received so we don't block

            //when calling getResponse()

            if (queue.isResponseReceived()) {

                message = queue.getResponse();

                if (message != null) {

                    // is the response a search result reference?

                    if ( message instanceof LDAPSearchResultReference ) {

                        String urls[] =

                        ((LDAPSearchResultReference)message).getReferrals();

                        System.out.println("\nSearch result references:");

                        for ( int i = 0; i < urls.length; i++ )

                            System.out.println(urls[i]);

                        System.out.print(QUIT_PROMPT);

                    }

                    // is the response a search result?

                    else if ( message instanceof LDAPSearchResult ) {

                        LDAPControl[] controls = message.getControls();

                        for (int i = 0; i < controls.length; i++) {

                            if (controls[i] instanceof LDAPEntryChangeControl) {

                                LDAPEntryChangeControl ecCtrl =

                                 (LDAPEntryChangeControl)controls[i];



                                int changeType = ecCtrl.getChangeType();

                                System.out.println("\n\nchange type: " +

                                 getChangeTypeString(changeType));

                                if (changeType ==

                                    LDAPPersistSearchControl.MODDN)

                                    System.out.println("Prev. DN: " +

                                     ecCtrl.getPreviousDN());

                                if (ecCtrl.getHasChangeNumber())

                                    System.out.println("Change Number: " +

                                     ecCtrl.getChangeNumber());



                                LDAPEntry entry =

                                 ((LDAPSearchResult)message).getEntry();



                                System.out.println("entry: " + entry.getDN());

                                System.out.print(QUIT_PROMPT);

                            }

                        }

                    }

                    // the message is a search response

                    else {

                        LDAPResponse response = (LDAPResponse)message;

                        int resultCode = response.getResultCode();

                        if ( resultCode == LDAPException.SUCCESS ) {

                            System.out.println(

                             "\nUnexpected success response.");

                            result = false;

                        }

                        else if ( resultCode == LDAPException.REFERRAL ) {

                            String urls[] =

                             ((LDAPResponse)message).getReferrals();

                            System.out.println("\n\nReferrals:");

                            for ( int i = 0; i < urls.length; i++ )

                                System.out.println(urls[i]);

                            System.out.print(QUIT_PROMPT);

                        }

                        else {

                            System.out.println("Persistent search failed.");

                            throw new LDAPException( response.getErrorMessage(),

                                                     resultCode,

                                                     response.getMatchedDN() );

                        }

                    }

                }

            }

        }

        catch( LDAPException e ) {

            System.out.println( "Error: " + e.toString() );

            result = false;

        }



        return result;

    }



    /**

     * Return a string indicating the type of change represented by the

     * changeType parameter.

     */

    private static String getChangeTypeString(

        int changeType)

    {

        String changeTypeString;



        switch (changeType) {

            case LDAPPersistSearchControl.ADD:

                changeTypeString = "ADD";

                break;

            case LDAPPersistSearchControl.MODIFY:

                changeTypeString = "MODIFY";

                break;

            case LDAPPersistSearchControl.MODDN:

                changeTypeString = "MODDN";

                break;

            case LDAPPersistSearchControl.DELETE:

                changeTypeString = "DELETE";

                break;

            default:

                changeTypeString =

                 "Unknown change type: " + String.valueOf(changeType);

                break;

        }



        return changeTypeString;

    }



} //end class SearchPersist

