/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ package netscape.ldap.controls; import java.io.*; import netscape.ldap.client.JDAPBERTagDecoder; import netscape.ldap.LDAPControl; import netscape.ldap.ber.stream.*; /** * Represents an LDAP v3 server control that specifies a persistent * search (an ongoing search operation), which allows your LDAP client * to get notification of changes to the directory. (The OID for this * control is 2.16.840.1.113730.3.4.3.) You can use this control in * conjunction with an "entry change notification" control (represented * by LDAPEntryChangeControl object. *

* * To use persistent searching for change notification, you create a * "persistent search" control that specifies the types of changes that * you want to track. You include the control in a search request. * If an entry in the directory is changed, the server determines if * the entry matches the search criteria in your request and if the * change is the type of change that you are tracking. If both of * these are true, the server sends the entry to your client. *

* * The server can also include an "entry change notification" control * with the entry. (The OID for this control is 2.16.840.1.113730.3.4.7.) * This control contains additional information about the * change made to the entry, including the type of change made, * the change number (which corresponds to an item in the server's * change log, if the server supports a change log), and, if the * entry was renamed, the old DN of the entry. *

* * When constructing an LDAPPersistSearchControl object, * you can specify the following information: *

* *

*

* * For example: *

 * ...
 * LDAPConnection ld = new LDAPConnection();
 *
 * try {
 *     // Connect to server.
 *     ld.connect( 3, hostname, portnumber, "", "" );
 *
 *     // Create a persistent search control.
 *     int op = LDAPPersistSearchControl.ADD |
 *         LDAPPersistSearchControl.MODIFY |
 *         LDAPPersistSearchControl.DELETE |
 *         LDAPPersistSearchControl.MODDN;
 *     boolean changesOnly = true;
 *     boolean returnControls = true;
 *     boolean isCritical = true;
 *     LDAPPersistSearchControl persistCtrl = new
 *         LDAPPersistSearchControl( op, changesOnly,
 *         returnControls, isCritical );
 *
 *     // Set the search constraints to use that control.
 *     LDAPSearchConstraints cons = ld.getSearchConstraints();
 *     cons.setBatchSize( 1 );
 *     cons.setServerControls( persistCtrl );
 *
 *     // Start the persistent search.
 *     LDAPSearchResults res = ld.search( "o=Airius.com",
 *               LDAPv3.SCOPE_SUB, "(cn=Barbara*)", null, false, cons );
 *
 *     // Loop through the incoming results.
 *     while ( res.hasMoreElements() ) {
 *     ...
 *     }
 * ...
 * }
 * 
* * @see netscape.ldap.LDAPControl * @see netscape.ldap.controls.LDAPEntryChangeControl */ public class LDAPPersistSearchControl extends LDAPControl { /** * Default constructor */ public LDAPPersistSearchControl() { super(PERSISTENTSEARCH, true, null); } /** * Constructs an LDAPPersistSearchControl object * that specifies a persistent search. * * @param changeTypes the change types to monitor. You can perform * a bitwise OR on any of the following values and specify the result as * the change types: * * @param changesOnly true if you do not want the server * to return all existing entries in the directory that match the * search criteria. (Use this if you just want the changed entries * to be returned.) * @param returnControls true if you want the server to return * entry change controls with each entry in the search results * @param isCritical true if this control is critical to * the search operation. (If the server does not support * this control, you may not want the server to perform the search * at all.) * @see netscape.ldap.LDAPControl * @see netscape.ldap.controls.LDAPEntryChangeControl */ public LDAPPersistSearchControl(int changeTypes, boolean changesOnly, boolean returnControls, boolean isCritical) { super(PERSISTENTSEARCH, isCritical, null); m_value = createPersistSearchSpecification(changeTypes, changesOnly, returnControls); m_changeTypes = changeTypes; m_changesOnly = changesOnly; m_returnECs = returnControls; } /** * Gets the change types monitored by this control. * @return integer representing the change types to monitor. * This value can be the bitwise OR of ADD, DELETE, MODIFY, * and/or MODDN. If the change type is unknown, * this method returns -1. * @see netscape.ldap.controls.LDAPPersistSearchControl#setChangeTypes */ public int getChangeTypes() { return m_changeTypes; } /** * Indicates whether you want the server to send any existing * entries that already match the search criteria or only the * entries that have changed. * @return if true, the server returns only the * entries that have changed. If false, the server * also returns any existing entries that match the search criteria * but have not changed. * @see netscape.ldap.controls.LDAPPersistSearchControl#setChangesOnly */ public boolean getChangesOnly() { return m_changesOnly; } /** * Indicates whether or not the server includes an "entry change * notification" control with each entry it sends back to the client * during the persistent search. * @return true if the server includes "entry change * notification" controls with the entries it sends during the * persistent search. * @see netscape.ldap.controls.LDAPEntryChangeControl * @see netscape.ldap.controls.LDAPPersistSearchControl#setReturnControls */ public boolean getReturnControls() { return m_returnECs; } /** * Sets the change types that you want monitored by this control. * @param types integer representing the change types to monitor * This value can be the bitwise OR of ADD, DELETE, MODIFY, * and/or MODDN. * @see netscape.ldap.controls.LDAPPersistSearchControl#getChangeTypes */ public void setChangeTypes(int types) { m_changeTypes = types; } /** * Specifies whether you want the server to send any existing * entries that already match the search criteria or only the * entries that have changed. * @param changesOnly if true, the server returns only the * entries that have changed. If false, the server * also returns any existing entries that match the search criteria * but have not changed. * @see netscape.ldap.controls.LDAPPersistSearchControl#getChangesOnly */ public void setChangesOnly(boolean changesOnly) { m_changesOnly = changesOnly; } /** * Specifies whether you want the server to include an "entry change * notification" control with each entry it sends back to the client * during the persistent search. * @param returnControls if true, the server includes * "entry change notification" controls with the entries it sends * during the persistent search * @see netscape.ldap.controls.LDAPEntryChangeControl * @see netscape.ldap.controls.LDAPPersistSearchControl#setReturnControls */ public void setReturnControls(boolean returnControls) { m_returnECs = returnControls; } /** * Takes an input byte array and extracts the ber elements, assigning * them to appropriate fields in the entry change control. * * @param c byte array that contains BER elements * @return the entry change control. * @deprecated LDAPEntryChangeControl controls are now automatically * instantiated. */ public LDAPEntryChangeControl parseResponse(byte[] c) { LDAPEntryChangeControl con = new LDAPEntryChangeControl(); ByteArrayInputStream inStream = new ByteArrayInputStream(c); BERSequence seq = new BERSequence(); JDAPBERTagDecoder decoder = new JDAPBERTagDecoder(); int[] numRead = new int[1]; numRead[0] = 0; try { /* a sequence */ BERSequence s = (BERSequence)BERElement.getElement(decoder, inStream, numRead); BEREnumerated itr = (BEREnumerated)s.elementAt(0); con.setChangeType(itr.getValue()); if (s.size() > 1) { if (s.elementAt(1) instanceof BEROctetString) { BEROctetString str = (BEROctetString)s.elementAt(1); con.setPreviousDN(new String(str.getValue(), "UTF8")); } else if (s.elementAt(1) instanceof BERInteger) { BERInteger num = (BERInteger)s.elementAt(1); con.setChangeNumber(num.getValue()); } } if (s.size() > 2) { BERInteger num = (BERInteger)s.elementAt(2); con.setChangeNumber(num.getValue()); } } catch (Exception e) { return null; } return con; } /** * Returns an "entry change notification" control if the control is in * the specified array of controls. Use this method to retrieve an "entry * change notification" control included with an entry sent by the server. *

* * You can get the controls returned by the server by using the * getResponseControls method of the * LDAPConnection class. *

* * For example: *

     * ...
     * LDAPConnection ld = new LDAPConnection();
     * try {
     *     // Connect to the server, set up the persistent search control,
     *     // and set up the search constraints.
     *     ...
     *
     *     // Search the directory.
     *     LDAPSearchResults res = ld.search( "o=Airius.com",
     *         LDAPv3.SCOPE_SUB, "(cn=Barbara*)", attrs, false, cons );
     *
     *     // Determine if the server sent a control back to you.
     *     LDAPControl[] returnedControls = ld.getResponseControls();
     *     if ( returnedControls != null ) {
     *
     *         // Get the entry change control.
     *         LDAPEntryChangeControl entryCtrl = null;
     *         for ( int i = 0; i < returnedControls.length; i++ ) {
     *             if ( returnedControls[i] instanceof LDAPEntryChangeControl ) {
     *                 entryCtrl = (LDAPEntryChangeControl)returnedControls[i];
     *                 break;
     *             }
     *         }
     *         if ( entryCtrl != null ) {
     *
     *             // Get and print the type of change made to the entry.
     *             int changeType = entryCtrl.getChangeType();
     *             if ( changeType != -1 ) {
     *                 System.out.print( "Change made: " );
     *                 switch ( changeType ) {
     *                 case LDAPPersistSearchControl.ADD:
     *                     System.out.println( "Added new entry." );
     *             break;
     *                 case LDAPPersistSearchControl.MODIFY:
     *                     System.out.println( "Modified entry." );
     *             break;
     *                 case LDAPPersistSearchControl.DELETE:
     *                     System.out.println( "Deleted entry." );
     *             break;
     *                 case LDAPPersistSearchControl.MODDN:
     *                     System.out.println( "Renamed entry." );
     *             break;
     *                 }
     *             }
     *
     *             // Get and print the change number corresponding
     *             // to the change.
     *             int changeNumber = entryCtrl.getChangeNumber();
     *             if ( changeNumber != -1 )
     *                 System.out.println( "Change log number: " + changeNumber);
     *
     *             // Get and print the previous DN of the entry,
     *             // if the entry was renamed.
     *             LDAPDN oldDN = entryCtrl.getPreviousDN();
     *             if ( oldDN != null )
     *                     System.out.println( "Previous DN: " + oldDN );
     *
     *         } else {
     *
     *             System.out.println( "No entry change control." );
     *         }
     *     }
     *     ...
     * }
     * ...
     *
     * 
* * @param controls an array of LDAPControl objects, * representing the controls returned by the server * with an entry. To get these controls, use the * getResponseControls method of the * LDAPConnection class. * @return an LDAPEntryChangeControl object representing * the entry change control sent by the server. If no entry change * control was sent, this method returns null. * @see netscape.ldap.controls.LDAPEntryChangeControl * @see netscape.ldap.LDAPConnection#getResponseControls * @deprecated LDAPEntryChangeControl controls are now automatically * instantiated. */ public static LDAPEntryChangeControl parseResponse(LDAPControl[] controls) { LDAPPersistSearchControl con = new LDAPPersistSearchControl(); for (int i=0; (controls != null) && (i < controls.length); i++) { // get the entry change control if (controls[i].getID().equals(LDAPEntryChangeControl.ENTRYCHANGED)) { return con.parseResponse(controls[i].getValue()); } } return null; } /** * Creates a "flattened" BER encoding of the persistent search * specifications and returns it as a byte array. * @param changeTypes the change types to monitor on the server * @param changesOnly true to skip the initial search * @param returnECs true if entry change controls are to be * returned with the search results * @return the BER-encoded data. */ private byte[] createPersistSearchSpecification(int changeTypes, boolean changesOnly, boolean returnECs) { /* A sequence */ BERSequence seq = new BERSequence(); seq.addElement(new BERInteger(changeTypes)); seq.addElement(new BERBoolean(changesOnly)); seq.addElement(new BERBoolean(returnECs)); /* return a byte array */ return flattenBER( seq ); } public String toString() { StringBuffer sb = new StringBuffer("{PersistSearchCtrl:"); sb.append(" isCritical="); sb.append(isCritical()); sb.append(" returnEntryChangeCtrls="); sb.append(m_returnECs); sb.append(" changesOnly="); sb.append(m_changesOnly); sb.append(" changeTypes="); sb.append(typesToString(m_changeTypes)); sb.append("}"); return sb.toString(); } /** * This method is also used by LDAPentryChangeControl.toString() */ static String typesToString(int changeTypes) { String types = ""; if ((changeTypes & ADD) != 0) { types += (types.length() > 0) ? "+ADD" : "ADD"; } if ((changeTypes & DELETE) != 0) { types += (types.length() > 0) ? "+DEL" : "DEL"; } if ((changeTypes & MODIFY) != 0) { types += (types.length() > 0) ? "+MOD" : "MOD"; } if ((changeTypes & MODDN) != 0) { types += (types.length() > 0) ? "+MODDN" : "MODDN"; } return types; } private int m_changeTypes = 1; private boolean m_changesOnly = false; private boolean m_returnECs = false; /** * Change type specifying that you want to track additions of new * entries to the directory. You can either specify this change type * when constructing an LDAPPersistSearchControl or * by using the setChangeTypes method. * @see netscape.ldap.controls.LDAPPersistSearchControl#getChangeTypes * @see netscape.ldap.controls.LDAPPersistSearchControl#setChangeTypes */ public static final int ADD = 1; /** * Change type specifying that you want to track removals of * entries from the directory. You can either specify this change type * when constructing an LDAPPersistSearchControl or * by using the setChangeTypes method. * @see netscape.ldap.controls.LDAPPersistSearchControl#getChangeTypes * @see netscape.ldap.controls.LDAPPersistSearchControl#setChangeTypes */ public static final int DELETE = 2; /** * Change type specifying that you want to track modifications of * entries in the directory. You can either specify this change type * when constructing an LDAPPersistSearchControl or * by using the setChangeTypes method. * @see netscape.ldap.controls.LDAPPersistSearchControl#getChangeTypes * @see netscape.ldap.controls.LDAPPersistSearchControl#setChangeTypes */ public static final int MODIFY = 4; /** * Change type specifying that you want to track modifications of the * DNs of entries in the directory. You can either specify this change type * when constructing an LDAPPersistSearchControl or * by using the setChangeTypes method. * @see netscape.ldap.controls.LDAPPersistSearchControl#getChangeTypes * @see netscape.ldap.controls.LDAPPersistSearchControl#setChangeTypes */ public static final int MODDN = 8; public final static String PERSISTENTSEARCH = "2.16.840.1.113730.3.4.3"; }