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 2014-2017 ForgeRock AS.
015 */
016package org.opends.server.replication.server.changelog.file;
017
018import java.util.Iterator;
019import java.util.Map.Entry;
020import java.util.concurrent.ConcurrentSkipListMap;
021
022import net.jcip.annotations.NotThreadSafe;
023
024import org.opends.server.replication.common.ServerState;
025import org.opends.server.replication.protocol.UpdateMsg;
026import org.opends.server.replication.server.changelog.api.ChangelogException;
027import org.opends.server.replication.server.changelog.api.DBCursor;
028import org.opends.server.replication.server.changelog.api.ReplicationDomainDB;
029import org.forgerock.opendj.ldap.DN;
030
031/** Cursor iterating over all the replication domains known to the changelog DB. */
032@NotThreadSafe
033public class MultiDomainDBCursor extends CompositeDBCursor<DN>
034{
035  private final ReplicationDomainDB domainDB;
036  private final ConcurrentSkipListMap<DN, ServerState> newDomains = new ConcurrentSkipListMap<>();
037  private final CursorOptions options;
038
039  /**
040   * Builds a MultiDomainDBCursor instance.
041   *
042   * @param domainDB
043   *          the replication domain management DB
044   * @param options The cursor options
045   */
046  public MultiDomainDBCursor(final ReplicationDomainDB domainDB, CursorOptions options)
047  {
048    this.domainDB = domainDB;
049    this.options = options;
050  }
051
052  /**
053   * Adds a replication domain for this cursor to iterate over. Added cursors
054   * will be created and iterated over on the next call to {@link #next()}.
055   *
056   * @param baseDN
057   *          the replication domain's baseDN
058   * @param startAfterState
059   *          the {@link ServerState} after which to start iterating
060   */
061  public void addDomain(DN baseDN, ServerState startAfterState)
062  {
063    newDomains.put(baseDN, startAfterState != null ? startAfterState : new ServerState());
064  }
065
066  /** {@inheritDoc} */
067  @Override
068  protected void incorporateNewCursors() throws ChangelogException
069  {
070    for (Iterator<Entry<DN, ServerState>> iter = newDomains.entrySet().iterator();
071         iter.hasNext();)
072    {
073      final Entry<DN, ServerState> entry = iter.next();
074      final DN baseDN = entry.getKey();
075      final ServerState serverState = entry.getValue();
076      final DBCursor<UpdateMsg> domainDBCursor = domainDB.getCursorFrom(baseDN, serverState, options);
077      addCursor(domainDBCursor, baseDN);
078      iter.remove();
079    }
080  }
081
082  /**
083   * Removes a replication domain from this cursor and stops iterating over it.
084   * Removed cursors will be effectively removed on the next call to
085   * {@link #next()}.
086   *
087   * @param baseDN
088   *          the replication domain's baseDN
089   */
090  public void removeDomain(DN baseDN)
091  {
092    removeCursor(baseDN);
093  }
094
095  /** {@inheritDoc} */
096  @Override
097  public void close()
098  {
099    super.close();
100    domainDB.unregisterCursor(this);
101    newDomains.clear();
102  }
103
104}