| | |
| | | implements ConfigurationChangeListener<ReplicationDomainCfg>, |
| | | AlertGenerator |
| | | { |
| | | |
| | | /** |
| | | * Set of attributes that will return all the user attributes and the |
| | | * replication related operational attributes when used in a search operation. |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * The fully-qualified name of this class. |
| | | */ |
| | | private static final String CLASS_NAME = LDAPReplicationDomain.class |
| | | .getName(); |
| | | /** The fully-qualified name of this class. */ |
| | | private static final String CLASS_NAME = LDAPReplicationDomain.class.getName(); |
| | | |
| | | /** |
| | | * The attribute used to mark conflicting entries. |
| | |
| | | |
| | | private ExternalChangelogDomain eclDomain; |
| | | |
| | | /** |
| | | * A boolean indicating if the thread used to save the persistentServerState |
| | | * is terminated. |
| | | */ |
| | | /** A boolean indicating if the thread used to save the persistentServerState is terminated. */ |
| | | private volatile boolean done = true; |
| | | |
| | | private final ServerStateFlush flushThread; |
| | | |
| | | /** |
| | | * The attribute name used to store the generation id in the backend. |
| | | */ |
| | | private static final String REPLICATION_GENERATION_ID = |
| | | "ds-sync-generation-id"; |
| | | /** |
| | | * The attribute name used to store the fractional include configuration in |
| | | * the backend. |
| | | */ |
| | | static final String REPLICATION_FRACTIONAL_INCLUDE = |
| | | "ds-sync-fractional-include"; |
| | | /** |
| | | * The attribute name used to store the fractional exclude configuration in |
| | | * the backend. |
| | | */ |
| | | static final String REPLICATION_FRACTIONAL_EXCLUDE = |
| | | "ds-sync-fractional-exclude"; |
| | | /** The attribute name used to store the generation id in the backend. */ |
| | | private static final String REPLICATION_GENERATION_ID = "ds-sync-generation-id"; |
| | | /** The attribute name used to store the fractional include configuration in the backend. */ |
| | | static final String REPLICATION_FRACTIONAL_INCLUDE = "ds-sync-fractional-include"; |
| | | /** The attribute name used to store the fractional exclude configuration in the backend. */ |
| | | static final String REPLICATION_FRACTIONAL_EXCLUDE = "ds-sync-fractional-exclude"; |
| | | |
| | | /** |
| | | * Fractional replication variables. |
| | |
| | | /** Holds the fractional configuration for this domain, if any. */ |
| | | private final FractionalConfig fractionalConfig; |
| | | |
| | | /** |
| | | * The list of attributes that cannot be used in fractional replication |
| | | * configuration. |
| | | */ |
| | | /** The list of attributes that cannot be used in fractional replication configuration. */ |
| | | private static final String[] FRACTIONAL_PROHIBITED_ATTRIBUTES = new String[] |
| | | { |
| | | "objectClass", |
| | |
| | | * the fractional replication ldif import plugin. |
| | | */ |
| | | private int importErrorMessageId = -1; |
| | | /** |
| | | * LocalizableMessage type for ERR_FULL_UPDATE_IMPORT_FRACTIONAL_BAD_REMOTE. |
| | | */ |
| | | /** LocalizableMessage type for ERR_FULL_UPDATE_IMPORT_FRACTIONAL_BAD_REMOTE. */ |
| | | static final int IMPORT_ERROR_MESSAGE_BAD_REMOTE = 1; |
| | | /** |
| | | * LocalizableMessage type for ERR_FULL_UPDATE_IMPORT_FRACTIONAL_REMOTE_IS_FRACTIONAL. |
| | | */ |
| | | /** LocalizableMessage type for ERR_FULL_UPDATE_IMPORT_FRACTIONAL_REMOTE_IS_FRACTIONAL. */ |
| | | static final int IMPORT_ERROR_MESSAGE_REMOTE_IS_FRACTIONAL = 2; |
| | | |
| | | /* |
| | |
| | | super("Replica DS(" + getServerId() + ") state checkpointer for domain \"" + getBaseDN() + "\""); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void run() |
| | | { |
| | |
| | | this.startCSN = replServerMaxCSN; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void run() |
| | | { |
| | |
| | | this.attrValIt = attrValIt; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean hasNext() |
| | | { |
| | | return attrValIt.hasNext(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String next() |
| | | { |
| | | return attrValIt.next().toString(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | // Should not be needed anyway |
| | | @Override |
| | | public void remove() |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // Check consistency of all classes attributes |
| | | for (String attrName : newFractionalAllClassesAttributes) |
| | | { |
| | |
| | | return hasSomeAttributesToFilter; |
| | | } |
| | | |
| | | private static boolean isMandatoryAttribute(Set<ObjectClass> entryClasses, AttributeType attributeType) |
| | | private static boolean isMandatoryAttribute(Set<ObjectClass> entryClasses, AttributeType attributeType) |
| | | { |
| | | for (ObjectClass objectClass : entryClasses) |
| | | { |
| | |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg); |
| | | } |
| | | |
| | | // FIXME should the next call use the initWindow parameter rather than the |
| | | // instance variable? |
| | | super.initializeRemote(target, requestorID, initTask, getInitWindow()); |
| | | super.initializeRemote(target, requestorID, initTask, initWindow); |
| | | } |
| | | |
| | | /** |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Implement the handleConflictResolution phase of the ModifyDNOperation. |
| | | * |
| | |
| | | addOperation.setAttachment(SYNCHROCONTEXT, ctx); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void publishReplicaOfflineMsg() |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | // If the operation is a DELETE on the base entry of the suffix |
| | | // that is replicated, the generation is now lost because the |
| | | // DB is empty. We need to save it again the next time we add an entry. |
| | | if (op.getOperationType().equals(OperationType.DELETE) |
| | | /* |
| | | * If the operation is a DELETE on the base entry of the suffix |
| | | * that is replicated, the generation is now lost because the |
| | | * DB is empty. We need to save it again the next time we add an entry. |
| | | */ |
| | | if (OperationType.DELETE.equals(op.getOperationType()) |
| | | && ((PostOperationDeleteOperation) op) |
| | | .getEntryDN().equals(getBaseDN())) |
| | | { |
| | |
| | | op.run(); |
| | | } |
| | | |
| | | /** |
| | | * Delete this ReplicationDomain. |
| | | */ |
| | | /** Delete this ReplicationDomain. */ |
| | | void delete() |
| | | { |
| | | shutdown(); |
| | | removeECLDomainCfg(); |
| | | } |
| | | |
| | | /** |
| | | * Shutdown this ReplicationDomain. |
| | | */ |
| | | /** Shutdown this ReplicationDomain. */ |
| | | public void shutdown() |
| | | { |
| | | if (shutdown.compareAndSet(false, true)) |
| | |
| | | return pendingChanges.putLocalOperation(operation); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Find the Unique Id of the entry with the provided DN by doing a |
| | | * search of the entry and extracting its entryUUID from its attributes. |
| | |
| | | |
| | | if (result == ResultCode.NO_SUCH_OBJECT) |
| | | { |
| | | /* |
| | | * Find if the entry is still in the database. |
| | | */ |
| | | /* Find if the entry is still in the database. */ |
| | | DN currentDN = findEntryDN(entryUUID); |
| | | if (currentDN == null) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Solve a conflict detected when replaying a ADD operation. |
| | | * |
| | |
| | | return conflict; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Rename an entry that was conflicting so that it stays below the |
| | | * baseDN of the replicationDomain. |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Generate a modification to add the conflict attribute to an entry |
| | | * whose Dn is now conflicting with another entry. |
| | |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Load the GenerationId from the root entry of the domain |
| | | * from the REPLICATION_GENERATION_ID attribute in database |
| | |
| | | logger.trace("Attempt to read generation ID from DB " + getBaseDN()); |
| | | } |
| | | |
| | | /* |
| | | * Search the database entry that is used to periodically |
| | | * save the generation id |
| | | */ |
| | | // Search the database entry that is used to periodically save the generation id |
| | | final SearchRequest request = newSearchRequest(getBaseDN(), SearchScope.BASE_OBJECT) |
| | | .addAttribute(REPLICATION_GENERATION_ID); |
| | | InternalSearchOperation search = conn.processSearch(request); |
| | |
| | | * <<Total Update |
| | | */ |
| | | |
| | | |
| | | /** |
| | | * Push the schema modifications contained in the given parameter as a |
| | | * modification that would happen on a local server. The modifications are not |
| | |
| | | return true; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConfigChangeResult applyConfigurationChange( |
| | | ReplicationDomainCfg configuration) |
| | |
| | | return ccr; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isConfigurationChangeAcceptable( |
| | | ReplicationDomainCfg configuration, List<LocalizableMessage> unacceptableReasons) |
| | |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Map<String, String> getAlerts() |
| | | { |
| | |
| | | return alerts; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getClassName() |
| | | { |
| | | return CLASS_NAME; |
| | | |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN getComponentEntryDN() |
| | | { |
| | | return config.dn(); |
| | | } |
| | | |
| | | /** |
| | | * Starts the Replication Domain. |
| | | */ |
| | | /** Starts the Replication Domain. */ |
| | | public void start() |
| | | { |
| | | // Create the ServerStateFlush thread |
| | |
| | | startListenService(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Remove from this domain configuration, the configuration of the |
| | | * external change log. |
| | | */ |
| | | /** Remove the configuration of the external changelog from this domain configuration. */ |
| | | private void removeECLDomainCfg() |
| | | { |
| | | try |
| | |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void sessionInitiated(ServerStatus initStatus, ServerState rsState) |
| | | { |
| | |
| | | return searchForChangedEntries(baseDN, fromCSN, null, resultListener); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * This method should return the total number of objects in the |
| | | * replicated domain. |
| | |
| | | return backend.getNumberOfEntriesInBaseDN(getBaseDN()); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean processUpdate(UpdateMsg updateMsg) |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | Set<String> attrList = |
| | | fractionalSpecificClassesAttributes.get(classNameLower); |
| | | Set<String> attrList = fractionalSpecificClassesAttributes.get(classNameLower); |
| | | if (attrList == null) |
| | | { |
| | | attrList = new LinkedHashSet<>(); |