| | |
| | | import org.opends.server.types.operation.PreOperationDeleteOperation; |
| | | import org.opends.server.types.operation.PreOperationModifyDNOperation; |
| | | import org.opends.server.types.operation.PreOperationModifyOperation; |
| | | import org.opends.server.types.operation.PreOperationOperation; |
| | | import org.opends.server.util.LDIFReader; |
| | | import org.opends.server.util.TimeThread; |
| | | import org.opends.server.workflowelement.externalchangelog.ECLWorkflowElement; |
| | |
| | | */ |
| | | private volatile boolean done = true; |
| | | |
| | | private ServerStateFlush flushThread; |
| | | private final ServerStateFlush flushThread; |
| | | |
| | | /** |
| | | * The attribute name used to store the generation id in the backend. |
| | |
| | | { |
| | | done = false; |
| | | |
| | | while (shutdown == false) |
| | | while (!shutdown) |
| | | { |
| | | try |
| | | { |
| | |
| | | |
| | | /* |
| | | * Create a new Persistent Server State that will be used to store |
| | | * the last ChangeNmber seen from all LDAP servers in the topology. |
| | | * the last ChangeNumber seen from all LDAP servers in the topology. |
| | | */ |
| | | 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); |
| | | } |
| | | flushThread = new ServerStateFlush(); |
| | | |
| | | /* |
| | | * ChangeNumberGenerator is used to create new unique ChangeNumbers |
| | |
| | | // listen for changes on the configuration |
| | | configuration.addChangeListener(this); |
| | | |
| | | // register as an AltertGenerator |
| | | // register as an AlertGenerator |
| | | DirectoryServer.registerAlertGenerator(this); |
| | | } |
| | | |
| | |
| | | boolean needReconnection = false; |
| | | |
| | | byte newSdLevel = (byte) configuration.getAssuredSdLevel(); |
| | | if ((isAssured() && (getAssuredMode() == AssuredMode.SAFE_DATA_MODE)) && |
| | | (newSdLevel != getAssuredSdLevel())) |
| | | if (isAssured() && getAssuredMode() == AssuredMode.SAFE_DATA_MODE && |
| | | newSdLevel != getAssuredSdLevel()) |
| | | { |
| | | needReconnection = true; |
| | | } |
| | |
| | | } |
| | | break; |
| | | case SAFE_DATA: |
| | | if (!isAssured() || |
| | | (isAssured() && (getAssuredMode() == AssuredMode.SAFE_READ_MODE))) |
| | | if (!isAssured() || getAssuredMode() == AssuredMode.SAFE_READ_MODE) |
| | | { |
| | | needReconnection = true; |
| | | } |
| | | break; |
| | | case SAFE_READ: |
| | | if (!isAssured() || |
| | | (isAssured() && (getAssuredMode() == AssuredMode.SAFE_DATA_MODE))) |
| | | if (!isAssured() || getAssuredMode() == AssuredMode.SAFE_DATA_MODE) |
| | | { |
| | | needReconnection = true; |
| | | } |
| | |
| | | |
| | | if (!found) |
| | | { |
| | | // The backend is probably empty: if there is some fractional |
| | | // configuration in memory, we do not let the domain being connected, |
| | | // otherwise, it's ok |
| | | if (fractionalConfig.isFractional()) |
| | | { |
| | | return false; |
| | | } |
| | | else |
| | | { |
| | | return true; |
| | | } |
| | | /* |
| | | The backend is probably empty: if there is some fractional |
| | | configuration in memory, we do not let the domain being connected, |
| | | otherwise, it's ok |
| | | */ |
| | | return !fractionalConfig.isFractional(); |
| | | } |
| | | |
| | | /* |
| | |
| | | * @param performFiltering Tells if the effective modifications should |
| | | * be performed or if the call is just to analyze if there are some |
| | | * inconsistency with fractional configuration |
| | | * @return true if the operation is inconsistent with fractional configuration |
| | | * @return true if the operation is inconsistent with fractional |
| | | * configuration |
| | | */ |
| | | public boolean fractionalFilterOperation( |
| | | PreOperationModifyDNOperation modifyDNOperation, boolean performFiltering) |
| | |
| | | { |
| | | if (modifyDNOperation.deleteOldRDN()) |
| | | { |
| | | // The core will remove any occurence of attribute that was part of the |
| | | // old RDN, nothing more to do. |
| | | // The core will remove any occurrence of attribute that was part |
| | | // of the old RDN, nothing more to do. |
| | | return true; // Will not be used as analyze was not requested |
| | | } |
| | | } |
| | |
| | | // No attributes to filter |
| | | return false; |
| | | |
| | | /** |
| | | /* |
| | | * Analyze the old and new rdn to see if they are some attributes to be |
| | | * removed: if the oldnRDN contains some forbidden attributes (for instance |
| | | * removed: if the oldRDN contains some forbidden attributes (for instance |
| | | * it is possible if the entry was created with an add operation and the |
| | | * RDN used contains a forbidden attribute: in this case the attribute value |
| | | * has been kept to be consistent with the dn of the entry.) that are no |
| | |
| | | !newRdn.hasAttributeType(attributeType) && |
| | | !modifyDNOperation.deleteOldRDN()) |
| | | { |
| | | // A forbidden attribute is in the old RDN and no more in the new RDN, |
| | | // and it has not been requested to remove attributes from old RDN: |
| | | // remove ourself the attribute from the entry to stay consistent with |
| | | // fractional configuration |
| | | /* |
| | | * A forbidden attribute is in the old RDN and no more in the new RDN, |
| | | * and it has not been requested to remove attributes from old RDN: |
| | | * let's remove the attribute from the entry to stay consistent with |
| | | * fractional configuration |
| | | */ |
| | | Modification modification = new Modification(ModificationType.DELETE, |
| | | Attributes.empty(attributeType)); |
| | | modifyDNOperation.addModification(modification); |
| | |
| | | // entry as it is forbidden |
| | | if (entryRdn.hasAttributeType(attributeType)) |
| | | { |
| | | // We must remove all values of the attributes map for this |
| | | // attribute type but the one that has the value which is in the RDN |
| | | // of the entry. In fact the (underlying )attribute list does not |
| | | // suppot remove so we have to create a new list, keeping only the |
| | | // attribute value which is the same as in the RDN |
| | | /* |
| | | We must remove all values of the attributes map for this |
| | | attribute type but the one that has the value which is in the RDN |
| | | of the entry. In fact the (underlying )attribute list does not |
| | | support remove so we have to create a new list, keeping only the |
| | | attribute value which is the same as in the RDN |
| | | */ |
| | | AttributeValue rdnAttributeValue = |
| | | entryRdn.getAttributeValue(attributeType); |
| | | List<Attribute> attrList = attributesMap.get(attributeType); |
| | |
| | | Attribute attr = attrIt.next(); |
| | | if (attr.contains(rdnAttributeValue)) |
| | | { |
| | | Iterator<AttributeValue> attrValues = attr.iterator(); |
| | | while(attrValues.hasNext()) |
| | | { |
| | | AttributeValue attrValue = attrValues.next(); |
| | | if (rdnAttributeValue.equals(attrValue)) |
| | | { |
| | | for (AttributeValue attrValue : attr) { |
| | | if (rdnAttributeValue.equals(attrValue)) { |
| | | // Keep the value we want |
| | | sameAttrValue = attrValue; |
| | | } |
| | | else |
| | | { |
| | | } else { |
| | | hasSomeAttributesToFilter = true; |
| | | } |
| | | } |
| | |
| | | // Paranoia check: should never be the case as we should always |
| | | // find the attribute/value pair matching the pair in the RDN |
| | | { |
| | | // Construct and store new atribute list |
| | | // Construct and store new attribute list |
| | | List<Attribute> newRdnAttrList = new ArrayList<Attribute>(); |
| | | AttributeBuilder attrBuilder = |
| | | new AttributeBuilder(attributeType); |
| | | attrBuilder.add(sameAttrValue); |
| | | newRdnAttrList.add(attrBuilder.toAttribute()); |
| | | newRdnAttrLists.add(newRdnAttrList); |
| | | // Store matching attribute type |
| | | // The mapping will be done using object from rdnAttrTypes as key |
| | | // and object from newRdnAttrLists (at same index) as value in |
| | | // the user attribute map to be modified |
| | | /* |
| | | Store matching attribute type |
| | | The mapping will be done using object from rdnAttrTypes as key |
| | | and object from newRdnAttrLists (at same index) as value in |
| | | the user attribute map to be modified |
| | | */ |
| | | rdnAttrTypes.add(attributeType); |
| | | } |
| | | } |
| | |
| | | else |
| | | { |
| | | // The call was just to check : at least one attribute to filter |
| | | // found, return immediatly the answer; |
| | | // found, return immediately the answer; |
| | | return true; |
| | | } |
| | | } |
| | |
| | | continue; |
| | | } |
| | | // Is the current attribute part of the established list ? |
| | | boolean foundAttribute = |
| | | boolean foundAttribute = attributeName != null && |
| | | fractionalConcernedAttributes.contains(attributeName.toLowerCase()); |
| | | if (!foundAttribute) |
| | | { |
| | |
| | | else |
| | | { |
| | | // The call was just to check : at least one attribute to filter |
| | | // found, return immediatly the answer; |
| | | // found, return immediately the answer; |
| | | return FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES; |
| | | } |
| | | } |
| | |
| | | PreOperationDeleteOperation deleteOperation) |
| | | { |
| | | if ((!deleteOperation.isSynchronizationOperation()) |
| | | && (!brokerIsConnected(deleteOperation))) |
| | | && (!brokerIsConnected())) |
| | | { |
| | | Message msg = ERR_REPLICATION_COULD_NOT_CONNECT.get(baseDn.toString()); |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | |
| | | * Probably the original entry was renamed and replaced with |
| | | * another entry. |
| | | * We must not let the change proceed, return a negative |
| | | * result and set the result code to NO_SUCH_OBJET. |
| | | * result and set the result code to NO_SUCH_OBJECT. |
| | | * When the operation will return, the thread that started the |
| | | * operation will try to find the correct entry and restart a new |
| | | * operation. |
| | |
| | | PreOperationAddOperation addOperation) |
| | | { |
| | | if ((!addOperation.isSynchronizationOperation()) |
| | | && (!brokerIsConnected(addOperation))) |
| | | && (!brokerIsConnected())) |
| | | { |
| | | Message msg = ERR_REPLICATION_COULD_NOT_CONNECT.get(baseDn.toString()); |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | |
| | | * Check that the broker associated to this ReplicationDomain has found |
| | | * a Replication Server and that this LDAP server is therefore able to |
| | | * process operations. |
| | | * If not set the ResultCode and the response message, |
| | | * If not, set the ResultCode, the response message, |
| | | * interrupt the operation, and return false |
| | | * |
| | | * @param op The Operation that needs to be checked. |
| | | * |
| | | * @return true when it OK to process the Operation, false otherwise. |
| | | * When false is returned the resultCode and the reponse message |
| | | * When false is returned the resultCode and the response message |
| | | * is also set in the Operation. |
| | | */ |
| | | private boolean brokerIsConnected(PreOperationOperation op) |
| | | private boolean brokerIsConnected() |
| | | { |
| | | if (isolationPolicy.equals(IsolationPolicy.ACCEPT_ALL_UPDATES)) |
| | | { |
| | |
| | | PreOperationModifyDNOperation modifyDNOperation) |
| | | { |
| | | if ((!modifyDNOperation.isSynchronizationOperation()) |
| | | && (!brokerIsConnected(modifyDNOperation))) |
| | | && (!brokerIsConnected())) |
| | | { |
| | | Message msg = ERR_REPLICATION_COULD_NOT_CONNECT.get(baseDn.toString()); |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | |
| | | * Probably the original entry was renamed and replaced with |
| | | * another entry. |
| | | * We must not let the change proceed, return a negative |
| | | * result and set the result code to NO_SUCH_OBJET. |
| | | * result and set the result code to NO_SUCH_OBJECT. |
| | | * When the operation will return, the thread that started the |
| | | * operation will try to find the correct entry and restart a new |
| | | * operation. |
| | |
| | | PreOperationModifyOperation modifyOperation) |
| | | { |
| | | if ((!modifyOperation.isSynchronizationOperation()) |
| | | && (!brokerIsConnected(modifyOperation))) |
| | | && (!brokerIsConnected())) |
| | | { |
| | | Message msg = ERR_REPLICATION_COULD_NOT_CONNECT.get(baseDn.toString()); |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | |
| | | Entry modifiedEntry = modifyOperation.getModifiedEntry(); |
| | | if (ctx == null) |
| | | { |
| | | // No replication ctxt attached => not a replicated operation |
| | | // - create a ctxt with : changeNumber, entryUUID |
| | | // No replication ctx attached => not a replicated operation |
| | | // - create a ctx with : changeNumber, entryUUID |
| | | // - attach the context to the op |
| | | |
| | | ChangeNumber changeNumber = generateChangeNumber(modifyOperation); |
| | |
| | | } |
| | | else |
| | | { |
| | | // Replication ctxt attached => this is a replicated operation being |
| | | // Replication ctx attached => this is a replicated operation being |
| | | // replayed here, it is necessary to |
| | | // - check if the entry has been renamed |
| | | // - check for conflicts |
| | |
| | | * Probably the original entry was renamed and replaced with |
| | | * another entry. |
| | | * We must not let the modification proceed, return a negative |
| | | * result and set the result code to NO_SUCH_OBJET. |
| | | * result and set the result code to NO_SUCH_OBJECT. |
| | | * When the operation will return, the thread that started the |
| | | * operation will try to find the correct entry and restart a new |
| | | * operation. |
| | |
| | | catch (NoSuchElementException e) |
| | | { |
| | | Message message = ERR_OPERATION_NOT_FOUND_IN_PENDING.get( |
| | | curChangeNumber.toString(), op.toString()); |
| | | op.toString(), curChangeNumber.toString()); |
| | | logError(message); |
| | | return; |
| | | } |
| | |
| | | generationIdSavedStatus = false; |
| | | } |
| | | |
| | | if (generationIdSavedStatus != true) |
| | | if (!generationIdSavedStatus) |
| | | { |
| | | this.saveGenerationId(generationId); |
| | | } |
| | |
| | | attrs, null); |
| | | |
| | | LinkedList<SearchResultEntry> entries = searchOp.getSearchEntries(); |
| | | Entry entrytoRename = null; |
| | | ChangeNumber entrytoRenameDate = null; |
| | | Entry entryToRename = null; |
| | | ChangeNumber entryToRenameCN = null; |
| | | for (SearchResultEntry entry : entries) |
| | | { |
| | | EntryHistorical history = EntryHistorical.newInstanceFromEntry(entry); |
| | | if (entrytoRename == null) |
| | | if (entryToRename == null) |
| | | { |
| | | entrytoRename = entry; |
| | | entrytoRenameDate = history.getDNDate(); |
| | | entryToRename = entry; |
| | | entryToRenameCN = history.getDNDate(); |
| | | } |
| | | else if (!history.addedOrRenamedAfter(entrytoRenameDate)) |
| | | else if (!history.addedOrRenamedAfter(entryToRenameCN)) |
| | | { |
| | | // this conflict is older than the previous, keep it. |
| | | entrytoRename = entry; |
| | | entrytoRenameDate = history.getDNDate(); |
| | | entryToRename = entry; |
| | | entryToRenameCN = history.getDNDate(); |
| | | } |
| | | } |
| | | |
| | | if (entrytoRename != null) |
| | | if (entryToRename != null) |
| | | { |
| | | DN entryDN = entrytoRename.getDN(); |
| | | DN entryDN = entryToRename.getDN(); |
| | | ModifyDNOperationBasis newOp = renameEntry( |
| | | entryDN, freedDN.getRDN(), freedDN.getParent(), false); |
| | | |
| | |
| | | } |
| | | } catch (InterruptedException e) |
| | | { |
| | | // stop waiting when interrupted. |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | |
| | |
| | | * search if the entry has been renamed, and return the new dn |
| | | * of the entry. |
| | | */ |
| | | DN newdn = findEntryDN(entryUUID); |
| | | if (newdn != null) |
| | | DN newDN = findEntryDN(entryUUID); |
| | | if (newDN != null) |
| | | { |
| | | // There is an entry with the same unique id as this modify operation |
| | | // replay the modify using the current dn of this entry. |
| | | msg.setDn(newdn.toString()); |
| | | msg.setDn(newDN.toString()); |
| | | numResolvedNamingConflicts.incrementAndGet(); |
| | | return false; |
| | | } |
| | |
| | | // current RDN value(s); |
| | | mod.setModificationType(ModificationType.REPLACE); |
| | | Attribute newAttribute = mod.getAttribute(); |
| | | AttributeBuilder attrBuilder; |
| | | if (newAttribute == null) |
| | | { |
| | | attrBuilder = new AttributeBuilder(modAttrType); |
| | | } |
| | | else |
| | | { |
| | | attrBuilder = new AttributeBuilder(newAttribute); |
| | | } |
| | | AttributeBuilder attrBuilder = new AttributeBuilder(newAttribute); |
| | | attrBuilder.add(currentRDN.getAttributeValue(modAttrType)); |
| | | mod.setAttribute(attrBuilder.toAttribute()); |
| | | } |
| | |
| | | /* |
| | | * This entry is the base dn of the backend. |
| | | * It is quite surprising that the operation result be NO_SUCH_OBJECT. |
| | | * There is nothing more we can do except TODO log a |
| | | * There is nothing more we can do except log a |
| | | * message for the repair tool to look at this problem. |
| | | * TODO : Log the message |
| | | */ |
| | | return true; |
| | | } |
| | |
| | | * - two adds are done on different servers but with the |
| | | * same target DN. |
| | | * - the same ADD is being replayed for the second time on this server. |
| | | * if the nsunique ID already exist, assume this is a replay and |
| | | * if the entryUUID already exist, assume this is a replay and |
| | | * don't do anything |
| | | * if the entry unique id do not exist, generate conflict. |
| | | */ |
| | |
| | | attrs.add(ENTRYUUID_ATTRIBUTE_NAME); |
| | | attrs.add(EntryHistorical.HISTORICAL_ATTRIBUTE_NAME); |
| | | |
| | | SearchFilter ALLMATCH; |
| | | ALLMATCH = SearchFilter.createFilterFromString("(objectClass=*)"); |
| | | InternalSearchOperation op = |
| | | conn.processSearch(entryDN, SearchScope.SINGLE_LEVEL, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, ALLMATCH, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=*)"), |
| | | attrs); |
| | | |
| | | if (op.getResultCode() == ResultCode.SUCCESS) |
| | |
| | | * @param dn The original DN of the entry. |
| | | * |
| | | * @return The generated RDN for a conflicting entry. |
| | | * @throws DirectoryException |
| | | */ |
| | | private RDN generateDeleteConflictDn(String entryUUID, DN dn) |
| | | { |
| | |
| | | state.clearInMemory(); |
| | | state.loadState(); |
| | | |
| | | // Check to see if a Ruv needs to be translated |
| | | Long compatGenId = state.checkRUVCompat(); |
| | | |
| | | generator.adjust(state.getMaxChangeNumber(serverId)); |
| | | // Retrieves the generation ID associated with the data imported |
| | | |
| | | if (compatGenId != null) |
| | | { |
| | | generationId = compatGenId; |
| | | saveGenerationId(generationId); |
| | | } |
| | | else |
| | | generationId = loadGenerationId(); |
| | | generationId = loadGenerationId(); |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | if (search.getResultCode() != ResultCode.SUCCESS) |
| | | { |
| | | if (search.getResultCode() == ResultCode.NO_SUCH_OBJECT) |
| | | { |
| | | // nothing initialized yet |
| | | // don't log an error generationID will be computed. |
| | | } |
| | | else |
| | | { |
| | | // |
| | | if (search.getResultCode() != ResultCode.NO_SUCH_OBJECT) |
| | | { // This is an error. |
| | | Message message = ERR_SEARCHING_GENERATION_ID.get( |
| | | search.getResultCode().getResultCodeName() + " " + |
| | | search.getErrorMessage(), |
| | |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | if ((ros != null) && |
| | | (ros.getNumExportedEntries() >= entryCount)) |
| | | { |
| | | // This is the normal end when computing the generationId |
| | | // We can interrupt the export only by an IOException |
| | | } |
| | | else |
| | | if (ros == null || |
| | | ros.getNumExportedEntries() < entryCount) |
| | | { |
| | | Message message = |
| | | ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(de.getMessageObject()); |
| | | ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(de.getMessageObject()); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | |
| | | } |
| | | |
| | | // Release the shared lock on the backend. |
| | | String lockFile = LockFileManager.getBackendLockFileName(backend); |
| | | StringBuilder failureReason = new StringBuilder(); |
| | | try |
| | | { |
| | | String lockFile = LockFileManager.getBackendLockFileName(backend); |
| | | StringBuilder failureReason = new StringBuilder(); |
| | | if (! LockFileManager.releaseLock(lockFile, failureReason)) |
| | | { |
| | | Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get( |
| | |
| | | } |
| | | |
| | | // From the domainDN retrieves the replication domain |
| | | LDAPReplicationDomain sdomain = |
| | | LDAPReplicationDomain domain = |
| | | MultimasterReplication.findDomain(baseDn, null); |
| | | if (sdomain == null) |
| | | if (domain == null) |
| | | { |
| | | break; |
| | | } |
| | |
| | | throw new DirectoryException(ResultCode.OTHER, |
| | | message); |
| | | } |
| | | replicationDomain = sdomain; |
| | | replicationDomain = domain; |
| | | } |
| | | |
| | | if (replicationDomain == null) |
| | |
| | | * This has no negative impact because the changes on schema should |
| | | * not produce conflicts. |
| | | */ |
| | | if (baseDn.compareTo(DirectoryServer.getSchemaDN()) == 0) |
| | | { |
| | | solveConflictFlag = false; |
| | | } |
| | | else |
| | | { |
| | | solveConflictFlag = configuration.isSolveConflicts(); |
| | | } |
| | | solveConflictFlag = baseDn.compareTo(DirectoryServer.getSchemaDN()) != 0 && |
| | | configuration.isSolveConflicts(); |
| | | |
| | | try |
| | | { |
| | |
| | | public void start() |
| | | { |
| | | // Create the ServerStateFlush thread |
| | | flushThread = new ServerStateFlush(); |
| | | flushThread.start(); |
| | | |
| | | startListenService(); |
| | |
| | | /** |
| | | * Store the provided ECL configuration for the domain. |
| | | * @param domCfg The provided configuration. |
| | | * @throws ConfigException When an error occured. |
| | | * @throws ConfigException When an error occurred. |
| | | */ |
| | | public void storeECLConfiguration(ReplicationDomainCfg domCfg) |
| | | throws ConfigException |
| | |
| | | { |
| | | try |
| | | { eclDomCfg = domCfg.getExternalChangelogDomain(); |
| | | } catch(Exception e) {} |
| | | } catch(Exception e) { /* do nothing */ } |
| | | // domain with no config entry only when running unit tests |
| | | if (eclDomCfg == null) |
| | | { |
| | |
| | | // normally the RS should have been updated by other RSes except for |
| | | // very last changes lost if the local connection was broken |
| | | // ... hence the RS we are connected to should not be empty |
| | | // ... or if it is empty, it is due to a volontary reset |
| | | // ... or if it is empty, it is due to a voluntary reset |
| | | // and we don't want to update it with our changes that could be huge. |
| | | if ((replServerMaxChangeNumber != null) && |
| | | (replServerMaxChangeNumber.getSeqnum()!=0)) |
| | |
| | | } |
| | | |
| | | /** |
| | | * Called by synchronize post op plugin in order to add the entry historized |
| | | * Called by synchronize post op plugin in order to add the entry historical |
| | | * attributes to the UpdateMsg. |
| | | * @param msg |
| | | * @param op |
| | | * @param msg an replication update message |
| | | * @param op the operation in progress |
| | | * @throws DirectoryException |
| | | */ |
| | | private void addEntryAttributesForCL(UpdateMsg msg, |
| | |
| | | { |
| | | // Potential fast-path for delete operations. |
| | | LinkedList<Attribute> attributes = new LinkedList<Attribute>(); |
| | | for (List<Attribute> alist : entry.getUserAttributes().values()) |
| | | for (List<Attribute> attributeList : entry.getUserAttributes().values()) |
| | | { |
| | | attributes.addAll(alist); |
| | | attributes.addAll(attributeList); |
| | | } |
| | | Attribute ocattr = entry.getObjectClassAttribute(); |
| | | if (ocattr != null) |
| | | Attribute objectClassAttribute = entry.getObjectClassAttribute(); |
| | | if (objectClassAttribute != null) |
| | | { |
| | | attributes.add(ocattr); |
| | | attributes.add(objectClassAttribute); |
| | | } |
| | | return attributes; |
| | | } |
| | |
| | | Map<String, List<String>> fractionalSpecificClassesAttributes, |
| | | List<String> fractionalAllClassesAttributes) throws ConfigException |
| | | { |
| | | int fractional_mode = NOT_FRACTIONAL; |
| | | int fractionalMode; |
| | | |
| | | // Determine if fractional-exclude or fractional-include property is used |
| | | // : only one of them is allowed |
| | | Iterator<String> fracConfIt = null; |
| | | Iterator<String> iterator; |
| | | |
| | | // Deduce the wished fractional mode |
| | | if ((exclIt != null) && exclIt.hasNext()) |
| | |
| | | } |
| | | else |
| | | { |
| | | fractional_mode = EXCLUSIVE_FRACTIONAL; |
| | | fracConfIt = exclIt; |
| | | fractionalMode = EXCLUSIVE_FRACTIONAL; |
| | | iterator = exclIt; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if ((inclIt != null) && inclIt.hasNext()) |
| | | { |
| | | fractional_mode = INCLUSIVE_FRACTIONAL; |
| | | fracConfIt = inclIt; |
| | | fractionalMode = INCLUSIVE_FRACTIONAL; |
| | | iterator = inclIt; |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | while (fracConfIt.hasNext()) |
| | | while (iterator.hasNext()) |
| | | { |
| | | // Parse a value with the form class:attr1,attr2... |
| | | // or *:attr1,attr2... |
| | | String fractCfgStr = fracConfIt.next(); |
| | | String fractCfgStr = iterator.next(); |
| | | StringTokenizer st = new StringTokenizer(fractCfgStr, ":"); |
| | | int nTokens = st.countTokens(); |
| | | if (nTokens < 2) |
| | |
| | | } |
| | | } |
| | | } |
| | | return fractional_mode; |
| | | return fractionalMode; |
| | | } |
| | | |
| | | // Return type of the parseFractionalConfig method |
| | |
| | | FractionalConfig fractionalConfig1, FractionalConfig fractionalConfig2) |
| | | throws ConfigException |
| | | { |
| | | // Comapre base DNs just to be consistent |
| | | // Compare base DNs just to be consistent |
| | | if (!fractionalConfig1.getBaseDn().equals(fractionalConfig2.getBaseDn())) |
| | | return false; |
| | | |
| | |
| | | if (specificClassesAttributes1.size() != |
| | | specificClassesAttributes2.size()) |
| | | return false; |
| | | |
| | | // Check consistency of specific classes attributes |
| | | /* |
| | | * Check consistency of specific classes attributes |
| | | * |
| | | * For each class in specificClassesAttributes1, check that the attribute |
| | | * list is equivalent to specificClassesAttributes2 attribute list |
| | | */ |
| | |
| | | for (SearchResultEntry entry : entries) |
| | | { |
| | | long maxTimeToRun = endDate - TimeThread.getTime(); |
| | | if (maxTimeToRun<0) |
| | | if (maxTimeToRun < 0) |
| | | { |
| | | Message errMsg = Message.raw(Category.SYNC, Severity.NOTICE, |
| | | " end date reached"); |