| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.meta.PluginCfgDefn; |
| | |
| | | import org.opends.server.api.plugin.*; |
| | | import org.opends.server.api.plugin.PluginResult.PostOperation; |
| | | import org.opends.server.api.plugin.PluginResult.PreOperation; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.schema.SchemaConstants; |
| | | import org.opends.server.types.*; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.opends.server.types.operation.*; |
| | | |
| | | import static org.opends.messages.PluginMessages.*; |
| | |
| | | * The data structure to store the mapping between the attribute value and the |
| | | * corresponding dn. |
| | | */ |
| | | private ConcurrentHashMap<AttributeValue,DN> uniqueAttrValue2Dn; |
| | | private ConcurrentHashMap<ByteString,DN> uniqueAttrValue2Dn; |
| | | |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | uniqueAttrValue2Dn = new ConcurrentHashMap<AttributeValue,DN>(); |
| | | uniqueAttrValue2Dn = new ConcurrentHashMap<ByteString,DN>(); |
| | | DirectoryServer.registerAlertGenerator(this); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | DN entryDN = entry.getName(); |
| | | List<AttributeValue> recordedValues = new LinkedList<AttributeValue>(); |
| | | List<ByteString> recordedValues = new LinkedList<ByteString>(); |
| | | for (AttributeType t : config.getType()) |
| | | { |
| | | List<Attribute> attrList = entry.getAttribute(t); |
| | |
| | | { |
| | | for (Attribute a : attrList) |
| | | { |
| | | for (AttributeValue v : a) |
| | | for (ByteString v : a) |
| | | { |
| | | PreOperation stop = |
| | | checkUniqueness(entryDN, t, v, baseDNs, recordedValues, config); |
| | |
| | | return PluginResult.PreOperation.continueOperationProcessing(); |
| | | } |
| | | |
| | | List<AttributeValue> recordedValues = new LinkedList<AttributeValue>(); |
| | | List<ByteString> recordedValues = new LinkedList<ByteString>(); |
| | | for (Modification m : modifyOperation.getModifications()) |
| | | { |
| | | Attribute a = m.getAttribute(); |
| | |
| | | { |
| | | case ADD: |
| | | case REPLACE: |
| | | for (AttributeValue v : a) |
| | | for (ByteString v : a) |
| | | { |
| | | PreOperation stop = |
| | | checkUniqueness(entryDN, t, v, baseDNs, recordedValues, config); |
| | |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : updatedAttr) |
| | | for (ByteString v : updatedAttr) |
| | | { |
| | | PreOperation stop = checkUniqueness( |
| | | entryDN, t, v, baseDNs, recordedValues, config); |
| | |
| | | |
| | | |
| | | private PreOperation checkUniqueness(DN entryDN, AttributeType t, |
| | | AttributeValue v, Set<DN> baseDNs, List<AttributeValue> recordedValues, |
| | | ByteString v, Set<DN> baseDNs, List<ByteString> recordedValues, |
| | | UniqueAttributePluginCfg config) |
| | | { |
| | | try |
| | |
| | | // Before returning, we need to remove all values added |
| | | // in the uniqueAttrValue2Dn map, because PostOperation |
| | | // plugin does not get called. |
| | | for (AttributeValue v2 : recordedValues) |
| | | for (ByteString v2 : recordedValues) |
| | | { |
| | | uniqueAttrValue2Dn.remove(v2); |
| | | } |
| | | LocalizableMessage msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get( |
| | | t.getNameOrOID(), v.getValue(), conflictDN); |
| | | t.getNameOrOID(), v, conflictDN); |
| | | return PluginResult.PreOperation.stopProcessing( |
| | | ResultCode.CONSTRAINT_VIOLATION, msg); |
| | | } |
| | |
| | | de.getResultCode(), de.getMessageObject()); |
| | | |
| | | // Try some cleanup before returning, to avoid memory leaks |
| | | for (AttributeValue v2 : recordedValues) |
| | | for (ByteString v2 : recordedValues) |
| | | { |
| | | uniqueAttrValue2Dn.remove(v2); |
| | | } |
| | |
| | | return PluginResult.PreOperation.continueOperationProcessing(); |
| | | } |
| | | |
| | | List<AttributeValue> recordedValues = new LinkedList<AttributeValue>(); |
| | | List<ByteString> recordedValues = new LinkedList<ByteString>(); |
| | | RDN newRDN = modifyDNOperation.getNewRDN(); |
| | | for (int i=0; i < newRDN.getNumValues(); i++) |
| | | { |
| | |
| | | continue; |
| | | } |
| | | |
| | | AttributeValue v = newRDN.getAttributeValue(i); |
| | | ByteString v = newRDN.getAttributeValue(i); |
| | | DN entryDN = modifyDNOperation.getEntryDN(); |
| | | PreOperation stop = |
| | | checkUniqueness(entryDN, t, v, baseDNs, recordedValues, config); |
| | |
| | | { |
| | | for (Attribute a : attrList) |
| | | { |
| | | for (AttributeValue v : a) |
| | | for (ByteString v : a) |
| | | { |
| | | sendAlertForUnresolvedConflict(addOperation, entryDN, entryDN, t, |
| | | v, baseDNs, config); |
| | |
| | | { |
| | | case ADD: |
| | | case REPLACE: |
| | | for (AttributeValue v : a) |
| | | for (ByteString v : a) |
| | | { |
| | | sendAlertForUnresolvedConflict(modifyOperation, entryDN, entryDN, t, |
| | | v, baseDNs, config); |
| | |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : updatedAttr) |
| | | for (ByteString v : updatedAttr) |
| | | { |
| | | sendAlertForUnresolvedConflict(modifyOperation, entryDN, |
| | | entryDN, t, v, baseDNs, config); |
| | |
| | | continue; |
| | | } |
| | | |
| | | AttributeValue v = newRDN.getAttributeValue(i); |
| | | ByteString v = newRDN.getAttributeValue(i); |
| | | sendAlertForUnresolvedConflict(modifyDNOperation, entryDN, |
| | | updatedEntryDN, t, v, baseDNs, config); |
| | | } |
| | |
| | | |
| | | |
| | | private void sendAlertForUnresolvedConflict(PluginOperation operation, |
| | | DN entryDN, DN updatedEntryDN, AttributeType t, AttributeValue v, |
| | | DN entryDN, DN updatedEntryDN, AttributeType t, ByteString v, |
| | | Set<DN> baseDNs, UniqueAttributePluginCfg config) |
| | | { |
| | | try |
| | |
| | | t.getNameOrOID(), |
| | | operation.getConnectionID(), |
| | | operation.getOperationID(), |
| | | v.getValue(), |
| | | v, |
| | | updatedEntryDN, |
| | | conflictDN); |
| | | DirectoryServer.sendAlertNotification(this, |
| | |
| | | */ |
| | | private DN getConflictingEntryDN(Set<DN> baseDNs, DN targetDN, |
| | | UniqueAttributePluginCfg config, |
| | | AttributeValue value) |
| | | ByteString value) |
| | | throws DirectoryException |
| | | { |
| | | SearchFilter filter; |
| | |
| | | { |
| | | for (Attribute a : attrList) |
| | | { |
| | | for (AttributeValue v : a) |
| | | for (ByteString v : a) |
| | | { |
| | | uniqueAttrValue2Dn.remove(v); |
| | | } |
| | |
| | | { |
| | | case ADD: |
| | | case REPLACE: |
| | | for (AttributeValue v : a) |
| | | for (ByteString v : a) |
| | | { |
| | | uniqueAttrValue2Dn.remove(v); |
| | | } |
| | |
| | | continue; |
| | | } |
| | | |
| | | for (AttributeValue v : updatedAttr) |
| | | for (ByteString v : updatedAttr) |
| | | { |
| | | uniqueAttrValue2Dn.remove(v); |
| | | } |
| | |
| | | // We aren't interested in this attribute type. |
| | | continue; |
| | | } |
| | | AttributeValue v = newRDN.getAttributeValue(i); |
| | | uniqueAttrValue2Dn.remove(v); |
| | | uniqueAttrValue2Dn.remove(newRDN.getAttributeValue(i)); |
| | | } |
| | | return PostOperation.continueOperationProcessing(); |
| | | } |