| | |
| | | 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 |
| | |
| | | // 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; |
| | | |
| | |
| | | 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. |
| | |
| | | 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) |
| | |
| | | |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | 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"); |
| | |
| | | */ |
| | | 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 |
| | |
| | | // 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; |
| | | |
| | | |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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 |
| | |
| | | * 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; |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | 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) |
| | |
| | | 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; |
| | |
| | | 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} |
| | |
| | | public SynchronizationProviderResult handleConflictResolution( |
| | | ModifyOperation modifyOperation) |
| | | { |
| | | SynchronizationDomain domain = findDomain(modifyOperation.getEntryDN()); |
| | | SynchronizationDomain domain = |
| | | findDomain(modifyOperation.getEntryDN(), modifyOperation); |
| | | if (domain == null) |
| | | return new SynchronizationProviderResult(true); |
| | | |
| | |
| | | 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); |
| | | |
| | |
| | | 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); |
| | | |
| | |
| | | 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); |
| | | |
| | |
| | | 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) |
| | |
| | | @Override |
| | | public SynchronizationProviderResult doPreOperation(AddOperation addOperation) |
| | | { |
| | | SynchronizationDomain domain = findDomain(addOperation.getEntryDN()); |
| | | SynchronizationDomain domain = |
| | | findDomain(addOperation.getEntryDN(), addOperation); |
| | | if (domain == null) |
| | | return new SynchronizationProviderResult(true); |
| | | |
| | |
| | | * @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 |
| | |
| | | } |
| | | } 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; |
| | | } |
| | | |
| | |
| | | */ |
| | | private void genericPostOperation(Operation operation, DN dn) |
| | | { |
| | | SynchronizationDomain domain = findDomain(dn); |
| | | SynchronizationDomain domain = findDomain(dn, operation); |
| | | if (domain == null) |
| | | return; |
| | | |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | 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(); |
| | | } |
| | | |
| | | /** |
| | |
| | | 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, |
| | |
| | | * 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))) |
| | | { |
| | |
| | | * 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); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | 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(); |
| | | |
| | |
| | | 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(); |
| | | |
| | |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * Get the Dn where the ServerState is stored. |
| | | * @return Returns the serverStateDn. |
| | | */ |
| | | public DN getServerStateDn() |
| | | { |
| | | return serverStateDn; |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | |
| | | private short serverId; |
| | | |
| | | private BooleanConfigAttribute receiveStatusStub; |
| | | private int listenerThreadNumber = 10; |
| | | private boolean receiveStatus = true; |
| | | |
| | |
| | | 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, |
| | |
| | | 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. |
| | |
| | | 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) |
| | |
| | | // 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); |
| | | } |
| | |
| | | { |
| | | 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 |
| | |
| | | } |
| | | |
| | | /** |
| | | * 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. |
| | | * |
| | |
| | | { |
| | | return broker.getNumLostConnections(); |
| | | } |
| | | |
| | | /** |
| | | * Check if the domain solve conflicts. |
| | | * |
| | | * @return a boolean indicating if the domain should sove conflicts. |
| | | */ |
| | | public boolean solveConflict() |
| | | { |
| | | return solveConflictFlag; |
| | | } |
| | | } |
| | |
| | | // file. |
| | | private long youngestModificationTime; |
| | | |
| | | // The Synchronization State. |
| | | private LinkedHashSet<AttributeValue> synchronizationState = null; |
| | | |
| | | |
| | | |
| | | /** |
| | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | |
| | | 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)); |
| | | } |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * 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."); |
| | | } |
| | | } |
| | |
| | | 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 |
| | | { |
| | |
| | | |
| | | 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); |
| | |
| | | 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); |
| | |
| | | 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); |
| | |
| | | entry.getUserAttributes(), entry.getOperationalAttributes()); |
| | | addOp.setInternalOperation(true); |
| | | addOp.run(); |
| | | entryList.add(entry.getDN()); |
| | | } |
| | | |
| | | baseUUID = getEntryUUID(DN.decode("ou=People,dc=example,dc=com")); |
| | |
| | | { |
| | | return new Object[][] { { false }, {true} }; |
| | | } |
| | | |
| | | /** |
| | | * Tests done using directly the ChangelogBroker interface. |
| | | */ |
| | |
| | | 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. |
| | | */ |
| New file |
| | |
| | | /* |
| | | * 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); |
| | | |
| | | } |
| | | } |