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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.replication.server;
028    
029    import org.opends.server.replication.common.ChangeNumber;
030    import org.opends.server.replication.protocol.UpdateMessage;
031    import org.opends.server.replication.server.ReplicationDB.ReplServerDBCursor;
032    
033    import com.sleepycat.je.DatabaseException;
034    
035    /**
036     * This class allows to iterate through the changes received from a given
037     * LDAP Server Identifier.
038     */
039    public class ReplicationIterator
040    {
041      private UpdateMessage currentChange = null;
042      private ReplServerDBCursor cursor = null;
043    
044      /**
045       * Creates a new ReplicationIterator.
046       * All created iterator must be released by the caller using the
047       * releaseCursor() method.
048       *
049       * @param id the Identifier of the server on which the iterator applies.
050       * @param db The db where the iterator must be created.
051       * @param changeNumber The ChangeNumber after which the iterator must start.
052       * @throws Exception If there is no other change to push after change
053       *         with changeNumber number.
054       * @throws DatabaseException if a database problem happened.
055       */
056      public ReplicationIterator(
057              short id, ReplicationDB db, ChangeNumber changeNumber)
058              throws Exception, DatabaseException
059      {
060        cursor = db.openReadCursor(changeNumber);
061        if (cursor == null)
062        {
063          throw new Exception("no new change");
064        }
065         if (this.next() == false)
066         {
067           cursor.close();
068           cursor = null;
069           throw new Exception("no new change");
070         }
071      }
072    
073      /**
074       * Get the UpdateMessage where the iterator is currently set.
075       * @return The UpdateMessage where the iterator is currently set.
076       */
077      public UpdateMessage getChange()
078      {
079        return currentChange;
080      }
081    
082      /**
083       * Go to the next change in the ReplicationDB or in the server Queue.
084       * @return false if the iterator is already on the last change before
085       *         this call.
086       */
087      public boolean next()
088      {
089        currentChange = cursor.next();
090    
091        if (currentChange != null)
092          return true;
093        else
094        {
095          // TODO : should check here if some changes are still in the
096          // dbHandler message queue and not yet saved to the backing database
097          // if yes should get change from there from now on.
098          return false;
099        }
100    
101      }
102    
103      /**
104       * Release the resources and locks used by this Iterator.
105       * This method must be called when the iterator is no longer used.
106       * Failure to do it could cause DB deadlock.
107       */
108      public void releaseCursor()
109      {
110        synchronized (this)
111        {
112          if (cursor != null)
113          {
114            cursor.close();
115            cursor = null;
116          }
117        }
118      }
119    
120      /**
121       * Called by the Gc when the object is garbage collected
122       * Release the cursor in case the iterator was badly used and releaseCursor
123       * was never called.
124       */
125      protected void finalize()
126      {
127        releaseCursor();
128      }
129    }