mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

fdorson
06.05.2009 7938c7ece07363df886d2a3be2cd55870fffbfe4
With these changes the openDS servers are able to load data coming from a Sun Java System Directory Server Enterprise Edition. 
1 files added
3 files modified
356 ■■■■■ changed files
opends/resource/schema/06-compat.ldif 30 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java 34 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java 200 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/ServerStateTest.java 92 ●●●●● patch | view | raw | blame | history
opends/resource/schema/06-compat.ldif
New file
@@ -0,0 +1,30 @@
# You can obtain a copy of the license at
# trunk/opends/resource/legal-notices/OpenDS.LICENSE
# or https://OpenDS.dev.java.net/OpenDS.LICENSE.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at
# trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
# add the following below this CDDL HEADER, with the fields enclosed
# by brackets "[]" replaced with your own identifying information:
#      Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#      Copyright 2009 Sun Microsystems, Inc.
#
#
# This file contains the attribute type and objectclass definitions for use
# with the Directory Server configuration.
dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
objectClasses: ( 2.16.840.1.113730.3.2.30 NAME 'glue' SUP top X-ORIGIN
  'Sun Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.587 NAME 'nsds50ruv'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Sun Directory Server' )
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.replication.plugin;
@@ -364,6 +364,18 @@
     */
    state = new PersistentServerState(baseDn, serverId, getServerState());
    /* Check if a ReplicaUpdateVector entry is present
     * if so, and no state is already initialized
     * translate the ruv into a serverState and
     * a generationId
     */
    Long compatGenId  = state.checkRUVCompat();
    if (compatGenId != null)
    {
      generationId = compatGenId;
      saveGenerationId(generationId);
    }
    startPublishService(replicationServers, window, heartbeatInterval);
    /*
@@ -1878,16 +1890,32 @@
  /**
   * Do what necessary when the data have changed : load state, load
   * generation Id.
   * If there is no such information check if there is a
   * ReplicaUpdateVector entry and translate it into a state
   * and generationId.
   * @exception DirectoryException Thrown when an error occurs.
  */
   */
  protected void loadDataState()
  throws DirectoryException
  {
    Long compatGenId = null;
    state.clearInMemory();
    state.loadState();
    // Check to see if a Ruv needs to be translated
    compatGenId  = state.checkRUVCompat();
    generator.adjust(state.getMaxChangeNumber(serverId));
    // Retrieves the generation ID associated with the data imported
    generationId = loadGenerationId();
    if (compatGenId != null)
    {
      generationId = compatGenId;
      saveGenerationId(generationId);
    }
    else
      generationId = loadGenerationId();
  }
  /**
opends/src/server/org/opends/server/replication/plugin/PersistentServerState.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.replication.plugin;
import org.opends.messages.Message;
@@ -36,6 +36,7 @@
import java.util.List;
import java.util.Iterator;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -81,6 +82,16 @@
    */
   protected static final String REPLICATION_STATE = "ds-sync-state";
   /**
    * The attribute name used to store the entryUUID.
    */
   private static final String ENTRY_UUID = "entryUUID";
   /**
    * The attribute name used to store the RUV elements.
    */
   private static final String REPLICATION_RUV_ELEMENT = "nsds50ruv";
  /**
   * create a new ServerState.
   * @param baseDn The baseDN for which the ServerState is created
@@ -471,6 +482,191 @@
    }
  }
/**
 * Check if a ReplicaUpdateVector entry is present
 * if so, translate the ruv into a serverState and
 * a generationId.
 * @return the generationId translated from the RUV
 * entry, 0 if no RUV is present
 */
  public Long checkRUVCompat() {
   Long genId = null;
   SearchResultEntry ruvEntry = null;
   // Search the RUV in the DB
   ruvEntry = searchRUVEntry();
   if (ruvEntry == null)
     return null;
   // Check if the serverState is already initialized
   if( !isServerStateInitilized())
   {
     // Translate the ruv to serverState
     // and GenerationId
     genId = initializeStateWithRUVEntry(ruvEntry);
   }
   // In any case, remove the RUV entry
   // if it exists
   DeleteOperationBasis del =  new DeleteOperationBasis(conn,
       InternalClientConnection.nextOperationID(),
       InternalClientConnection.nextMessageID(), null,
       new ASN1OctetString(ruvEntry.getDN().toNormalizedString()));
   // Run the internal operation
   del.setInternalOperation(true);
   del.setSynchronizationOperation(true);
   del.setDontSynchronize(true);
   del.run();
   return genId;
  }
  /**
   * Initialize the serverState and the GenerationId based on a RUV
   * entry.
   * @param ruvEntry the entry to translate into a serverState.
   * @return the generationId translated from the RUV entry.
   */
  private Long initializeStateWithRUVEntry(SearchResultEntry ruvEntry) {
    Long genId = null;
    String value = null;
    String csn = null;
    AttributeType ruvElementType =
      DirectoryServer.getAttributeType(REPLICATION_RUV_ELEMENT);
    if (ruvElementType == null)
      return null;
    for (Attribute attr : ruvEntry.getAttribute(ruvElementType))
    {
      Iterator<AttributeValue> it = attr.iterator();
      while (it.hasNext())
      {
        value = it.next().toString();
        // Search for the GenerationId
        if (value.startsWith("{replicageneration} "))
        {
          // Get only the timestamp present in the CSN
          String replicaGen = value.substring(20, 28);
          genId = Long.parseLong(replicaGen,16);
        }
        else
        {
          // Translate the other elements into serverState
          if (value.startsWith("{replica "))
          {
            String[] bits = value.split(" ");
            if (bits.length > 3)
            {
              csn = bits[4];
              String temp = csn.substring(0, 8);
              Long timeStamp = Long.parseLong(temp, 16);
              temp = csn.substring(8, 12);
              Integer seqNum = Integer.parseInt(temp, 16);
              temp = csn.substring(12, 16);
              Integer replicaId = Integer.parseInt(temp, 16);
              // No need to take into account the subSeqNum
              ChangeNumber cn = new ChangeNumber(timeStamp*1000, seqNum,
                  replicaId.shortValue());
              this.update(cn);
            }
          }
        }
      }
    }
    return genId;
}
  /**
   * Check if the server State is initialized by searching
   * the attribute type REPLICATION_STATE in the root entry.
   * @return true if the serverState is initialized, false
   * otherwise
   */
  private boolean isServerStateInitilized() {
    SearchResultEntry resultEntry = searchBaseEntry();
    AttributeType synchronizationStateType =
      DirectoryServer.getAttributeType(REPLICATION_STATE);
    List<Attribute> attrs =
      resultEntry.getAttribute(synchronizationStateType);
    return (attrs != null);
  }
/**
 * Search the database entry that represent a serverState
 * using the RUV format (compatibility mode).
 * @return the corresponding RUV entry, null otherwise
 */
  private SearchResultEntry searchRUVEntry() {
    LDAPFilter filter;
    SearchResultEntry ruvEntry = null;
    // Search the RUV entry
    try
    {
      filter = LDAPFilter.decode("objectclass=ldapSubEntry");
    } catch (LDAPException e)
    {
      // can not happen
      return null;
    }
    LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
    attributes.add(ENTRY_UUID);
    attributes.add(REPLICATION_RUV_ELEMENT);
    InternalSearchOperation search = conn.processSearch(asn1BaseDn,
        SearchScope.SUBORDINATE_SUBTREE,
        DereferencePolicy.DEREF_ALWAYS, 0, 0, false,
        filter,attributes);
    if (((search.getResultCode() != ResultCode.SUCCESS)) &&
        ((search.getResultCode() != ResultCode.NO_SUCH_OBJECT)))
      return null;
    if (search.getResultCode() == ResultCode.SUCCESS)
    {
      /*
       * Search the ldapSubEntry with the entryUUID equals
       * to "ffffffff-ffff-ffff-ffff-ffffffffffff"
       */
      LinkedList<SearchResultEntry> result = search.getSearchEntries();
      if (!result.isEmpty())
      {
        for (SearchResultEntry ldapSubEntry : result)
        {
          List<Attribute> attrs =
            ldapSubEntry.getAttribute(ENTRY_UUID.toLowerCase());
          if (attrs != null)
          {
            Iterator<AttributeValue> iav = attrs.get(0).iterator();
            AttributeValue attrVal = iav.next();
            if (attrVal.getStringValue().
                equalsIgnoreCase("ffffffff-ffff-ffff-ffff-ffffffffffff"))
            {
              ruvEntry = ldapSubEntry;
              break;
            }
          }
        }
      }
    }
    return ruvEntry;
  }
  /**
   * Get the largest ChangeNumber seen for a given LDAP server ID.
   *
@@ -482,4 +678,4 @@
  {
    return state.getMaxChangeNumber(serverID);
  }
}
}
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/common/ServerStateTest.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.replication.common;
@@ -30,9 +30,17 @@
import java.util.Set;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ServerState;
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.ResultCode;
import org.opends.server.util.TimeThread;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -102,4 +110,86 @@
    assertEquals(b, generatedServerState.getBytes()) ;
  }
  /**
   * Ensures that the Directory Server is able to
   * translate a ruv entry to a sever state.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test
  public void translateRuvEntryTest()
         throws Exception
  {
    Entry synchroServerEntry = null;
    String RuvString =
      "dn: nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff, o=test\n"
      +"objectClass: top\n"
      +"objectClass: extensibleobject\n"
      +"objectClass: ldapSubEntry\n"
      +"o: test\n"
      +"nsds50ruv: {replicageneration} 49098853000000010000\n"
      +"nsds50ruv: {replica 3 ldap://kawax:3389} 491d517b000000030000 "
      +"491d564a000000030000\n"
      +"nsds50ruv: {replica 1 ldap://kawax:1389} 490989e8000000010000 "
      +"490989e8000000010000\n"
      +"ds6ruv: {PRIO 3 ldap://kawax:3389}\n"
      +"ds6ruv: {PRIO 1 ldap://kawax:1389}\n"
      +"entryUUID: ffffffff-ffff-ffff-ffff-ffffffffffff\n";
    Entry RuvEntry = TestCaseUtils.entryFromLdifString(RuvString);
    AddOperationBasis addOp = new AddOperationBasis(InternalClientConnection.
        getRootConnection(), InternalClientConnection.nextOperationID(),
        InternalClientConnection.nextMessageID(), null, RuvEntry.getDN(),
        RuvEntry.getObjectClasses(), RuvEntry.getUserAttributes(),
        RuvEntry.getOperationalAttributes());
    addOp.setInternalOperation(true);
    addOp.run();
    assertTrue(addOp.getResultCode() == ResultCode.SUCCESS);
    // Instantiate a Replication domain
    // suffix synchronized
    String synchroServerLdif =
      "dn: cn=o=test, cn=domains, cn=Multimaster Synchronization, cn=Synchronization Providers,cn=config\n"
      + "objectClass: top\n"
      + "objectClass: ds-cfg-replication-domain\n"
      + "cn: o=test\n"
      + "ds-cfg-base-dn: o=test\n"
      + "ds-cfg-replication-server: localhost:3389\n"
      + "ds-cfg-server-id: 1\n"
      + "ds-cfg-receive-status: true\n"
      + "ds-cfg-window-size: 10";
    // When adding the replicationDomain entry the checkRUVCompat
    // method is called and should translate the RuvEntry Added
    // into a serverState + generationId
    synchroServerEntry = TestCaseUtils.entryFromLdifString(synchroServerLdif);
    DirectoryServer.getConfigHandler().addEntry(synchroServerEntry, null);
    assertNotNull(DirectoryServer.getConfigEntry(synchroServerEntry.getDN()),
      "Unable to add the synchronized server");
    LDAPReplicationDomain replDomain = LDAPReplicationDomain.
    retrievesReplicationDomain(DN.decode("o=test"));
    // Then check serverSate and GenId
    assertTrue(replDomain.getGenerationID() == 1225361491);
    ServerState state = replDomain.getServerState();
    assertTrue(state.getMaxChangeNumber((short) 1).
        compareTo(new ChangeNumber("0000011d4d42b240000100000000")) == 0);
    assertTrue(state.getMaxChangeNumber((short) 3).
        compareTo(new ChangeNumber("0000011d9a991110000300000000")) == 0);
    // Remove the configuration entry
    DirectoryServer.getConfigHandler().deleteEntry(synchroServerEntry.getDN(),
        null);
    assertNull(DirectoryServer.getConfigEntry(synchroServerEntry.getDN()),
      "Unable to remove the synchronized server");
  }
}