Partial fix for OPENDJ-194: Minor improvements to change log content and configuration
Commit main functionality:
* add support for wild-cards, and @objectClass notiation
* add support for configuring additional attributes to be included with delete operations via ecl-include-for-deletes property.
Requires protocol version upgrade which will be handled in final commit.
| | |
| | | NAME 'ds-cfg-ecl-include' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.7 |
| | | NAME 'ds-cfg-ecl-include-for-deletes' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | X-ORIGIN 'OpenDJ Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.603 |
| | | NAME 'ds-cfg-weight' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 |
| | |
| | | STRUCTURAL |
| | | MUST ( cn $ |
| | | ds-cfg-enabled ) |
| | | MAY ( ds-cfg-ecl-include ) |
| | | MAY ( ds-cfg-ecl-include $ ds-cfg-ecl-include-for-deletes ) |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.235 |
| | | NAME 'ds-cfg-collective-attribute-subentries-virtual-attribute' |
| | |
| | | ! |
| | | ! |
| | | ! Copyright 2009 Sun Microsystems, Inc. |
| | | ! Portions copyright 2011 ForgeRock AS |
| | | ! --> |
| | | <adm:managed-object name="external-changelog-domain" |
| | | plural-name="external-changelog-domains" |
| | |
| | | </adm:property> |
| | | <adm:property name="ecl-include" multi-valued="true" mandatory="false"> |
| | | <adm:synopsis> |
| | | Allows to include some target entry attributes in the external changelog. |
| | | Specifies a list of attributes which should be published with every |
| | | change log entry, regardless of whether or not the attribute itself |
| | | has changed. |
| | | </adm:synopsis> |
| | | <adm:description> |
| | | Specifies an attribute that will be included in every External Change Log |
| | | entry related to this replication domain. |
| | | The list of attributes may include wild cards such as "*" and "+" as |
| | | well as object class references prefixed with an ampersand, for |
| | | example "@person". |
| | | The included attributes will be published using the "includedAttributes" |
| | | operational attribute as a single LDIF value rather like the |
| | | "changes" attribute. For modify and modifyDN operations the included |
| | | attributes will be taken from the entry before any changes were applied. |
| | | </adm:description> |
| | | <adm:default-behavior> |
| | | <adm:undefined/> |
| | | </adm:default-behavior> |
| | | <adm:syntax> |
| | | <adm:attribute-type /> |
| | | <!-- FIXME: can we constrain this with a regex? --> |
| | | <adm:string /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | <adm:property name="ecl-include-for-deletes" multi-valued="true" mandatory="false"> |
| | | <adm:synopsis> |
| | | Specifies a list of attributes which should be published with every |
| | | delete operation change log entry, in addition to those specified by the |
| | | "ecl-include" property. |
| | | </adm:synopsis> |
| | | <adm:description> |
| | | This property provides a means for applications to archive entries after |
| | | they have been deleted. See the description of the "ecl-include" property |
| | | for further information about how the included attributes are published. |
| | | </adm:description> |
| | | <adm:default-behavior> |
| | | <adm:undefined/> |
| | | </adm:default-behavior> |
| | | <adm:syntax> |
| | | <!-- FIXME: can we constrain this with a regex? --> |
| | | <adm:string /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:name>ds-cfg-ecl-include-for-deletes</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | </adm:managed-object> |
| | |
| | | user-friendly-name=External Changelog Domain |
| | | user-friendly-plural-name=External Changelog Domains |
| | | synopsis=The External Changelog Domain provides configuration of the external changelog for the replication domain. |
| | | property.ecl-include.synopsis=Allows to include some target entry attributes in the external changelog. |
| | | property.ecl-include.description=Specifies an attribute that will be included in every External Change Log entry related to this replication domain. |
| | | property.ecl-include.synopsis=Specifies a list of attributes which should be published with every change log entry, regardless of whether or not the attribute itself has changed. |
| | | property.ecl-include.description=The list of attributes may include wild cards such as "*" and "+" as well as object class references prefixed with an ampersand, for example "@person". The included attributes will be published using the "includedAttributes" operational attribute as a single LDIF value rather like the "changes" attribute. For modify and modifyDN operations the included attributes will be taken from the entry before any changes were applied. |
| | | property.ecl-include-for-deletes.synopsis=Specifies a list of attributes which should be published with every delete operation change log entry, in addition to those specified by the "ecl-include" property. |
| | | property.ecl-include-for-deletes.description=This property provides a means for applications to archive entries after they have been deleted. See the description of the "ecl-include" property for further information about how the included attributes are published. |
| | | property.enabled.synopsis=Indicates whether the External Changelog Domain is enabled. |
| | |
| | | * |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.common; |
| | | |
| | |
| | | |
| | | private Set<String> eclIncludes = new HashSet<String>(); |
| | | |
| | | private Set<String> eclIncludesForDeletes = new HashSet<String>(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of DSInfo with every given info. |
| | | * |
| | | * @param dsId The DS id |
| | | * @param rsId The RS id the DS is connected to |
| | | * @param generationId The generation id the DS is using |
| | | * @param status The DS status |
| | | * @param assuredFlag DS assured replication enabled or not |
| | | * @param assuredMode DS assured mode |
| | | * @param safeDataLevel DS safe data level |
| | | * @param groupId DS group id |
| | | * @param refUrls DS exported referrals URLs |
| | | * @param eclIncludes The list of entry attributes to include in the ECL. |
| | | * @param protocolVersion Protocol version supported by this server. |
| | | * @param dsId |
| | | * The DS id |
| | | * @param rsId |
| | | * The RS id the DS is connected to |
| | | * @param generationId |
| | | * The generation id the DS is using |
| | | * @param status |
| | | * The DS status |
| | | * @param assuredFlag |
| | | * DS assured replication enabled or not |
| | | * @param assuredMode |
| | | * DS assured mode |
| | | * @param safeDataLevel |
| | | * DS safe data level |
| | | * @param groupId |
| | | * DS group id |
| | | * @param refUrls |
| | | * DS exported referrals URLs |
| | | * @param eclIncludes |
| | | * The list of entry attributes to include in the ECL. |
| | | * @param eclIncludesForDeletes |
| | | * The list of entry attributes to include in the ECL for deletes. |
| | | * @param protocolVersion |
| | | * Protocol version supported by this server. |
| | | */ |
| | | public DSInfo(int dsId, int rsId, long generationId, ServerStatus status, |
| | | boolean assuredFlag, AssuredMode assuredMode, byte safeDataLevel, |
| | | byte groupId, List<String> refUrls, Set<String> eclIncludes, |
| | | short protocolVersion) |
| | | public DSInfo(int dsId, int rsId, long generationId, |
| | | ServerStatus status, boolean assuredFlag, |
| | | AssuredMode assuredMode, byte safeDataLevel, byte groupId, |
| | | List<String> refUrls, Set<String> eclIncludes, |
| | | Set<String> eclIncludesForDeletes, short protocolVersion) |
| | | { |
| | | |
| | | this.dsId = dsId; |
| | | this.rsId = rsId; |
| | | this.generationId = generationId; |
| | |
| | | this.groupId = groupId; |
| | | this.refUrls = refUrls; |
| | | this.eclIncludes = eclIncludes; |
| | | this.eclIncludesForDeletes = eclIncludesForDeletes; |
| | | this.protocolVersion = protocolVersion; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Get the entry attributes to be included in the ECL for delete operations. |
| | | * @return The entry attributes to be included in the ECL. |
| | | */ |
| | | public Set<String> getEclIncludesForDeletes() |
| | | { |
| | | return eclIncludesForDeletes; |
| | | } |
| | | |
| | | /** |
| | | * Get the protocol version supported by this server. |
| | | * Returns -1 when the protocol version is not known (too old version). |
| | | * @return The protocol version. |
| | |
| | | (groupId == dsInfo.getGroupId()) && |
| | | (protocolVersion == dsInfo.getProtocolVersion()) && |
| | | (refUrls.equals(dsInfo.getRefUrls())) && |
| | | (((eclIncludes == null) && (dsInfo.getEclIncludes() == null)) || |
| | | ((eclIncludes != null) && |
| | | (eclIncludes.equals(dsInfo.getEclIncludes()))))); |
| | | (((eclIncludes == null) && (dsInfo.getEclIncludes() == null)) || |
| | | ((eclIncludes != null) && |
| | | (eclIncludes.equals(dsInfo.getEclIncludes())))) && |
| | | (((eclIncludesForDeletes == null) |
| | | && (dsInfo.getEclIncludesForDeletes() == null)) || |
| | | ((eclIncludesForDeletes != null) && |
| | | (eclIncludesForDeletes.equals(dsInfo.getEclIncludesForDeletes()))))); |
| | | } else |
| | | { |
| | | return false; |
| | |
| | | hash = 73 * hash + this.safeDataLevel; |
| | | hash = 73 * hash + (this.refUrls != null ? this.refUrls.hashCode() : 0); |
| | | hash = 73 * hash + (this.eclIncludes != null ? eclIncludes.hashCode() : 0); |
| | | hash = 73 * hash + (this.eclIncludesForDeletes != null ? |
| | | eclIncludesForDeletes.hashCode() : 0); |
| | | hash = 73 * hash + this.groupId; |
| | | hash = 73 * hash + this.protocolVersion; |
| | | return hash; |
| | |
| | | sb.append(refUrls); |
| | | sb.append(" ; ECL Include: "); |
| | | sb.append(eclIncludes); |
| | | sb.append(" ; ECL Include for Deletes: "); |
| | | sb.append(eclIncludesForDeletes); |
| | | return sb.toString(); |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.server.ConfigurationDeleteListener; |
| | | import org.opends.server.admin.std.server.ExternalChangelogDomainCfg; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.ResultCode; |
| | | import java.util.HashSet; |
| | | |
| | | /** |
| | | * This class specifies the external changelog feature for a replication |
| | |
| | | ConfigurationChangeListener<ExternalChangelogDomainCfg> |
| | | { |
| | | |
| | | LDAPReplicationDomain domain; |
| | | boolean isEnabled; |
| | | private LDAPReplicationDomain domain; |
| | | private boolean isEnabled; |
| | | |
| | | /** |
| | | * Constructor from a provided LDAPReplicationDomain. |
| | |
| | | public ExternalChangelogDomain(LDAPReplicationDomain domain, |
| | | ExternalChangelogDomainCfg configuration) |
| | | { |
| | | this.domain =domain; |
| | | this.domain = domain; |
| | | this.isEnabled = configuration.isEnabled(); |
| | | configuration.addChangeListener(this); |
| | | if (configuration.getECLInclude() != null) |
| | | { |
| | | HashSet<String> attrNames = new HashSet<String>(0); |
| | | for (AttributeType eclIncludeAttribute : configuration.getECLInclude()) |
| | | attrNames.add(eclIncludeAttribute.getNormalizedPrimaryName()); |
| | | domain.setEclInclude(domain.getServerId(), attrNames); |
| | | } |
| | | domain.setEclIncludes(domain.getServerId(), |
| | | configuration.getECLInclude(), |
| | | configuration.getECLIncludeForDeletes()); |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | this.isEnabled = configuration.isEnabled(); |
| | | HashSet<String> attrNames = new HashSet<String>(0); |
| | | for (AttributeType eclInclude : configuration.getECLInclude()) |
| | | attrNames.add(eclInclude.getNormalizedPrimaryName()); |
| | | domain.setEclInclude(domain.getServerId(), attrNames); |
| | | domain.setEclIncludes(domain.getServerId(), |
| | | configuration.getECLInclude(), |
| | | configuration.getECLIncludeForDeletes()); |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, false); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | this.isEnabled = configuration.isEnabled(); |
| | | HashSet<String> attrNames = new HashSet<String>(0); |
| | | for (AttributeType eclInclude : configuration.getECLInclude()) |
| | | attrNames.add(eclInclude.getNormalizedPrimaryName()); |
| | | domain.changeConfig(attrNames); |
| | | domain.changeConfig(configuration.getECLInclude(), |
| | | configuration.getECLIncludeForDeletes()); |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, false); |
| | | } |
| | | catch (Exception e) |
| | |
| | | import static org.opends.server.util.StaticUtils.createEntry; |
| | | import static org.opends.server.util.StaticUtils.getFileForPath; |
| | | import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; |
| | | import static org.opends.server.util.StaticUtils.toLowerCase; |
| | | |
| | | import java.io.File; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.io.StringReader; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.NoSuchElementException; |
| | | import java.util.Set; |
| | | import java.util.SortedSet; |
| | | import java.util.StringTokenizer; |
| | | import java.util.TreeMap; |
| | | import java.util.*; |
| | | import java.util.concurrent.BlockingQueue; |
| | | import java.util.concurrent.TimeoutException; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | |
| | | * @param op |
| | | * @throws DirectoryException |
| | | */ |
| | | private void addEntryAttributesForCL(UpdateMsg msg,PostOperationOperation op) |
| | | throws DirectoryException |
| | | private void addEntryAttributesForCL(UpdateMsg msg, |
| | | PostOperationOperation op) throws DirectoryException |
| | | { |
| | | String[] entryAttributeNames = |
| | | getEclInclude().toArray(new String[0]); |
| | | ArrayList<Attribute> newattrs = new ArrayList<Attribute>(); |
| | | |
| | | if (op instanceof PostOperationDeleteOperation) |
| | | { |
| | | Entry entry = null; |
| | | PostOperationDeleteOperation delOp = (PostOperationDeleteOperation)op; |
| | | entry = delOp.getEntryToDelete(); |
| | | for (String name : entryAttributeNames) |
| | | { |
| | | AttributeType atype = DirectoryServer.getAttributeType(name); |
| | | List<Attribute> attrs = entry.getAttribute(atype); |
| | | if (attrs != null) |
| | | for (Attribute a : attrs) |
| | | newattrs.add(a); |
| | | } |
| | | ((DeleteMsg)msg).setEclIncludes(newattrs); |
| | | Set<String> names = getEclIncludesForDeletes(); |
| | | PostOperationDeleteOperation delOp = (PostOperationDeleteOperation) op; |
| | | Entry entry = delOp.getEntryToDelete(); |
| | | ((DeleteMsg) msg).setEclIncludes(getIncludedAttributes(entry, names)); |
| | | |
| | | // For delete only, add the Authorized DN since it's required in the |
| | | // ECL entry but is not part of rest of the message. |
| | | DN deleterDN = delOp.getAuthorizationDN(); |
| | | if (deleterDN != null) |
| | | { |
| | | ((DeleteMsg)msg).setInitiatorsName(deleterDN.toString()); |
| | | ((DeleteMsg) msg).setInitiatorsName(deleterDN.toString()); |
| | | } |
| | | |
| | | } |
| | | else if (op instanceof PostOperationModifyOperation) |
| | | { |
| | | Entry entry = null; |
| | | PostOperationModifyOperation modOp = (PostOperationModifyOperation)op; |
| | | entry = modOp.getCurrentEntry(); |
| | | for (String name : entryAttributeNames) |
| | | { |
| | | AttributeType atype = DirectoryServer.getAttributeType(name); |
| | | List<Attribute> attrs = entry.getAttribute(atype); |
| | | if (attrs != null) |
| | | for (Attribute a : attrs) |
| | | newattrs.add(a); |
| | | } |
| | | ((ModifyMsg)msg).setEclIncludes(newattrs); |
| | | Set<String> names = getEclIncludes(); |
| | | PostOperationModifyOperation modOp = (PostOperationModifyOperation) op; |
| | | Entry entry = modOp.getCurrentEntry(); |
| | | ((ModifyMsg) msg).setEclIncludes(getIncludedAttributes(entry, names)); |
| | | } |
| | | else if (op instanceof PostOperationModifyDNOperation) |
| | | { |
| | | Entry entry = null; |
| | | Set<String> names = getEclIncludes(); |
| | | PostOperationModifyDNOperation modDNOp = |
| | | (PostOperationModifyDNOperation)op; |
| | | entry = modDNOp.getOriginalEntry(); |
| | | for (String name : entryAttributeNames) |
| | | { |
| | | AttributeType atype = DirectoryServer.getAttributeType(name); |
| | | List<Attribute> attrs = entry.getAttribute(atype); |
| | | if (attrs != null) |
| | | for (Attribute a : attrs) |
| | | newattrs.add(a); |
| | | } |
| | | ((ModifyDNMsg)msg).setEclIncludes(newattrs); |
| | | (PostOperationModifyDNOperation) op; |
| | | Entry entry = modDNOp.getOriginalEntry(); |
| | | ((ModifyDNMsg) msg).setEclIncludes(getIncludedAttributes(entry, names)); |
| | | } |
| | | else if (op instanceof PostOperationAddOperation) |
| | | { |
| | | Entry entry = null; |
| | | PostOperationAddOperation addOp = (PostOperationAddOperation)op; |
| | | entry = addOp.getEntryToAdd(); |
| | | for (String name : entryAttributeNames) |
| | | { |
| | | AttributeType atype = DirectoryServer.getAttributeType(name); |
| | | List<Attribute> attrs = entry.getAttribute(atype); |
| | | if (attrs != null) |
| | | { |
| | | for (Attribute a : attrs) |
| | | newattrs.add(a); |
| | | } |
| | | else |
| | | { |
| | | // FIXME:ECL |
| | | } |
| | | } |
| | | ((AddMsg)msg).setEclIncludes(newattrs); |
| | | Set<String> names = getEclIncludes(); |
| | | PostOperationAddOperation addOp = (PostOperationAddOperation) op; |
| | | Entry entry = addOp.getEntryToAdd(); |
| | | ((AddMsg) msg).setEclIncludes(getIncludedAttributes(entry, names)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private Collection<Attribute> getIncludedAttributes(Entry entry, |
| | | Set<String> names) |
| | | { |
| | | if (names.isEmpty()) |
| | | { |
| | | // Fast-path. |
| | | return Collections.emptySet(); |
| | | } |
| | | else if (names.size() == 1 && names.contains("*")) |
| | | { |
| | | // Potential fast-path for delete operations. |
| | | LinkedList<Attribute> attributes = new LinkedList<Attribute>(); |
| | | for (List<Attribute> alist : entry.getUserAttributes().values()) |
| | | { |
| | | attributes.addAll(alist); |
| | | } |
| | | Attribute ocattr = entry.getObjectClassAttribute(); |
| | | if (ocattr != null) |
| | | { |
| | | attributes.add(ocattr); |
| | | } |
| | | return attributes; |
| | | } |
| | | else |
| | | { |
| | | // Expand @objectclass references in attribute list if needed. We |
| | | // do this now in order to take into account dynamic schema changes. |
| | | |
| | | // Only rebuild the attribute set if necessary. |
| | | boolean needsExpanding = false; |
| | | for (String name : names) |
| | | { |
| | | if (name.startsWith("@")) |
| | | { |
| | | needsExpanding = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | Set<String> expandedNames; |
| | | if (needsExpanding) |
| | | { |
| | | expandedNames = new HashSet<String>(names.size()); |
| | | for (String name : names) |
| | | { |
| | | if (name.startsWith("@")) |
| | | { |
| | | String ocName = name.substring(1); |
| | | ObjectClass objectClass = DirectoryServer |
| | | .getObjectClass(toLowerCase(ocName)); |
| | | if (objectClass != null) |
| | | { |
| | | for (AttributeType at : objectClass |
| | | .getRequiredAttributeChain()) |
| | | { |
| | | expandedNames.add(at.getNameOrOID()); |
| | | } |
| | | for (AttributeType at : objectClass |
| | | .getOptionalAttributeChain()) |
| | | { |
| | | expandedNames.add(at.getNameOrOID()); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | expandedNames.add(name); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | expandedNames = names; |
| | | } |
| | | |
| | | Entry filteredEntry = entry.filterEntry(expandedNames, false, |
| | | false, false); |
| | | return filteredEntry.getAttributes(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Gets the fractional configuration of this domain. |
| | | * @return The fractional configuration of this domain. |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.protocol; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Collection; |
| | | import java.util.zip.DataFormatException; |
| | | |
| | | import org.opends.server.protocols.asn1.ASN1; |
| | |
| | | /** |
| | | * Encode a list of attributes. |
| | | */ |
| | | static private byte[] encodeAttributes(List<Attribute> attributes) |
| | | static private byte[] encodeAttributes(Collection<Attribute> attributes) |
| | | { |
| | | if (attributes==null) |
| | | return new byte[0]; |
| | |
| | | * Set a provided list of entry attributes. |
| | | * @param entryAttrs The provided list of entry attributes. |
| | | */ |
| | | public void setEclIncludes(List<Attribute> entryAttrs) |
| | | public void setEclIncludes(Collection<Attribute> entryAttrs) |
| | | { |
| | | this.encodedEclIncludes = encodeAttributes(entryAttrs); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.protocol; |
| | | |
| | |
| | | |
| | | private Set<String> eclIncludes = new HashSet<String>(); |
| | | |
| | | private Set<String> eclIncludesForDeletes = new HashSet<String>(); |
| | | |
| | | /** |
| | | * The protocolVersion that should be used when serializing this message. |
| | | */ |
| | |
| | | } |
| | | else |
| | | { |
| | | decode_V4(in); |
| | | decode_V4(in, version); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | else |
| | | { |
| | | return getBytes_V4(); |
| | | return getBytes_V4(protocolVersion); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | else |
| | | { |
| | | return getBytes_V4(); |
| | | return getBytes_V4(reqProtocolVersion); |
| | | } |
| | | } |
| | | |
| | | private byte[] getBytes_V4() |
| | | private byte[] getBytes_V4(short version) |
| | | { |
| | | try |
| | | { |
| | |
| | | |
| | | writer.writeStartSequence(); |
| | | for (String attrDef : eclIncludes) |
| | | { |
| | | writer.writeOctetString(attrDef); |
| | | } |
| | | writer.writeEndSequence(); |
| | | |
| | | writer.writeStartSequence(); |
| | | for (String attrDef : eclIncludesForDeletes) |
| | | { |
| | | writer.writeOctetString(attrDef); |
| | | } |
| | | writer.writeEndSequence(); |
| | | |
| | | return byteBuilder.toByteArray(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | return null; |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | |
| | | // Msg decoding |
| | | // ============ |
| | | |
| | | private void decode_V4(byte[] in) |
| | | private void decode_V4(byte[] in, short version) |
| | | throws DataFormatException |
| | | { |
| | | ByteSequenceReader reader = ByteString.wrap(in).asReader(); |
| | |
| | | this.eclIncludes.add(s); |
| | | } |
| | | asn1Reader.readEndSequence(); |
| | | |
| | | asn1Reader.readStartSequence(); |
| | | while (asn1Reader.hasNextElement()) |
| | | { |
| | | String s = asn1Reader.readOctetStringAsString(); |
| | | this.eclIncludesForDeletes.add(s); |
| | | } |
| | | asn1Reader.readEndSequence(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | "\nassuredMode: " + assuredMode + |
| | | "\nsafeDataLevel: " + safeDataLevel + |
| | | "\nreferralsURLs: " + urls + |
| | | "\nEclIncludes: " + eclIncludes); |
| | | "\nEclIncludes " + eclIncludes + |
| | | "\nEclIncludeForDeletes: " + eclIncludesForDeletes); |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | /** |
| | | * Set the list of entry attributes to include in the ECL. |
| | | * @param eclIncludes The list of attributes. |
| | | * Set the attributes configured on a server to be included in the ECL. |
| | | * |
| | | * @param includeAttributes |
| | | * attributes to be included with all change records. |
| | | * @param includeAttributesForDeletes |
| | | * additional attributes to be included with delete change records. |
| | | */ |
| | | public void setEclIncludes(Set<String> eclIncludes) |
| | | public void setEclIncludes( |
| | | Set<String> includeAttributes, |
| | | Set<String> includeAttributesForDeletes) |
| | | { |
| | | if (eclIncludes != null) |
| | | this.eclIncludes = eclIncludes; |
| | | if (includeAttributes != null) |
| | | { |
| | | eclIncludes = includeAttributes; |
| | | } |
| | | |
| | | if (includeAttributesForDeletes != null) |
| | | { |
| | | eclIncludesForDeletes = includeAttributesForDeletes; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Get the list of entry attributes to include in the ECL.. |
| | | * @return The list of entry attributes to include in the ECL. |
| | | * Get the attributes to include in each change for the ECL. |
| | | * |
| | | * @return The attributes to include in each change for the ECL. |
| | | */ |
| | | public Set<String> getEclIncludes() |
| | | { |
| | | return eclIncludes; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get the attributes to include in each delete change for the ECL. |
| | | * |
| | | * @return The attributes to include in each delete change for the ECL. |
| | | */ |
| | | public Set<String> getEclIncludesForDeletes() |
| | | { |
| | | return eclIncludesForDeletes; |
| | | } |
| | | |
| | | } |
| | |
| | | } |
| | | |
| | | Set<String> attrs = new HashSet<String>(); |
| | | Set<String> delattrs = new HashSet<String>(); |
| | | short protocolVersion = -1; |
| | | if (version>=ProtocolVersion.REPLICATION_PROTOCOL_V4) |
| | | if (version >= ProtocolVersion.REPLICATION_PROTOCOL_V4) |
| | | { |
| | | byte nAttrs = in[pos++]; |
| | | nRead = 0; |
| | | /* Read attrs until expected number read */ |
| | | while ((nRead != nAttrs) && |
| | | (pos < in.length) //security |
| | | ) |
| | | while ((nRead != nAttrs) && (pos < in.length)) |
| | | { |
| | | length = getNextLength(in, pos); |
| | | String attr = new String(in, pos, length, "UTF-8"); |
| | |
| | | pos += length + 1; |
| | | nRead++; |
| | | } |
| | | |
| | | nAttrs = in[pos++]; |
| | | nRead = 0; |
| | | /* Read attrs until expected number read */ |
| | | while ((nRead != nAttrs) && (pos < in.length)) |
| | | { |
| | | length = getNextLength(in, pos); |
| | | String attr = new String(in, pos, length, "UTF-8"); |
| | | delattrs.add(attr); |
| | | pos += length + 1; |
| | | nRead++; |
| | | } |
| | | |
| | | /* Read Protocol version */ |
| | | protocolVersion = Short.valueOf(in[pos++]); |
| | | } |
| | |
| | | |
| | | DSInfo dsInfo = new DSInfo(dsId, rsId, generationId, status, |
| | | assuredFlag, assuredMode, safeDataLevel, groupId, refUrls, attrs, |
| | | protocolVersion); |
| | | delattrs, protocolVersion); |
| | | dsList.add(dsInfo); |
| | | |
| | | nDsInfo--; |
| | |
| | | oStream.write(attr.getBytes("UTF-8")); |
| | | oStream.write(0); |
| | | } |
| | | |
| | | Set<String> delattrs = dsInfo.getEclIncludesForDeletes(); |
| | | oStream.write(delattrs.size()); |
| | | for (String attr : delattrs) |
| | | { |
| | | oStream.write(attr.getBytes("UTF-8")); |
| | | oStream.write(0); |
| | | } |
| | | |
| | | oStream.write(dsInfo.getProtocolVersion()); |
| | | } |
| | | |
| | | } |
| | | |
| | | // Put number of following RS info entries |
| | |
| | | // DS safe data level (relevant if assured mode is safe data) |
| | | private byte safeDataLevel = (byte) -1; |
| | | private Set<String> eclIncludes = new HashSet<String>(); |
| | | private Set<String> eclIncludesForDeletes = new HashSet<String>(); |
| | | |
| | | /** |
| | | * Creates a new data server handler. |
| | |
| | | { |
| | | DSInfo dsInfo = new DSInfo(serverId, replicationServerId, generationId, |
| | | status, assuredFlag, assuredMode, safeDataLevel, groupId, refUrls, |
| | | eclIncludes, protocolVersion); |
| | | eclIncludes, eclIncludesForDeletes, protocolVersion); |
| | | |
| | | return dsInfo; |
| | | } |
| | |
| | | this.assuredMode = startSessionMsg.getAssuredMode(); |
| | | this.safeDataLevel = startSessionMsg.getSafeDataLevel(); |
| | | this.eclIncludes = startSessionMsg.getEclIncludes(); |
| | | this.eclIncludesForDeletes = startSessionMsg.getEclIncludesForDeletes(); |
| | | |
| | | /* |
| | | * If we have already a generationID set for the domain |
| | |
| | | private short protocolVersion = -1; |
| | | |
| | | private Set<String> eclInclude = new HashSet<String>(); |
| | | private Set<String> eclIncludeForDeletes = new HashSet<String>(); |
| | | |
| | | /** |
| | | * Creates a new LighweightServerHandler with the provided serverid, connected |
| | |
| | | * @param assuredMode The assured mode of the remote DS |
| | | * @param safeDataLevel The safe data level of the remote DS |
| | | * @param eclInclude The list of entry attributes to be added to the ECL. |
| | | * @param eclIncludeForDeletes The list of entry attributes to be added to |
| | | * the ECL. |
| | | * @param protocolVersion The protocol version supported by the remote DS. |
| | | */ |
| | | public LightweightServerHandler(ReplicationServerHandler replServerHandler, |
| | | int replicationServerId, int serverId, long generationId, byte groupId, |
| | | ServerStatus status, List<String> refUrls, boolean assuredFlag, |
| | | AssuredMode assuredMode, byte safeDataLevel, Set<String> eclInclude, |
| | | short protocolVersion) |
| | | Set<String> eclIncludeForDeletes, short protocolVersion) |
| | | { |
| | | this.replServerHandler = replServerHandler; |
| | | this.rsDomain = replServerHandler.getDomain(); |
| | |
| | | this.assuredMode = assuredMode; |
| | | this.safeDataLevel = safeDataLevel; |
| | | this.eclInclude = eclInclude; |
| | | this.eclIncludeForDeletes = eclIncludeForDeletes; |
| | | this.protocolVersion = protocolVersion; |
| | | |
| | | if (debugEnabled()) |
| | |
| | | { |
| | | DSInfo dsInfo = new DSInfo(serverId, replicationServerId, generationId, |
| | | status, assuredFlag, assuredMode, safeDataLevel, groupId, refUrls, |
| | | eclInclude, protocolVersion); |
| | | eclInclude, eclIncludeForDeletes, protocolVersion); |
| | | |
| | | return dsInfo; |
| | | } |
| | |
| | | dsInfo.isAssured(), dsInfo.getAssuredMode(), |
| | | dsInfo.getSafeDataLevel(), |
| | | dsInfo.getEclIncludes(), |
| | | dsInfo.getEclIncludesForDeletes(), |
| | | dsInfo.getProtocolVersion()); |
| | | lsh.startHandler(); |
| | | remoteDirectoryServers.put(lsh.getServerId(), lsh); |
| | |
| | | domain.getAssuredMode(), |
| | | domain.getAssuredSdLevel()); |
| | | startSessionMsg.setEclIncludes( |
| | | domain.getEclInclude(domain.getServerId())); |
| | | } else |
| | | domain.getEclIncludes(domain.getServerId()), |
| | | domain.getEclIncludesForDeletes(domain.getServerId())); |
| | | } |
| | | else |
| | | { |
| | | startSessionMsg = |
| | | new StartSessionMsg(initStatus, new ArrayList<String>()); |
| | |
| | | if (domain != null) |
| | | { |
| | | for (DSInfo info : dsList) |
| | | domain.setEclInclude(info.getDsId(), info.getEclIncludes()); |
| | | { |
| | | domain.setEclIncludes(info.getDsId(), info.getEclIncludes(), |
| | | info.getEclIncludesForDeletes()); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.net.SocketTimeoutException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.SortedMap; |
| | | import java.util.TreeMap; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeoutException; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | |
| | | */ |
| | | private final ChangeNumberGenerator generator; |
| | | |
| | | private final Map<Integer, Set<String>> eclIncludeByServer = |
| | | new ConcurrentHashMap<Integer, Set<String>>(); |
| | | Set<String> crossServersECLIncludes = new HashSet<String>(); |
| | | private final Object eclIncludesLock = new Object(); |
| | | private final Map<Integer, Set<String>> eclIncludesByServer = |
| | | new HashMap<Integer, Set<String>>(); |
| | | private Set<String> eclIncludesAllServers = Collections.emptySet(); |
| | | |
| | | private final Map<Integer, Set<String>> eclIncludesForDeletesByServer = |
| | | new HashMap<Integer, Set<String>>(); |
| | | private Set<String> eclIncludesForDeletesAllServers = Collections |
| | | .emptySet(); |
| | | |
| | | /** |
| | | * An object used to protect the initialization of the underlying broker |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Change some ReplicationDomain parameters : the ECL include attribute. |
| | | * Applies a configuration change to the attributes which should be be |
| | | * included in the ECL. |
| | | * |
| | | * @param newECLInclude The new ECL attribute. |
| | | * @param includeAttributes |
| | | * attributes to be included with all change records. |
| | | * @param includeAttributesForDeletes |
| | | * additional attributes to be included with delete change records. |
| | | */ |
| | | public void changeConfig(Set<String> newECLInclude) |
| | | public void changeConfig(Set<String> includeAttributes, |
| | | Set<String> includeAttributesForDeletes) |
| | | { |
| | | boolean configECLIncludeChanged = false; |
| | | Set<String> currentECLInclude = this.getEclInclude(serverID); |
| | | |
| | | if (newECLInclude.size() != currentECLInclude.size()) |
| | | if (setEclIncludes(serverID, includeAttributes, |
| | | includeAttributesForDeletes)) |
| | | { |
| | | configECLIncludeChanged = true; |
| | | } |
| | | else |
| | | { |
| | | // compare current config and new config |
| | | for (String attr : currentECLInclude) |
| | | { |
| | | if (!newECLInclude.contains(attr)) |
| | | { |
| | | configECLIncludeChanged = true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (configECLIncludeChanged) |
| | | { |
| | | // set new config |
| | | this.setEclInclude(this.serverID, newECLInclude); |
| | | if (broker != null) |
| | | { |
| | | disableService(); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * This method should trigger an export of the replicated data. |
| | | * to the provided outputStream. |
| | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Set the attributes configured on a server to be included in the ECL. |
| | | * @param serverId server where these attributes are configured. |
| | | * @param attributes the configured attributes. |
| | | * Set the attributes configured on a server to be included in the ECL. |
| | | * |
| | | * @param serverId |
| | | * Server where these attributes are configured. |
| | | * @param includeAttributes |
| | | * Attributes to be included with all change records, may include |
| | | * wild-cards. |
| | | * @param includeAttributesForDeletes |
| | | * Additional attributes to be included with delete change records, |
| | | * may include wild-cards. |
| | | * @return {@code true} if the set of attributes was modified. |
| | | */ |
| | | public void setEclInclude(int serverId, Set<String> attributes) |
| | | public boolean setEclIncludes(int serverId, |
| | | Set<String> includeAttributes, |
| | | Set<String> includeAttributesForDeletes) |
| | | { |
| | | synchronized(eclIncludeByServer) |
| | | boolean configurationChanged = false; |
| | | |
| | | synchronized (eclIncludesLock) |
| | | { |
| | | eclIncludeByServer.put(serverId, attributes); |
| | | Set<String> s1 = new HashSet<String>(includeAttributes); |
| | | |
| | | // Combine all+delete attributes. |
| | | Set<String> s2 = new HashSet<String>(s1); |
| | | s2.addAll(includeAttributesForDeletes); |
| | | |
| | | Set<String> s = eclIncludesByServer.get(serverId); |
| | | if (!s1.equals(s)) |
| | | { |
| | | configurationChanged = true; |
| | | eclIncludesByServer.put(serverId, Collections.unmodifiableSet(s1)); |
| | | } |
| | | |
| | | s = eclIncludesForDeletesByServer.get(serverId); |
| | | if (!s2.equals(s)) |
| | | { |
| | | configurationChanged = true; |
| | | eclIncludesForDeletesByServer.put(serverId, |
| | | Collections.unmodifiableSet(s2)); |
| | | } |
| | | |
| | | // and rebuild the global list to be ready for usage |
| | | crossServersECLIncludes.clear(); |
| | | for (Set<String> attributesByServer : eclIncludeByServer.values()) |
| | | for (String attribute : attributesByServer) |
| | | crossServersECLIncludes.add(attribute); |
| | | s = new HashSet<String>(); |
| | | for (Set<String> attributes : eclIncludesByServer.values()) |
| | | { |
| | | s.addAll(attributes); |
| | | } |
| | | eclIncludesAllServers = Collections.unmodifiableSet(s); |
| | | |
| | | s = new HashSet<String>(); |
| | | for (Set<String> attributes : eclIncludesForDeletesByServer.values()) |
| | | { |
| | | s.addAll(attributes); |
| | | } |
| | | eclIncludesForDeletesAllServers = Collections.unmodifiableSet(s); |
| | | } |
| | | |
| | | return configurationChanged; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get the attributes to include in each change for the ECL. |
| | | * It's a set : an attribute appears once even if configured on more than one |
| | | * server. |
| | | * |
| | | * @return The attributes to include in each change for the ECL. |
| | | */ |
| | | public Set<String> getEclInclude() |
| | | public Set<String> getEclIncludes() |
| | | { |
| | | return crossServersECLIncludes; |
| | | } |
| | | |
| | | /** |
| | | * Get the attributes to include in each change for the ECL |
| | | * for a given serverId. |
| | | * @param serverId The serverId for which we want the include attributes. |
| | | * @return The attributes. |
| | | */ |
| | | public Set<String> getEclInclude(int serverId) |
| | | { |
| | | synchronized(eclIncludeByServer) |
| | | synchronized (eclIncludesLock) |
| | | { |
| | | return eclIncludeByServer.get(serverId); |
| | | return eclIncludesAllServers; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get the attributes to include in each delete change for the ECL. |
| | | * |
| | | * @return The attributes to include in each delete change for the ECL. |
| | | */ |
| | | public Set<String> getEclIncludesForDeletes() |
| | | { |
| | | synchronized (eclIncludesLock) |
| | | { |
| | | return eclIncludesForDeletesAllServers; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get the attributes to include in each change for the ECL for a given |
| | | * serverId. |
| | | * |
| | | * @param serverId |
| | | * The serverId for which we want the include attributes. |
| | | * @return The attributes. |
| | | */ |
| | | public Set<String> getEclIncludes(int serverId) |
| | | { |
| | | synchronized (eclIncludesLock) |
| | | { |
| | | return eclIncludesByServer.get(serverId); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get the attributes to include in each change for the ECL for a given |
| | | * serverId. |
| | | * |
| | | * @param serverId |
| | | * The serverId for which we want the include attributes. |
| | | * @return The attributes. |
| | | */ |
| | | public Set<String> getEclIncludesForDeletes(int serverId) |
| | | { |
| | | synchronized (eclIncludesLock) |
| | | { |
| | | return eclIncludesForDeletesByServer.get(serverId); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the ChangeNUmber of the last Change that was fully processed |
| | | * by this ReplicationDomain. |
| | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | toString(buffer); |
| | | return buffer.toString(); |
| | | return toLDIFString(); |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | public void toString(StringBuilder buffer) |
| | | { |
| | | buffer.append("Entry(dn=\""); |
| | | dn.toString(buffer); |
| | | |
| | | buffer.append("\", objectClasses={"); |
| | | if (! objectClasses.isEmpty()) |
| | | { |
| | | Iterator<String> ocNames = objectClasses.values().iterator(); |
| | | buffer.append(ocNames.next()); |
| | | |
| | | while (ocNames.hasNext()) |
| | | { |
| | | buffer.append(","); |
| | | buffer.append(ocNames.next()); |
| | | } |
| | | } |
| | | |
| | | buffer.append("}, userAttrs={"); |
| | | if (! userAttributes.isEmpty()) |
| | | { |
| | | Iterator<AttributeType> attrs = |
| | | userAttributes.keySet().iterator(); |
| | | buffer.append(attrs.next().getNameOrOID()); |
| | | |
| | | while (attrs.hasNext()) |
| | | { |
| | | buffer.append(","); |
| | | buffer.append(attrs.next().getNameOrOID()); |
| | | } |
| | | } |
| | | |
| | | buffer.append("}, operationalAttrs={"); |
| | | if (! operationalAttributes.isEmpty()) |
| | | { |
| | | Iterator<AttributeType> attrs = |
| | | operationalAttributes.keySet().iterator(); |
| | | buffer.append(attrs.next().getNameOrOID()); |
| | | |
| | | while (attrs.hasNext()) |
| | | { |
| | | buffer.append(","); |
| | | buffer.append(attrs.next().getNameOrOID()); |
| | | } |
| | | } |
| | | |
| | | buffer.append("})"); |
| | | buffer.append(toString()); |
| | | } |
| | | |
| | | |
| | |
| | | import java.io.StringReader; |
| | | import java.net.ServerSocket; |
| | | import java.net.Socket; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.NoSuchElementException; |
| | | import java.util.Set; |
| | | import java.util.SortedSet; |
| | | import java.util.TreeSet; |
| | | import java.util.*; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.api.Backend; |
| | |
| | | import org.opends.server.types.AbstractOperation; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeBuilder; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.Attributes; |
| | | import org.opends.server.types.ByteString; |
| | |
| | | DomainFakeCfg domainConf = |
| | | new DomainFakeCfg(baseDn2, 1602, replServers); |
| | | ExternalChangelogDomainFakeCfg eclCfg = |
| | | new ExternalChangelogDomainFakeCfg(true, null); |
| | | new ExternalChangelogDomainFakeCfg(true, null, null); |
| | | domainConf.setExternalChangelogDomain(eclCfg); |
| | | LDAPReplicationDomain domain2 = |
| | | MultimasterReplication.createNewDomain(domainConf); |
| | |
| | | } |
| | | |
| | | eclCfg = |
| | | new ExternalChangelogDomainFakeCfg(false, null); |
| | | new ExternalChangelogDomainFakeCfg(false, null, null); |
| | | domainConf.setExternalChangelogDomain(eclCfg); |
| | | domain2.applyConfigurationChange(domainConf); |
| | | |
| | |
| | | new DomainFakeCfg(baseDn2, 1702, replServers); |
| | | |
| | | // on o=test2,sid=1702 include attrs set to : 'sn' |
| | | SortedSet<AttributeType> eclInclude = new TreeSet<AttributeType>(); |
| | | eclInclude.add(DirectoryServer.getAttributeType("sn")); |
| | | eclInclude.add(DirectoryServer.getAttributeType("roomnumber")); |
| | | SortedSet<String> eclInclude = new TreeSet<String>(); |
| | | eclInclude.add("sn"); |
| | | eclInclude.add("roomnumber"); |
| | | ExternalChangelogDomainFakeCfg eclCfg = |
| | | new ExternalChangelogDomainFakeCfg(true, eclInclude); |
| | | new ExternalChangelogDomainFakeCfg(true, eclInclude, eclInclude); |
| | | domainConf.setExternalChangelogDomain(eclCfg); |
| | | // Set a Changetime heartbeat interval low enough (less than default |
| | | // value that is 1000 ms) for the test to be sure to consider all changes |
| | |
| | | new DomainFakeCfg(baseDn3, 1703, replServers); |
| | | |
| | | // on o=test3,sid=1703 include attrs set to : 'objectclass' |
| | | eclInclude = new TreeSet<AttributeType>(); |
| | | eclInclude.add(DirectoryServer.getAttributeType("objectclass")); |
| | | eclCfg = |
| | | new ExternalChangelogDomainFakeCfg(true, eclInclude); |
| | | eclInclude = new TreeSet<String>(); |
| | | eclInclude.add("objectclass"); |
| | | |
| | | TreeSet<String> eclIncludeForDeletes = new TreeSet<String>(); |
| | | eclIncludeForDeletes.add("*"); |
| | | |
| | | eclCfg = new ExternalChangelogDomainFakeCfg(true, eclInclude, eclIncludeForDeletes); |
| | | domainConf.setExternalChangelogDomain(eclCfg); |
| | | // Set a Changetime heartbeat interval low enough (less than default |
| | | // value that is 1000 ms) for the test to be sure to consider all changes |
| | |
| | | // on o=test2,sid=1704 include attrs set to : 'cn' |
| | | domainConf = |
| | | new DomainFakeCfg(baseDn2, 1704, replServers); |
| | | eclInclude = new TreeSet<AttributeType>(); |
| | | eclInclude.add(DirectoryServer.getAttributeType("cn")); |
| | | eclInclude = new TreeSet<String>(); |
| | | eclInclude.add("cn"); |
| | | |
| | | eclCfg = |
| | | new ExternalChangelogDomainFakeCfg(true, eclInclude); |
| | | new ExternalChangelogDomainFakeCfg(true, eclInclude, eclInclude); |
| | | domainConf.setExternalChangelogDomain(eclCfg); |
| | | // Set a Changetime heartbeat interval low enough (less than default |
| | | // value that is 1000 ms) for the test to be sure to consider all changes |
| | |
| | | |
| | | HashSet<String> eoc = new HashSet<String>(); |
| | | eoc.add("person");eoc.add("inetOrgPerson");eoc.add("organizationalPerson");eoc.add("top"); |
| | | assertEquals(targetEntry.getAttributes().size(), 0); // objectClass is handled separately |
| | | checkValues(targetEntry,"objectclass",eoc); |
| | | |
| | | String changeType = getAttributeValue(resultEntry, |
| | | "changetype"); |
| | | if (changeType.equals("delete")) |
| | | { |
| | | // We are using "*" for deletes so should get back 4 attributes. |
| | | assertEquals(targetEntry.getAttributes().size(), 4); |
| | | checkValue(targetEntry, "uid", "robert"); |
| | | checkValue(targetEntry, "cn", "Robert Hue2"); |
| | | checkValue(targetEntry, "telephonenumber", "555555"); |
| | | checkValue(targetEntry, "sn", "Robby"); |
| | | } |
| | | else |
| | | { |
| | | assertEquals(targetEntry.getAttributes().size(), 0); |
| | | } |
| | | } |
| | | if (targetdn.endsWith("cn=fiona jensen,o=test2")) |
| | | { |
| | |
| | | * |
| | | * |
| | | * Copyright 2007-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | private SortedSet<String> fractionalExcludes = new TreeSet<String>(); |
| | | private SortedSet<String> fractionalIncludes = new TreeSet<String>(); |
| | | |
| | | private SortedSet<String> eclIncludes = new TreeSet<String>(); |
| | | private ExternalChangelogDomainCfg eclCfg = |
| | | new ExternalChangelogDomainFakeCfg(true, new TreeSet<AttributeType>()); |
| | | new ExternalChangelogDomainFakeCfg(true, null, null); |
| | | |
| | | /** |
| | | * Creates a new Domain with the provided information |
| | |
| | | return true; |
| | | } |
| | | |
| | | public void setEclIncludes(SortedSet<String> attrs) |
| | | { |
| | | this.eclIncludes = attrs; |
| | | } |
| | | |
| | | public SortedSet<String> getECLInclude() |
| | | { |
| | | return this.eclIncludes; |
| | | } |
| | | |
| | | public long getInitializationHeartbeatInterval() |
| | | { |
| | | return 180; |
| | |
| | | { |
| | | return true; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Gets the "conflicts-historical-purge-delay" property. |
| | | * <p> |
| | |
| | | * |
| | | * |
| | | * Copyright 2007-2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | | import java.util.SortedSet; |
| | | import java.util.TreeSet; |
| | | |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.server.ExternalChangelogDomainCfg; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.DN; |
| | | |
| | | /** |
| | | * This class implement a configuration object for the ExternalChangelog domain |
| | | * that can be used in unit tests to instantiate ExternalChangelogDomain. |
| | | */ |
| | | public class ExternalChangelogDomainFakeCfg |
| | | public class ExternalChangelogDomainFakeCfg |
| | | implements ExternalChangelogDomainCfg |
| | | { |
| | | |
| | | // The value of the "ecl-include" property. |
| | | private SortedSet<AttributeType> pECLInclude; |
| | | private SortedSet<String> pECLInclude; |
| | | |
| | | // The value of the "ecl-include-for-deletes" property. |
| | | private SortedSet<String> pECLIncludeForDeletes; |
| | | |
| | | // The value of the "enabled" property. |
| | | private boolean pEnabled; |
| | | |
| | | private DN pDN; |
| | | |
| | | |
| | | /** |
| | | * Creates a new Domain with the provided information |
| | | * (assured mode disabled, default group id) |
| | | */ |
| | | public ExternalChangelogDomainFakeCfg(boolean isEnabled, |
| | | SortedSet<AttributeType> eCLInclude) |
| | | SortedSet<String> eclInclude, |
| | | SortedSet<String> eclIncludeForDeletes) |
| | | { |
| | | this.pEnabled = isEnabled; |
| | | this.pECLInclude = eCLInclude; |
| | | this.pECLInclude = eclInclude != null ? eclInclude : new TreeSet<String>(); |
| | | this.pECLIncludeForDeletes = eclIncludeForDeletes != null ? eclIncludeForDeletes : new TreeSet<String>(); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Gets the "ecl-include" property. |
| | | * <p> |
| | | * Allows to include some target entry attributes in the external |
| | | * changelog. |
| | | * <p> |
| | | * Specifies an attribute that will be included in every External |
| | | * Change Log entry related to this replication domain. |
| | | * |
| | | * @return Returns an unmodifiable set containing the values of the "ecl-include" property. |
| | | */ |
| | | public SortedSet<AttributeType> getECLInclude() |
| | | public SortedSet<String> getECLInclude() |
| | | { |
| | | return this.pECLInclude; |
| | | } |
| | | |
| | | /** |
| | | * Set eclInclude. |
| | | * @param eclInclude the attribute to include. |
| | | */ |
| | | public void setECLInclude(SortedSet<AttributeType> eclInclude) |
| | | public SortedSet<String> getECLIncludeForDeletes() |
| | | { |
| | | this.pECLInclude = eclInclude; |
| | | return this.pECLIncludeForDeletes; |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | return this.pEnabled; |
| | | } |
| | | |
| | | |
| | | public DN dn() |
| | | { |
| | | return pDN; |
| | |
| | | * |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | | import java.net.UnknownHostException; |
| | | import java.util.logging.Level; |
| | | import java.util.logging.Logger; |
| | | import static org.opends.server.TestCaseUtils.TEST_ROOT_DN_STRING; |
| | | import static org.opends.server.loggers.ErrorLogger.logError; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; |
| | |
| | | } |
| | | |
| | | return new DSInfo(dsId, rsId, TEST_DN_WITH_ROOT_ENTRY_GENID, status, assuredFlag, assMode, |
| | | (byte)assuredSdLevel, groupId, urls, eclIncludes, protocolVersion); |
| | | (byte)assuredSdLevel, groupId, urls, eclIncludes, eclIncludes, protocolVersion); |
| | | } |
| | | |
| | | /** |
| | |
| | | byte safeDataLevel = rd.getAssuredSdLevel(); |
| | | byte groupId = rd.getGroupId(); |
| | | List<String> refUrls = rd.getRefUrls(); |
| | | Set<String> eclInclude = rd.getEclInclude(); |
| | | Set<String> eclInclude = rd.getEclIncludes(); |
| | | Set<String> eclIncludeForDeletes = rd.getEclIncludesForDeletes(); |
| | | short protocolVersion = 4; |
| | | DSInfo dsInfo = new DSInfo(dsId, rsId, TEST_DN_WITH_ROOT_ENTRY_GENID, status, assuredFlag, assuredMode, |
| | | safeDataLevel, groupId, refUrls, eclInclude, protocolVersion); |
| | | safeDataLevel, groupId, refUrls, eclInclude, eclIncludeForDeletes, protocolVersion); |
| | | dsList.add(dsInfo); |
| | | |
| | | TopoView dsTopoView = new TopoView(dsList, rd.getRsList()); |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | |
| | | package org.opends.server.replication.protocol; |
| | |
| | | urls4.add("ldaps://host:port/dc=foobar2??sub?(sn=Another Entry 2)"); |
| | | |
| | | DSInfo dsInfo1 = new DSInfo(13, 26, (long)154631, ServerStatus.FULL_UPDATE_STATUS, |
| | | false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, new HashSet<String>(), (short)-1); |
| | | false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, new HashSet<String>(), new HashSet<String>(), (short)-1); |
| | | |
| | | DSInfo dsInfo2 = new DSInfo(-436, 493, (long)-227896, ServerStatus.DEGRADED_STATUS, |
| | | true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, new HashSet<String>(), (short)-1); |
| | | true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, new HashSet<String>(), new HashSet<String>(), (short)-1); |
| | | |
| | | DSInfo dsInfo3 = new DSInfo(2436, 591, (long)0, ServerStatus.NORMAL_STATUS, |
| | | false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, new HashSet<String>(), (short)-1); |
| | | false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, new HashSet<String>(), new HashSet<String>(), (short)-1); |
| | | |
| | | DSInfo dsInfo4 = new DSInfo(415, 146, (long)0, ServerStatus.BAD_GEN_ID_STATUS, |
| | | true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, new HashSet<String>(), (short)-1); |
| | | true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, new HashSet<String>(), new HashSet<String>(), (short)-1); |
| | | |
| | | List<DSInfo> dsList1 = new ArrayList<DSInfo>(); |
| | | dsList1.add(dsInfo1); |
| | |
| | | * using protocol VLAST and V3 are working. |
| | | */ |
| | | @Test(enabled=true, dataProvider="createInitializationRequestMsgData") |
| | | public void initializationRequestMsgTestVLASTV3(int sender, int dest, |
| | | public void initializationRequestMsgTestVLASTV3(int sender, int dest, |
| | | String baseDn, int initWindow) |
| | | throws Exception |
| | | { |
| | |
| | | String baseDn = "dc=whatever"; |
| | | int entryCount = 56; |
| | | int initWindow = 22; |
| | | Object[] set1 = new Object[] {sender, dest, initiator, baseDn, |
| | | Object[] set1 = new Object[] {sender, dest, initiator, baseDn, |
| | | entryCount, initWindow }; |
| | | return new Object [][] { set1}; |
| | | } |
| | |
| | | * using protocol VLAST and V3 are working. |
| | | */ |
| | | @Test(enabled=true, dataProvider="createInitializeTargetMsgData") |
| | | public void initializeTargetMsgTestVLASTV3(int sender, int dest, |
| | | public void initializeTargetMsgTestVLASTV3(int sender, int dest, |
| | | int initiator, String baseDn, int entryCount, int initWindow) |
| | | throws Exception |
| | | { |
| | |
| | | assertEquals(msg.getInitiatorID(), vlastMsg.getInitiatorID()); |
| | | assertEquals(msg.getInitWindow(), vlastMsg.getInitWindow()); |
| | | } |
| | | |
| | | |
| | | @DataProvider(name = "createEntryMsgV3") |
| | | public Object[][] createEntryMsgV3() |
| | | { |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011 ForgeRock AS |
| | | */ |
| | | package org.opends.server.replication.protocol; |
| | | |
| | |
| | | i++; |
| | | } |
| | | } |
| | | |
| | | |
| | | Operation generatedOperation = generatedMsg.createOperation(connection); |
| | | |
| | | assertEquals(generatedOperation.getClass(), DeleteOperationBasis.class); |
| | |
| | | Set<String> a4 = new HashSet<String>(); |
| | | |
| | | DSInfo dsInfo1 = new DSInfo(13, 26, (long)154631, ServerStatus.FULL_UPDATE_STATUS, |
| | | false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, a1, (short)1); |
| | | false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, a1, a1, (short)1); |
| | | |
| | | DSInfo dsInfo2 = new DSInfo(-436, 493, (long)-227896, ServerStatus.DEGRADED_STATUS, |
| | | true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, a2, (short)2); |
| | | true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, a2, a2, (short)2); |
| | | |
| | | DSInfo dsInfo3 = new DSInfo(2436, 591, (long)0, ServerStatus.NORMAL_STATUS, |
| | | false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a3, (short)3); |
| | | false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a3, a3, (short)3); |
| | | |
| | | DSInfo dsInfo4 = new DSInfo(415, 146, (long)0, ServerStatus.BAD_GEN_ID_STATUS, |
| | | true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, a4, (short)4); |
| | | true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, a4, a4, (short)4); |
| | | |
| | | DSInfo dsInfo5 = new DSInfo(452436, 45591, (long)0, ServerStatus.NORMAL_STATUS, |
| | | false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a1, (short)5); |
| | | false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a1, a1, (short)5); |
| | | |
| | | List<DSInfo> dsList1 = new ArrayList<DSInfo>(); |
| | | dsList1.add(dsInfo1); |
| | |
| | | { |
| | | StartSessionMsg msg = new StartSessionMsg(status, refUrls, assuredFlag, |
| | | assuredMode, safedataLevel); |
| | | msg.setEclIncludes(attrs); |
| | | msg.setEclIncludes(attrs, attrs); |
| | | StartSessionMsg newMsg = |
| | | new StartSessionMsg(msg.getBytes(),ProtocolVersion.getCurrentVersion()); |
| | | assertEquals(msg.getStatus(), newMsg.getStatus()); |
| | |
| | | assertEquals(msg.getAssuredMode(), newMsg.getAssuredMode()); |
| | | assertTrue(msg.getSafeDataLevel() == newMsg.getSafeDataLevel()); |
| | | assertEquals(msg.getReferralsURLs(), newMsg.getReferralsURLs()); |
| | | Set<String> newAttrs = newMsg.getEclIncludes(); |
| | | assertTrue(attrs.size() == newAttrs.size()); |
| | | assertTrue(attrs.equals(newMsg.getEclIncludes())); |
| | | assertTrue(attrs.equals(newMsg.getEclIncludesForDeletes())); |
| | | } |
| | | |
| | | /** |