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

gbellato
28.06.2007 f87b1f70312df3e81cdef283089970e500c33a48
opendj-sdk/opends/resource/schema/02-config.ldif
@@ -776,7 +776,8 @@
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
  SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.227 NAME 'ds-sync-state'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.228
  NAME 'ds-cfg-backup-directory' EQUALITY caseExactMatch
  SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -189,6 +189,9 @@
  // The attribute type that will be used to include the defined name forms.
  private AttributeType nameFormsType;
  // The attribute type that will be used to save the synchronization state.
  private AttributeType synchronizationStateType;
  // The value containing DN of the user we'll say created the configuration.
  private AttributeValue creatorsName;
@@ -293,6 +296,8 @@
    matchingRuleUsesType =
         DirectoryServer.getAttributeType(ATTR_MATCHING_RULE_USE_LC, true);
    nameFormsType = DirectoryServer.getAttributeType(ATTR_NAME_FORMS_LC, true);
    synchronizationStateType =
      DirectoryServer.getAttributeType(ATTR_SYNCHRONIZATION_STATE_LC, true);
    // Initialize the lastmod attributes.
@@ -797,6 +802,20 @@
                               valueSet));
    operationalAttrs.put(modifyTimestampType, attrList);
    //  Add the synchronization State attribute.
    valueSet = DirectoryServer.getSchema().getSynchronizationState();
    attr = new Attribute(synchronizationStateType,
                         ATTR_SYNCHRONIZATION_STATE_LC, valueSet);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(attr);
    if (synchronizationStateType.isOperational() && (! showAllAttributes))
    {
      operationalAttrs.put(synchronizationStateType, attrList);
    }
    else
    {
      userAttrs.put(synchronizationStateType, attrList);
    }
    // Add all the user-defined attributes.
    for (Attribute a : userDefinedAttributes)
@@ -1350,10 +1369,19 @@
        default:
          int    msgID   = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE;
          String message = getMessage(msgID, m.getModificationType());
          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message,
                                       msgID);
          if (!modifyOperation.isSynchronizationOperation())
          {
            int    msgID   = MSGID_SCHEMA_INVALID_MODIFICATION_TYPE;
            String message = getMessage(msgID, m.getModificationType());
            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                         message, msgID);
          }
          else
          {
            if (at.equals(synchronizationStateType))
              newSchema.setSynchronizationState(a.getValues());
            modifiedSchemaFiles.add(FILE_USER_SCHEMA_ELEMENTS);
          }
      }
    }
@@ -3438,6 +3466,18 @@
      schemaEntry.putAttribute(matchingRuleUsesType, attrList);
    }
    if (schemaFile.equals(FILE_USER_SCHEMA_ELEMENTS))
    {
      values = schema.getSynchronizationState();
      if (values != null)
      {
        ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
        attrList.add(new Attribute(matchingRuleUsesType,
                                 matchingRuleUsesType.getPrimaryName(),
                                 values));
        schemaEntry.putAttribute(matchingRuleUsesType, attrList);
      }
    }
    // Create a temporary file to which we can write the schema entry.
    File tempFile = File.createTempFile(schemaFile, "temp");
opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -1217,7 +1217,11 @@
   */
  public static final String ATTR_MATCHING_RULE_USE_LC = "matchingruleuse";
  /**
   * The name of the attribute that holds the sycnhronization state,
   * formatted in lowercase.
   */
  public static final String ATTR_SYNCHRONIZATION_STATE_LC = "ds-sync-state";
  /**
   * The default maximum request size that should be used if none is specified
opendj-sdk/opends/src/server/org/opends/server/core/Operation.java
@@ -138,6 +138,10 @@
  // in the response to the client.
  private StringBuilder errorMessage;
  // Indicates whether this operation nneds to be synchronized to
  // other copies of the data.
  private boolean dontSynchronizeFlag;
  /**
@@ -730,6 +734,21 @@
  }
  /**
   * Specifies whether this operation must be synchronized to other copies
   * of the data.
   *
   * @param  dontSynchronize  Specifies whether this operation must be
   *                          synchronized to other copies
   *                          of the data.
   */
  public final void setDontSynchronize(boolean dontSynchronize)
  {
    assert debugEnter(CLASS_NAME, "setDontSynchronize",
                      String.valueOf(dontSynchronize));
    this.dontSynchronizeFlag = dontSynchronize;
  }
  /**
   * Retrieves the entry for the user that should be considered the
@@ -1058,5 +1077,21 @@
   *                 operation should be appended.
   */
  public abstract void toString(StringBuilder buffer);
  /**
   * Indicates whether this operation needs to be synchronized to
   * other copies of the data.
   *
   * @return  <CODE>true</CODE> if this operation don't need to be
   *                            synchronized, or
   *          <CODE>false</CODE> if it needs to be synchronized.
   */
  public boolean dontSynchronize()
  {
    assert debugEnter(CLASS_NAME, "dontSynchronize");
    return dontSynchronizeFlag;
  }
}
opendj-sdk/opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -1053,6 +1053,19 @@
    List<Attribute> mruList = entry.getAttribute(mruAttrType);
    AttributeType synchronizationStateType =
      schema.getAttributeType(ATTR_SYNCHRONIZATION_STATE_LC);
    if (synchronizationStateType == null)
    {
      synchronizationStateType =
        DirectoryServer.getDefaultAttributeType(ATTR_SYNCHRONIZATION_STATE_LC,
            new MatchingRuleUseSyntax());
    }
    List<Attribute> synchronizationState =
      entry.getAttribute(synchronizationStateType);
    if (synchronizationState != null && !(synchronizationState.isEmpty()))
      schema.setSynchronizationState(synchronizationState.get(0).getValues());
    // Parse the attribute type definitions if there are any.
    if (attrList != null)
opendj-sdk/opends/src/server/org/opends/server/synchronization/plugin/MultimasterSynchronization.java
@@ -38,7 +38,6 @@
import org.opends.server.core.AddOperation;
import org.opends.server.synchronization.changelog.Changelog;
import org.opends.server.synchronization.common.LogMessages;
import org.opends.server.synchronization.common.ServerState;
import org.opends.server.types.DN;
import org.opends.server.core.DeleteOperation;
import org.opends.server.types.DirectoryException;
@@ -74,20 +73,6 @@
  private static Map<DN, SynchronizationDomain> domains =
    new HashMap<DN, SynchronizationDomain>() ;
  /**
   * Get the ServerState associated to the SynchronizationDomain
   * with a given DN.
   *
   * @param baseDn The DN of the Synchronization Domain for which the
   *               ServerState must be returned.
   * @return the ServerState associated to the SynchronizationDomain
   *         with the DN in parameter.
   */
  public static ServerState getServerState(DN baseDn)
  {
    SynchronizationDomain domain = findDomain(baseDn);
    return domain.getServerState();
  }
  /**
   * {@inheritDoc}
@@ -323,7 +308,8 @@
  public SynchronizationProviderResult handleConflictResolution(
                                                ModifyOperation modifyOperation)
  {
    SynchronizationDomain domain = findDomain(modifyOperation.getEntryDN());
    SynchronizationDomain domain =
      findDomain(modifyOperation.getEntryDN(), modifyOperation);
    if (domain == null)
      return new SynchronizationProviderResult(true);
@@ -337,7 +323,8 @@
  public SynchronizationProviderResult handleConflictResolution(
      AddOperation addOperation) throws DirectoryException
  {
    SynchronizationDomain domain = findDomain(addOperation.getEntryDN());
    SynchronizationDomain domain =
      findDomain(addOperation.getEntryDN(), addOperation);
    if (domain == null)
      return new SynchronizationProviderResult(true);
@@ -351,7 +338,8 @@
  public SynchronizationProviderResult handleConflictResolution(
      DeleteOperation deleteOperation) throws DirectoryException
  {
    SynchronizationDomain domain = findDomain(deleteOperation.getEntryDN());
    SynchronizationDomain domain =
      findDomain(deleteOperation.getEntryDN(), deleteOperation);
    if (domain == null)
      return new SynchronizationProviderResult(true);
@@ -365,7 +353,8 @@
  public SynchronizationProviderResult handleConflictResolution(
      ModifyDNOperation modifyDNOperation) throws DirectoryException
  {
    SynchronizationDomain domain = findDomain(modifyDNOperation.getEntryDN());
    SynchronizationDomain domain =
      findDomain(modifyDNOperation.getEntryDN(), modifyDNOperation);
    if (domain == null)
      return new SynchronizationProviderResult(true);
@@ -379,8 +368,10 @@
  public SynchronizationProviderResult
      doPreOperation(ModifyOperation modifyOperation)
  {
    SynchronizationDomain domain = findDomain(modifyOperation.getEntryDN());
    if (domain == null)
    DN operationDN = modifyOperation.getEntryDN();
    SynchronizationDomain domain = findDomain(operationDN, modifyOperation);
    if ((domain == null) || (!domain.solveConflict()))
      return new SynchronizationProviderResult(true);
    Historical historicalInformation = (Historical)
@@ -423,7 +414,8 @@
  @Override
  public SynchronizationProviderResult doPreOperation(AddOperation addOperation)
  {
    SynchronizationDomain domain = findDomain(addOperation.getEntryDN());
    SynchronizationDomain domain =
      findDomain(addOperation.getEntryDN(), addOperation);
    if (domain == null)
      return new SynchronizationProviderResult(true);
@@ -457,8 +449,15 @@
   * @param dn The DN for which the domain must be returned.
   * @return The Synchronization domain for this DN.
   */
  private static SynchronizationDomain findDomain(DN dn)
  private static SynchronizationDomain findDomain(DN dn, Operation op)
  {
    /*
     * Don't run the special synchronization code on Operation that are
     * specifically marked as don't synchronize.
     */
    if (op.dontSynchronize())
      return null;
    SynchronizationDomain domain = null;
    DN temp = dn;
    do
@@ -471,13 +470,6 @@
      }
    } while (domain == null);
    /*
     * Don't apply synchronization to the special entry where the ServerState
     * is stored.
     */
    if ((domain!= null) && (domain.getServerStateDN().equals(dn)))
      return null;
    return domain;
  }
@@ -489,7 +481,7 @@
   */
  private void genericPostOperation(Operation operation, DN dn)
  {
    SynchronizationDomain domain = findDomain(dn);
    SynchronizationDomain domain = findDomain(dn, operation);
    if (domain == null)
      return;
opendj-sdk/opends/src/server/org/opends/server/synchronization/plugin/PersistentServerState.java
@@ -35,7 +35,6 @@
import java.util.LinkedList;
import java.util.List;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -53,7 +52,6 @@
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.ModificationType;
@@ -72,8 +70,7 @@
   private boolean savedStatus = true;
   private InternalClientConnection conn =
       InternalClientConnection.getRootConnection();
   private ASN1OctetString serverStateAsn1Dn;
   private DN serverStateDn;
   private ASN1OctetString asn1BaseDn;
   /**
    * The attribute name used to store the state in the backend.
@@ -87,16 +84,8 @@
  public PersistentServerState(DN baseDn)
  {
    this.baseDn = baseDn;
    serverStateAsn1Dn = new ASN1OctetString(
        "dc=ffffffff-ffffffff-ffffffff-ffffffff,"
        + baseDn.toString());
    try
    {
      serverStateDn = DN.decode(serverStateAsn1Dn);
    } catch (DirectoryException e)
    {
      // never happens
    }
    asn1BaseDn = new ASN1OctetString(baseDn.toString());
    loadState();
  }
  /**
@@ -121,22 +110,14 @@
    ResultCode resultCode = updateStateEntry();
    if (resultCode != ResultCode.SUCCESS)
    {
      if (resultCode == ResultCode.NO_SUCH_OBJECT)
      {
        createStateEntry();
      }
      else
      {
        savedStatus = false;
      }
    }
  }
  /**
   * Load the ServerState from the backing entry in database to memory.
   */
  public void loadState()
  private void loadState()
  {
    /*
     * Read the serverState from the database,
@@ -156,10 +137,12 @@
     * Search the database entry that is used to periodically
     * save the ServerState
     */
    InternalSearchOperation search = conn.processSearch(serverStateAsn1Dn,
    LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
    attributes.add(SYNCHRONIZATION_STATE);
    InternalSearchOperation search = conn.processSearch(asn1BaseDn,
        SearchScope.BASE_OBJECT,
        DereferencePolicy.DEREF_ALWAYS, 0, 0, false,
        filter,new LinkedHashSet<String>(0));
        filter,attributes);
    if (((search.getResultCode() != ResultCode.SUCCESS)) &&
        ((search.getResultCode() != ResultCode.NO_SUCH_OBJECT)))
    {
@@ -210,51 +193,6 @@
       * and an ordering index for historical attribute
       */
    }
    if ((resultEntry == null) ||
        ((search.getResultCode() != ResultCode.SUCCESS)))
    {
      createStateEntry();
    }
  }
  /**
   * Create the Entry that will be used to store the ServerState information.
   * It will be updated when the server stops and periodically.
   */
  private void createStateEntry()
  {
    ArrayList<LDAPAttribute> attrs = new ArrayList<LDAPAttribute>();
    ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>();
    ASN1OctetString value = new ASN1OctetString("extensibleObject");
    values.add(value);
    LDAPAttribute attr = new LDAPAttribute("objectClass", values);
    value = new ASN1OctetString("domain");
    values.add(value);
    attr = new LDAPAttribute("objectClass", values);
    attrs.add(attr);
    values = new ArrayList<ASN1OctetString>();
    value = new ASN1OctetString("ffffffff-ffffffff-ffffffff-ffffffff");
    values.add(value);
    attr = new LDAPAttribute("dc", values);
    attrs.add(attr);
    AddOperation add = conn.processAdd(serverStateAsn1Dn, attrs);
    ResultCode resultCode = add.getResultCode();
    if ((resultCode != ResultCode.SUCCESS) &&
        (resultCode != ResultCode.NO_SUCH_OBJECT))
    {
      int msgID = MSGID_ERROR_UPDATING_RUV;
      String message = getMessage(msgID,
          add.getResultCode().getResultCodeName(),
          add.toString(), add.getErrorMessage(),
          baseDn.toString());
      logError(ErrorLogCategory.SYNCHRONIZATION,
          ErrorLogSeverity.SEVERE_ERROR,
          message, msgID);
    }
  }
  /**
@@ -266,8 +204,7 @@
  private ResultCode updateStateEntry()
  {
    /*
     * Generate a modify operation on the Server State Entry :
     * cn=ffffffff-ffffffff-ffffffff-ffffffff, baseDn
     * Generate a modify operation on the Server State baseD Entry.
     */
    ArrayList<ASN1OctetString> values = this.toASN1ArrayList();
@@ -283,10 +220,11 @@
    ModifyOperation op =
      new ModifyOperation(conn, InternalClientConnection.nextOperationID(),
          InternalClientConnection.nextMessageID(),
          new ArrayList<Control>(0), serverStateAsn1Dn,
          new ArrayList<Control>(0), asn1BaseDn,
          mods);
    op.setInternalOperation(true);
    op.setSynchronizationOperation(true);
    op.setDontSynchronize(true);
    op.run();
@@ -301,15 +239,4 @@
    }
    return result;
  }
  /**
   * Get the Dn where the ServerState is stored.
   * @return Returns the serverStateDn.
   */
  public DN getServerStateDn()
  {
    return serverStateDn;
  }
}
opendj-sdk/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
@@ -139,7 +139,6 @@
  private short serverId;
  private BooleanConfigAttribute receiveStatusStub;
  private int listenerThreadNumber = 10;
  private boolean receiveStatus = true;
@@ -157,16 +156,18 @@
  private InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
  static String CHANGELOG_SERVER_ATTR = "ds-cfg-changelog-server";
  static String BASE_DN_ATTR = "ds-cfg-synchronization-dn";
  static String SERVER_ID_ATTR = "ds-cfg-directory-server-id";
  static String RECEIVE_STATUS = "ds-cfg-receive-status";
  static String MAX_RECEIVE_QUEUE = "ds-cfg-max-receive-queue";
  static String MAX_RECEIVE_DELAY = "ds-cfg-max-receive-delay";
  static String MAX_SEND_QUEUE = "ds-cfg-max-send-queue";
  static String MAX_SEND_DELAY = "ds-cfg-max-send-delay";
  static String WINDOW_SIZE = "ds-cfg-window-size";
  static String HEARTBEAT_INTERVAL = "ds-cfg-heartbeat-interval";
  private boolean solveConflictFlag = true;
  static final String CHANGELOG_SERVER_ATTR = "ds-cfg-changelog-server";
  static final String BASE_DN_ATTR = "ds-cfg-synchronization-dn";
  static final String SERVER_ID_ATTR = "ds-cfg-directory-server-id";
  static final String RECEIVE_STATUS = "ds-cfg-receive-status";
  static final String MAX_RECEIVE_QUEUE = "ds-cfg-max-receive-queue";
  static final String MAX_RECEIVE_DELAY = "ds-cfg-max-receive-delay";
  static final String MAX_SEND_QUEUE = "ds-cfg-max-send-queue";
  static final String MAX_SEND_DELAY = "ds-cfg-max-send-delay";
  static final String WINDOW_SIZE = "ds-cfg-window-size";
  static final String HEARTBEAT_INTERVAL = "ds-cfg-heartbeat-interval";
  private static final StringConfigAttribute changelogStub =
    new StringConfigAttribute(CHANGELOG_SERVER_ATTR,
@@ -180,6 +181,10 @@
    new DNConfigAttribute(BASE_DN_ATTR, "synchronization base DN",
                          true, false, false);
  private static final BooleanConfigAttribute receiveStatusStub =
    new BooleanConfigAttribute(RECEIVE_STATUS, "receive status", false);
  /**
   * The set of time units that will be used for expressing the heartbeat
   * interval.
@@ -251,14 +256,33 @@
      baseDN = baseDn.activeValue();
    configAttributes.add(baseDn);
    /*
     * Modify conflicts are solved for all suffixes but the cn=schema suffix
     * because we don't want to store extra information in the schema
     * ldif files.
     * This has no negative impact because the changes on schema should
     * not produce conflicts.
     */
    try
    {
      if (baseDN.compareTo(DN.decode("cn=schema")) == 0)
      {
        solveConflictFlag = false;
      }
      else
      {
        solveConflictFlag = true;
      }
    } catch (DirectoryException e1)
    {
      // never happens because "cn=schema" is a valid DN
    }
    state = new PersistentServerState(baseDN);
    state.loadState();
    /*
     * Read the Receive Status.
     */
    receiveStatusStub = new BooleanConfigAttribute(RECEIVE_STATUS,
        "receive status", false);
    BooleanConfigAttribute receiveStatusAttr = (BooleanConfigAttribute)
          configEntry.getConfigAttribute(receiveStatusStub);
    if (receiveStatusAttr != null)
@@ -712,6 +736,8 @@
      // so this is not a synchronization operation.
      ChangeNumber changeNumber = generateChangeNumber(modifyOperation);
      String modifiedEntryUUID = Historical.getEntryUuid(modifiedEntry);
      if (modifiedEntryUUID == null)
        modifiedEntryUUID = modifyOperation.getEntryDN().toString();
      ctx = new ModifyContext(changeNumber, modifiedEntryUUID);
      modifyOperation.setAttachment(SYNCHROCONTEXT, ctx);
    }
@@ -719,7 +745,8 @@
    {
      String modifiedEntryUUID = ctx.getEntryUid();
      String currentEntryUUID = Historical.getEntryUuid(modifiedEntry);
      if (!currentEntryUUID.equals(modifiedEntryUUID))
      if ((currentEntryUUID != null) &&
          (!currentEntryUUID.equals(modifiedEntryUUID)))
      {
        /*
         * The current modified entry is not the same entry as the one on
@@ -1119,15 +1146,6 @@
  }
  /**
   * Get the DN where the ServerState is stored.
   * @return The DN where the ServerState is stored.
   */
  public DN getServerStateDN()
  {
    return state.getServerStateDn();
  }
  /**
   * Get the name of the changelog server to which this domain is currently
   * connected.
   *
@@ -1827,4 +1845,14 @@
  {
    return broker.getNumLostConnections();
  }
  /**
   * Check if the domain solve conflicts.
   *
   * @return a boolean indicating if the domain should sove conflicts.
   */
  public boolean solveConflict()
  {
    return solveConflictFlag;
  }
}
opendj-sdk/opends/src/server/org/opends/server/types/Schema.java
@@ -188,6 +188,9 @@
  // file.
  private long youngestModificationTime;
  // The Synchronization State.
  private LinkedHashSet<AttributeValue> synchronizationState = null;
  /**
@@ -3030,8 +3033,35 @@
    dupSchema.objectClassSet.addAll(objectClassSet);
    dupSchema.oldestModificationTime   = oldestModificationTime;
    dupSchema.youngestModificationTime = youngestModificationTime;
    if (synchronizationState != null)
    {
      dupSchema.synchronizationState =
        new LinkedHashSet<AttributeValue>(synchronizationState);
    }
    return dupSchema;
  }
  /**
   * Retrieves the Synchronization state for this schema.
   *
   * @return  The Synchronization state for this schema.
   */
  public LinkedHashSet<AttributeValue> getSynchronizationState()
  {
    return synchronizationState;
  }
  /**
   * Sets the Synchronization state for this schema.
   *
   * @param  values  Synchronization state for this schema.
   */
  public void setSynchronizationState(
              LinkedHashSet<AttributeValue> values)
  {
    synchronizationState = values;
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/api/ConfigurableComponentTestCase.java
@@ -137,8 +137,12 @@
    DN          configEntryDN = c.getConfigurableComponentEntryDN();
    ConfigEntry configEntry   = DirectoryServer.getConfigEntry(configEntryDN);
    ArrayList<String> unacceptableReasons = new ArrayList<String>();
    assertTrue(c.hasAcceptableConfiguration(configEntry, unacceptableReasons));
    if (configEntry != null)
    {
      ArrayList<String> unacceptableReasons = new ArrayList<String>();
      assertTrue(c.hasAcceptableConfiguration(configEntry,
                                              unacceptableReasons));
    }
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SchemaSynchronizationTest.java
New file
@@ -0,0 +1,237 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * 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
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.synchronization;
import static org.opends.server.loggers.Error.logError;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.Operation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.synchronization.common.ChangeNumber;
import org.opends.server.synchronization.plugin.ChangelogBroker;
import org.opends.server.synchronization.protocol.ModifyMsg;
import org.opends.server.synchronization.protocol.SynchronizationMessage;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ResultCode;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
 * Test for the schema synchronization.
 */
public class SchemaSynchronizationTest extends SynchronizationTestCase
{
  ArrayList<Modification> rcvdMods = null;
  /**
   * Set up the environment for performing the tests in this Class.
   * synchronization
   *
   * @throws Exception
   *           If the environment could not be set up.
   */
  @BeforeClass
  public void setUp() throws Exception
  {
    // This test suite depends on having the schema available.
    TestCaseUtils.startServer();
    // Disable schema check
    schemaCheck = DirectoryServer.checkSchema();
    DirectoryServer.setCheckSchema(false);
    // Create an internal connection
    connection = InternalClientConnection.getRootConnection();
    // top level synchro provider
    String synchroStringDN = "cn=Synchronization Providers,cn=config";
    // Multimaster Synchro plugin
    synchroPluginStringDN = "cn=Multimaster Synchronization, "
        + synchroStringDN;
    String synchroPluginLdif = "dn: "
        + synchroPluginStringDN
        + "\n"
        + "objectClass: top\n"
        + "objectClass: ds-cfg-synchronization-provider\n"
        + "ds-cfg-synchronization-provider-enabled: true\n"
        + "ds-cfg-synchronization-provider-class: org.opends.server.synchronization.MultimasterSynchronization\n";
    synchroPluginEntry = TestCaseUtils.entryFromLdifString(synchroPluginLdif);
    // Change log
    String changeLogStringDN = "cn=Changelog Server, " + synchroPluginStringDN;
    String changeLogLdif = "dn: " + changeLogStringDN + "\n"
        + "objectClass: top\n"
        + "objectClass: ds-cfg-synchronization-changelog-server-config\n"
        + "cn: Changelog Server\n" + "ds-cfg-changelog-port: 8989\n"
        + "ds-cfg-changelog-server-id: 1\n";
    changeLogEntry = TestCaseUtils.entryFromLdifString(changeLogLdif);
    // suffix synchronized
    String synchroServerLdif = "dn: cn=example, " + synchroPluginStringDN + "\n"
        + "objectClass: top\n"
        + "objectClass: ds-cfg-synchronization-provider-config\n"
        + "cn: example\n"
        + "ds-cfg-synchronization-dn: cn=schema\n"
        + "ds-cfg-changelog-server: localhost:8989\n"
        + "ds-cfg-directory-server-id: 1\n";
    synchroServerEntry = TestCaseUtils.entryFromLdifString(synchroServerLdif);
    configureSynchronization();
  }
  /**
   * Checks that changes done to the schema are pushed to the changelog
   * clients.
   */
  @Test()
  public void pushSchemaChange() throws Exception
  {
    logError(ErrorLogCategory.SYNCHRONIZATION,
        ErrorLogSeverity.NOTICE,
        "Starting synchronization test : pushSchemaChange ", 1);
    final DN baseDn = DN.decode("cn=schema");
    ChangelogBroker broker =
      openChangelogSession(baseDn, (short) 2, 100, 8989, 1000, true);
    try
    {
      // Modify the schema
      AttributeType attrType =
        DirectoryServer.getAttributeType("attributetypes", true);
      LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(attrType, "( 2.5.44.77.33 NAME 'dummy' )"));
      Attribute attr = new Attribute(attrType, "attributetypes", values);
      List<Modification> mods = new ArrayList<Modification>();
      Modification mod = new Modification(ModificationType.ADD, attr);
      mods.add(mod);
      ModifyOperation modOp = new ModifyOperation(connection,
          InternalClientConnection.nextOperationID(), InternalClientConnection
          .nextMessageID(), null, baseDn, mods);
      modOp.setInternalOperation(true);
      modOp.run();
      ResultCode code = modOp.getResultCode();
      assertTrue(code.equals(ResultCode.SUCCESS),
                 "The original operation failed");
      // See if the client has received the msg
      SynchronizationMessage msg = broker.receive();
      assertTrue(msg instanceof ModifyMsg,
                 "The received synchronization message is not a MODIFY msg");
      ModifyMsg modMsg = (ModifyMsg) msg;
      Operation receivedOp = modMsg.createOperation(connection);
      assertTrue(DN.decode(modMsg.getDn()).compareTo(baseDn) == 0,
                 "The received message is not for cn=schema");
      assertTrue(receivedOp instanceof ModifyOperation,
                 "The received synchronization message is not a MODIFY msg");
      ModifyOperation receivedModifyOperation = (ModifyOperation) receivedOp;
      List<LDAPModification> rcvdRawMods =
        receivedModifyOperation.getRawModifications();
      this.rcvdMods = new ArrayList<Modification>();
      for (LDAPModification m : rcvdRawMods)
      {
        this.rcvdMods.add(m.toModification());
      }
      assertTrue(this.rcvdMods.contains(mod),
                 "The received mod does not contain the original change");
      /*
       * Now cleanup the schema for the next test
       */
      mod = new Modification(ModificationType.DELETE, attr);
      mods.clear();
      mods.add(mod);
      modOp = new ModifyOperation(connection,
          InternalClientConnection.nextOperationID(), InternalClientConnection
          .nextMessageID(), null, baseDn, mods);
      modOp.setInternalOperation(true);
      modOp.run();
      code = modOp.getResultCode();
      assertTrue(code.equals(ResultCode.SUCCESS),
                 "The original operation failed");
    }
    finally
    {
      broker.stop();
    }
  }
  /**
   * Checks that changes to the schema pushed to the changelog
   * are received and correctly replayed by synchronization plugin.
   */
  @Test(dependsOnMethods = { "pushSchemaChange" })
  public void replaySchemaChange() throws Exception
  {
    logError(ErrorLogCategory.SYNCHRONIZATION,
        ErrorLogSeverity.NOTICE,
        "Starting synchronization test : pushSchemaChange ", 1);
    final DN baseDn = DN.decode("cn=schema");
    ChangelogBroker broker =
      openChangelogSession(baseDn, (short) 2, 100, 8989, 1000, true);
    ModifyMsg modMsg = new ModifyMsg(new ChangeNumber((long) 10, 1, (short) 2),
                                     baseDn, rcvdMods, "cn=schema");
    broker.publish(modMsg);
    boolean found = checkEntryHasAttribute(baseDn, "attributetypes",
                                           "( 2.5.44.77.33 NAME 'dummy' )",
                                           10000, true);
    if (found == false)
      fail("The modification has not been correctly replayed.");
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/StressTest.java
@@ -65,8 +65,7 @@
import org.testng.annotations.Test;
/**
 * Test the contructors, encoders and decoders of the synchronization AckMsg,
 * ModifyMsg, ModifyDnMsg, AddMsg and Delete Msg
 * Stress test for the synchronization code using the ChangelogBroker API.
 */
public class StressTest extends SynchronizationTestCase
{
@@ -109,7 +108,6 @@
    final DN baseDn = DN.decode("ou=People,dc=example,dc=com");
    final int TOTAL_MESSAGES = 1000;
    cleanEntries();
    ChangelogBroker broker =
      openChangelogSession(baseDn, (short) 18, 100, 8989, 5000, true);
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/SynchronizationTestCase.java
@@ -129,9 +129,12 @@
      int port, int timeout, boolean emptyOldChanges)
          throws Exception, SocketException
  {
    PersistentServerState state = new PersistentServerState(baseDn);
    ServerState state;
    if (emptyOldChanges)
      state.loadState();
       state = new PersistentServerState(baseDn);
    else
       state = new ServerState();
    ChangelogBroker broker = new ChangelogBroker(
        state, baseDn, serverId, 0, 0, 0, 0, window_size, 0);
    ArrayList<String> servers = new ArrayList<String>(1);
@@ -188,9 +191,12 @@
      boolean emptyOldChanges)
          throws Exception, SocketException
  {
    PersistentServerState state = new PersistentServerState(baseDn);
    ServerState state;
    if (emptyOldChanges)
      state.loadState();
       state = new PersistentServerState(baseDn);
    else
       state = new ServerState();
    ChangelogBroker broker = new ChangelogBroker(
        state, baseDn, serverId, maxRcvQueue, 0,
        maxSendQueue, 0, window_size, 0);
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
@@ -123,7 +123,6 @@
          entry.getUserAttributes(), entry.getOperationalAttributes());
      addOp.setInternalOperation(true);
      addOp.run();
      entryList.add(entry.getDN());
    }
    baseUUID = getEntryUUID(DN.decode("ou=People,dc=example,dc=com"));
@@ -819,6 +818,7 @@
  {
    return new Object[][] { { false }, {true} };
  }
  /**
   * Tests done using directly the ChangelogBroker interface.
   */
@@ -839,19 +839,6 @@
      ChangeNumberGenerator gen = new ChangeNumberGenerator((short) 27, 0);
      /*
       * loop receiving update until there is nothing left
       * to make sure that message from previous tests have been consumed.
       */
      try
      {
        while (true)
        {
          broker.receive();
        }
      }
      catch (Exception e)
      {}
      /*
       * Test that operations done on this server are sent to the
       * changelog server and forwarded to our changelog broker session.
       */
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/plugin/PersistentStateTest.java
New file
@@ -0,0 +1,125 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * 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
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 */
package org.opends.server.synchronization.plugin;
import static org.testng.Assert.assertEquals;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.AddOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.synchronization.SynchronizationTestCase;
import org.opends.server.synchronization.common.ChangeNumber;
import org.opends.server.synchronization.common.ChangeNumberGenerator;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
 * Test the PersistentServerState class.
 */
public class PersistentStateTest extends SynchronizationTestCase
{
  /**
   * Set up the environment for performing the tests in this suite.
   *
   * @throws Exception
   *         If the environment could not be set up.
   */
  @BeforeClass
  public void setUp() throws Exception
  {
    /*
     * start the server and create the dc=exmaple,dc=xom entry if it does not
     * exist yet.
     */
    TestCaseUtils.startServer();
    String topEntry = "dn: dc=example,dc=com\n" + "objectClass: top\n"
    + "objectClass: domain\n";
    connection = InternalClientConnection.getRootConnection();
    Entry entry = TestCaseUtils.entryFromLdifString(topEntry);
    AddOperation addOp = new AddOperation(connection,
        InternalClientConnection.nextOperationID(), InternalClientConnection
        .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
        entry.getUserAttributes(), entry.getOperationalAttributes());
    addOp.setInternalOperation(true);
    addOp.run();
  }
  /**
   * The suffix for which we want to test the PersistentServerState class.
   */
  @DataProvider(name = "suffix")
  public Object[][] suffixData() {
    return new Object[][] {
       {"dc=example,dc=com"},
       {"cn=schema"}
    };
  }
  /**
   * Test that the PersistentServerState class is able to store and
   * retrieve ServerState to persistent storage.
   */
  @Test(dataProvider = "suffix")
  public void persistenServerStateTest(String dn)
         throws Exception
  {
    /*
     * Create a new PersitentServerState,
     * update it with 2 new ChangeNumbers with 2 different server Ids
     * save it
     *
     * Then creates a new PersistentServerState and check that the
     * 2 ChangeNumbers have been saved in this new PersistentServerState.
     */
    DN baseDn = DN.decode(dn);
    PersistentServerState state = new PersistentServerState(baseDn);
    ChangeNumberGenerator gen1 = new ChangeNumberGenerator((short) 1, state);
    ChangeNumberGenerator gen2 = new ChangeNumberGenerator((short) 2, state);
    ChangeNumber cn1 = gen1.NewChangeNumber();
    ChangeNumber cn2 = gen2.NewChangeNumber();
    state.update(cn1);
    state.update(cn2);
    state.save();
    PersistentServerState stateSaved = new PersistentServerState(baseDn);
    ChangeNumber cn1Saved = stateSaved.getMaxChangeNumber((short) 1);
    ChangeNumber cn2Saved = stateSaved.getMaxChangeNumber((short) 2);
    assertEquals(cn1Saved, cn1,
        "cn1 has not been saved or loaded correctly for " + dn);
    assertEquals(cn2Saved, cn2,
        "cn2 has not been saved or loaded correctly for " + dn);
  }
}