From 4fe72a4bef946169b0f50bc05bd9dc3b4b1131d3 Mon Sep 17 00:00:00 2001
From: pgamba <pgamba@localhost>
Date: Fri, 14 Aug 2009 12:37:19 +0000
Subject: [PATCH] Support for External change log compatible with draft-good-ldap-changelog-04.txt , March 2003
---
opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java | 551 +++++++++++++++++++++++++++++++-----------------------
1 files changed, 312 insertions(+), 239 deletions(-)
diff --git a/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java b/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
index 64be4c0..95bb790 100644
--- a/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -37,12 +37,12 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
@@ -81,7 +81,6 @@
import org.opends.server.replication.protocol.StartECLSessionMsg;
import org.opends.server.replication.protocol.UpdateMsg;
import org.opends.server.replication.server.ReplicationServer;
-import org.opends.server.replication.service.ReplicationDomain;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
@@ -94,6 +93,7 @@
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
+import org.opends.server.types.FilterType;
import org.opends.server.types.Modification;
import org.opends.server.types.ObjectClass;
import org.opends.server.types.Privilege;
@@ -107,7 +107,6 @@
import org.opends.server.types.operation.SearchReferenceSearchOperation;
import org.opends.server.util.Base64;
import org.opends.server.util.ServerConstants;
-import org.opends.server.util.TimeThread;
@@ -136,22 +135,12 @@
// The associated DN.
private DN rootBaseDN;
- // The cookie received in the ECL request control coming along
- // with the request.
- MultiDomainServerState requestCookie = null;
-
/**
* The replication server in which the search on ECL is to be performed.
*/
protected ReplicationServer replicationServer;
/**
- * Indicates whether we should actually process the search. This should
- * only be false if it's a persistent search with changesOnly=true.
- */
- protected boolean changesOnly;
-
- /**
* The client connection for the search operation.
*/
protected ClientConnection clientConnection;
@@ -177,6 +166,7 @@
private HashSet<String> supportedControls;
// The set of supported features for this WE
+ // TODO: any special feature to be implemented for an ECL search operation ?
private HashSet<String> supportedFeatures;
String privateDomainsBaseDN;
@@ -202,11 +192,12 @@
ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
eclObjectClasses.put(topOC, OC_TOP);
ObjectClass eclEntryOC = DirectoryServer.getObjectClass(OC_CHANGELOG_ENTRY,
- true);
+ true);
eclObjectClasses.put(eclEntryOC, OC_CHANGELOG_ENTRY);
// Define an empty sets for the supported controls and features.
+ // FIXME:ECL Decide if ServerSideControl and VLV are supported
supportedControls = new HashSet<String>(0);
supportedControls.add(ServerConstants.OID_SERVER_SIDE_SORT_REQUEST_CONTROL);
supportedControls.add(ServerConstants.OID_VLV_REQUEST_CONTROL);
@@ -226,57 +217,79 @@
* if this operation should be cancelled
*/
public void processECLSearch(ECLWorkflowElement wfe)
- throws CanceledOperationException
+ throws CanceledOperationException
{
boolean executePostOpPlugins = false;
- this.replicationServer = wfe.getReplicationServer();
-
- clientConnection = getClientConnection();
// Get the plugin config manager that will be used for invoking plugins.
PluginConfigManager pluginConfigManager =
DirectoryServer.getPluginConfigManager();
- changesOnly = false;
// Check for a request to cancel this operation.
checkIfCanceled(false);
- // Create a labeled block of code that we can break out of if a problem is
- // detected.
-searchProcessing:
+ searchProcessing:
{
+ replicationServer = wfe.getReplicationServer();
+ clientConnection = getClientConnection();
+ startECLSessionMsg = new StartECLSessionMsg();
+
+ // Set default behavior as "from draft change number".
+ // "from cookie" is set only when cookie is provided.
+ startECLSessionMsg.setECLRequestType(
+ StartECLSessionMsg.REQUEST_TYPE_FROM_DRAFT_CHANGE_NUMBER);
+
+ // Set a string operationid that will help correlate any error message
+ // logged for this operation with the 'real' client operation.
+ startECLSessionMsg.setOperationId(this.toString());
+
+ // Set a list of excluded domains (also exclude 'cn=changelog' itself)
+ ArrayList<String> excludedDomains =
+ MultimasterReplication.getPrivateDomains();
+ if (!excludedDomains.contains(ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT))
+ excludedDomains.add(ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT);
+ startECLSessionMsg.setExcludedDNs(excludedDomains);
+
+ // Test existence of the RS - normally should always be here
+ if (replicationServer == null)
+ {
+ setResultCode(ResultCode.OPERATIONS_ERROR);
+ appendErrorMessage(ERR_SEARCH_BASE_DOESNT_EXIST.get(
+ String.valueOf(baseDN)));
+ break searchProcessing;
+ }
+
// Process the search base and filter to convert them from their raw forms
// as provided by the client to the forms required for the rest of the
// search processing.
baseDN = getBaseDN();
filter = getFilter();
-
if ((baseDN == null) || (filter == null)){
break searchProcessing;
}
- // Check to see if there are any controls in the request. If so, then
- // see if there is any special processing required.
+ // Analyse controls - including the cookie control
try
{
- this.requestCookie = null;
handleRequestControls();
- if (this.requestCookie == null)
- {
- setResponseData(new DirectoryException(
- ResultCode.OPERATIONS_ERROR,
- Message.raw(Category.SYNC, Severity.FATAL_ERROR,
- "Cookie control expected")));
- break searchProcessing;
- }
}
catch (DirectoryException de)
{
if (debugEnabled())
- {
TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
+ setResponseData(de);
+ break searchProcessing;
+ }
+ // Process filter - extract draft change number (seqnum) conditions
+ try
+ {
+ evaluateFilter(startECLSessionMsg, this.getFilter());
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
setResponseData(de);
break searchProcessing;
}
@@ -287,7 +300,7 @@
// Invoke the pre-operation search plugins.
executePostOpPlugins = true;
PluginResult.PreOperation preOpResult =
- pluginConfigManager.invokePreOperationSearchPlugins(this);
+ pluginConfigManager.invokePreOperationSearchPlugins(this);
if (!preOpResult.continueProcessing())
{
setResultCode(preOpResult.getResultCode());
@@ -297,26 +310,12 @@
break searchProcessing;
}
-
// Check for a request to cancel this operation.
checkIfCanceled(false);
-
- // Test existence of the RS
- if (replicationServer == null)
- {
- setResultCode(ResultCode.OPERATIONS_ERROR);
- appendErrorMessage(ERR_SEARCH_BASE_DOESNT_EXIST.get(
- String.valueOf(baseDN)));
- break searchProcessing;
- }
-
-
- // We'll set the result code to "success". If a problem occurs, then it
- // will be overwritten.
+ // Be optimistic by default.
setResultCode(ResultCode.SUCCESS);
-
// If there's a persistent search, then register it with the server.
if (persistentSearch != null)
{
@@ -332,9 +331,7 @@
catch (DirectoryException de)
{
if (debugEnabled())
- {
TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
setResponseData(de);
@@ -343,7 +340,6 @@
persistentSearch.cancel();
setSendResponse(true);
}
-
break searchProcessing;
}
catch (CanceledOperationException coe)
@@ -353,31 +349,25 @@
persistentSearch.cancel();
setSendResponse(true);
}
-
throw coe;
}
catch (Exception e)
{
if (debugEnabled())
- {
TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
setResultCode(DirectoryServer.getServerErrorResultCode());
appendErrorMessage(ERR_SEARCH_BACKEND_EXCEPTION.get(
- getExceptionMessage(e)));
-
+ getExceptionMessage(e)));
if (persistentSearch != null)
{
persistentSearch.cancel();
setSendResponse(true);
}
-
break searchProcessing;
}
}
-
// Check for a request to cancel this operation.
checkIfCanceled(false);
@@ -385,7 +375,7 @@
if (executePostOpPlugins)
{
PluginResult.PostOperation postOpResult =
- pluginConfigManager.invokePostOperationSearchPlugins(this);
+ pluginConfigManager.invokePostOperationSearchPlugins(this);
if (!postOpResult.continueProcessing())
{
setResultCode(postOpResult.getResultCode());
@@ -398,13 +388,13 @@
/**
- * Handles any controls contained in the request.
+ * Handles any controls contained in the request - including the cookie ctrl.
*
* @throws DirectoryException If there is a problem with any of the request
* controls.
*/
protected void handleRequestControls()
- throws DirectoryException
+ throws DirectoryException
{
List<Control> requestControls = getRequestControls();
if ((requestControls != null) && (! requestControls.isEmpty()))
@@ -414,22 +404,28 @@
Control c = requestControls.get(i);
String oid = c.getOID();
if (! AccessControlConfigManager.getInstance().
- getAccessControlHandler().isAllowed(baseDN, this, c))
+ getAccessControlHandler().isAllowed(baseDN, this, c))
{
throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
- ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(oid));
+ ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(oid));
}
if (oid.equals(OID_ECL_COOKIE_EXCHANGE_CONTROL))
{
ExternalChangelogRequestControl eclControl =
getRequestControl(ExternalChangelogRequestControl.DECODER);
- this.requestCookie = eclControl.getCookie();
+ MultiDomainServerState cookie = eclControl.getCookie();
+ if (cookie!=null)
+ {
+ startECLSessionMsg.setECLRequestType(
+ StartECLSessionMsg.REQUEST_TYPE_FROM_COOKIE);
+ startECLSessionMsg.setCrossDomainServerState(cookie.toString());
+ }
}
else if (oid.equals(OID_LDAP_ASSERTION))
{
LDAPAssertionRequestControl assertControl =
- getRequestControl(LDAPAssertionRequestControl.DECODER);
+ getRequestControl(LDAPAssertionRequestControl.DECODER);
try
{
@@ -449,20 +445,20 @@
}
throw new DirectoryException(de.getResultCode(),
- ERR_SEARCH_CANNOT_GET_ENTRY_FOR_ASSERTION.get(
- de.getMessageObject()));
+ ERR_SEARCH_CANNOT_GET_ENTRY_FOR_ASSERTION.get(
+ de.getMessageObject()));
}
if (entry == null)
{
throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
- ERR_SEARCH_NO_SUCH_ENTRY_FOR_ASSERTION.get());
+ ERR_SEARCH_NO_SUCH_ENTRY_FOR_ASSERTION.get());
}
if (! assertionFilter.matchesEntry(entry))
{
throw new DirectoryException(ResultCode.ASSERTION_FAILED,
- ERR_SEARCH_ASSERTION_FAILED.get());
+ ERR_SEARCH_ASSERTION_FAILED.get());
}
}
catch (DirectoryException de)
@@ -478,8 +474,8 @@
}
throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
- ERR_SEARCH_CANNOT_PROCESS_ASSERTION_FILTER.get(
- de.getMessageObject()), de);
+ ERR_SEARCH_CANNOT_PROCESS_ASSERTION_FILTER.get(
+ de.getMessageObject()), de);
}
}
else if (oid.equals(OID_PROXIED_AUTH_V1))
@@ -489,11 +485,11 @@
if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
{
throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED,
- ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
+ ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
}
ProxiedAuthV1Control proxyControl =
- getRequestControl(ProxiedAuthV1Control.DECODER);
+ getRequestControl(ProxiedAuthV1Control.DECODER);
Entry authorizationEntry = proxyControl.getAuthorizationEntry();
setAuthorizationEntry(authorizationEntry);
@@ -513,11 +509,11 @@
if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
{
throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED,
- ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
+ ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
}
ProxiedAuthV2Control proxyControl =
- getRequestControl(ProxiedAuthV2Control.DECODER);
+ getRequestControl(ProxiedAuthV2Control.DECODER);
Entry authorizationEntry = proxyControl.getAuthorizationEntry();
setAuthorizationEntry(authorizationEntry);
@@ -536,15 +532,17 @@
getRequestControl(PersistentSearchControl.DECODER);
persistentSearch = new PersistentSearch(this,
- psearchControl.getChangeTypes(),
- psearchControl.getReturnECs());
+ psearchControl.getChangeTypes(),
+ psearchControl.getReturnECs());
// If we're only interested in changes, then we don't actually want
// to process the search now.
- if (psearchControl.getChangesOnly())
- {
- changesOnly = true;
- }
+ if (!psearchControl.getChangesOnly())
+ startECLSessionMsg.setPersistent(
+ StartECLSessionMsg.PERSISTENT);
+ else
+ startECLSessionMsg.setPersistent(
+ StartECLSessionMsg.PERSISTENT_CHANGES_ONLY);
}
else if (oid.equals(OID_LDAP_SUBENTRIES))
{
@@ -553,7 +551,7 @@
else if (oid.equals(OID_MATCHED_VALUES))
{
MatchedValuesControl matchedValuesControl =
- getRequestControl(MatchedValuesControl.DECODER);
+ getRequestControl(MatchedValuesControl.DECODER);
setMatchedValuesControl(matchedValuesControl);
}
else if (oid.equals(OID_ACCOUNT_USABLE_CONTROL))
@@ -569,20 +567,19 @@
setVirtualAttributesOnly(true);
}
else if (oid.equals(OID_GET_EFFECTIVE_RIGHTS) &&
- DirectoryServer.isSupportedControl(OID_GET_EFFECTIVE_RIGHTS))
+ DirectoryServer.isSupportedControl(OID_GET_EFFECTIVE_RIGHTS))
{
// Do nothing here and let AciHandler deal with it.
}
- // NYI -- Add support for additional controls.
-
+ // TODO: Add support for additional controls, including VLV
else if (c.isCritical())
{
if ((replicationServer == null) || (! supportsControl(oid)))
{
throw new DirectoryException(
- ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
- ERR_SEARCH_UNSUPPORTED_CRITICAL_CONTROL.get(oid));
+ ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
+ ERR_SEARCH_UNSUPPORTED_CRITICAL_CONTROL.get(oid));
}
}
}
@@ -592,35 +589,12 @@
private void processSearch()
throws DirectoryException, CanceledOperationException
{
- startECLSessionMsg = new StartECLSessionMsg();
- startECLSessionMsg.setECLRequestType(
- StartECLSessionMsg.REQUEST_TYPE_FROM_COOKIE);
- startECLSessionMsg.setChangeNumber(
- new ChangeNumber(TimeThread.getTime(),(short)0, (short)0));
- startECLSessionMsg.setCrossDomainServerState(requestCookie.toString());
+ if (debugEnabled())
+ TRACER.debugInfo(
+ " processSearch toString=[" + toString() + "] opid=["
+ + startECLSessionMsg.getOperationId() + "]");
- if (persistentSearch==null)
- startECLSessionMsg.setPersistent(StartECLSessionMsg.NON_PERSISTENT);
- else
- if (!changesOnly)
- startECLSessionMsg.setPersistent(StartECLSessionMsg.PERSISTENT);
- else
- startECLSessionMsg.setPersistent(
- StartECLSessionMsg.PERSISTENT_CHANGES_ONLY);
-
- startECLSessionMsg.setFirstDraftChangeNumber(0);
- startECLSessionMsg.setLastDraftChangeNumber(0);
-
- // Help correlate with access log with the format: "conn=x op=y msgID=z"
- startECLSessionMsg.setOperationId(
- "conn="+String.valueOf(this.getConnectionID())
- + " op="+String.valueOf(this.getOperationID())
- + " msgID="+String.valueOf(getOperationID()));
-
- startECLSessionMsg.setExcludedDNs(
- MultimasterReplication.getPrivateDomains());
-
- // Start session
+ // Start a specific ECL session
eclSession = replicationServer.createECLSession(startECLSessionMsg);
if (!getScope().equals(SearchScope.SINGLE_LEVEL))
@@ -718,9 +692,9 @@
private boolean matchFilter(Entry entry)
throws DirectoryException
{
- boolean ms = entry.matchesBaseAndScope(getBaseDN(), getScope());
- boolean mf = getFilter().matchesEntry(entry);
- return (ms && mf);
+ boolean baseScopeMatch = entry.matchesBaseAndScope(getBaseDN(), getScope());
+ boolean filterMatch = getFilter().matchesEntry(entry);
+ return (baseScopeMatch && filterMatch);
}
/**
@@ -755,95 +729,99 @@
null, // real time current entry
null, // real time attrs names
null, // hist entry attributes
- -1, // TODO:ECL G Good changelog draft compat. addMsg.getSeqnum()
+ eclmsg.getDraftChangeNumber(),
"add");
} else
- if (msg instanceof ModifyMsg)
- {
- ModifyMsg modMsg = (ModifyMsg)msg;
- InternalClientConnection conn =
- InternalClientConnection.getRootConnection();
- try
+ if (msg instanceof ModifyMsg)
{
- // Map the modMsg modifications to an LDIF string
- // for the 'changes' attribute of the CL entry
- ModifyOperation modifyOperation =
- (ModifyOperation)modMsg.createOperation(conn);
- String LDIFchanges = modToLDIF(modifyOperation.getModifications());
+ ModifyMsg modMsg = (ModifyMsg)msg;
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+ try
+ {
+ // Map the modMsg modifications to an LDIF string
+ // for the 'changes' attribute of the CL entry
+ ModifyOperation modifyOperation =
+ (ModifyOperation)modMsg.createOperation(conn);
+ String LDIFchanges = modToLDIF(modifyOperation.getModifications());
- // TODO:ECL G Good changelog draft compat. Hist entry attributes
- // ArrayList<RawAttribute> attributes = modMsg.getEntryAttributes();
+ // TODO:ECL Hist entry attributes
+ // ArrayList<RawAttribute> attributes = modMsg.getEntryAttributes();
+ clEntry = createChangelogEntry(
+ eclmsg.getServiceId(),
+ eclmsg.getCookie().toString(),
+ DN.decode(modMsg.getDn()),
+ modMsg.getChangeNumber(),
+ LDIFchanges,
+ modMsg.getUniqueId(),
+ null, // real time current entry
+ null, // real time attrs names
+ null, // hist entry attributes
+ eclmsg.getDraftChangeNumber(),
+ "modify");
+
+ }
+ catch(Exception e)
+ {
+ // Exceptions raised by createOperation for example
+ throw new DirectoryException(ResultCode.OTHER,
+ Message.raw(Category.SYNC, Severity.NOTICE,
+ " Server fails to create entry: "),e);
+ }
+ }
+ else if (msg instanceof ModifyDNMsg)
+ {
+ ModifyDNMsg modDNMsg = (ModifyDNMsg)msg;
+
clEntry = createChangelogEntry(
eclmsg.getServiceId(),
eclmsg.getCookie().toString(),
- DN.decode(modMsg.getDn()),
- modMsg.getChangeNumber(),
- LDIFchanges,
- modMsg.getUniqueId(),
+ DN.decode(modDNMsg.getDn()),
+ modDNMsg.getChangeNumber(),
+ null,
+ modDNMsg.getUniqueId(),
null, // real time current entry
null, // real time attrs names
null, // hist entry attributes
- -1, // TODO:ECL G Good changelog draft compat. modMsg.getSeqnum()
- "modify");
+ eclmsg.getDraftChangeNumber(),
+ "modrdn");
+
+ Attribute a = Attributes.create("newrdn", modDNMsg.getNewRDN());
+ clEntry.addAttribute(a, null);
+
+ Attribute b = Attributes.create("newsuperior",
+ modDNMsg.getNewSuperior());
+ clEntry.addAttribute(b, null);
+
+ Attribute c = Attributes.create("deleteoldrdn",
+ String.valueOf(modDNMsg.deleteOldRdn()));
+ clEntry.addAttribute(c, null);
}
- catch(Exception e)
+ else if (msg instanceof DeleteMsg)
{
- // FIXME:ECL Handle error when createOperation raise DataFormatExceptin
+ DeleteMsg delMsg = (DeleteMsg)msg;
+ /* TODO:ECL Entry attributes for DEL op
+ ArrayList<RawAttribute> rattributes = new ArrayList<RawAttribute>();
+ ArrayList<RawAttribute> rattributes = delMsg.getEntryAttributes();
+ // Map the entry attributes of the DelMsg to an LDIF string
+ // for the 'deletedentryattributes' attribute of the CL entry
+ String delAttrs = delMsgToLDIFString(rattributes);
+ */
+ clEntry = createChangelogEntry(
+ eclmsg.getServiceId(),
+ eclmsg.getCookie().toString(),
+ DN.decode(delMsg.getDn()),
+ delMsg.getChangeNumber(),
+ null,
+ delMsg.getUniqueId(),
+ null,
+ null,
+ null, //rattributes,
+ eclmsg.getDraftChangeNumber(),
+ "delete");
}
- }
- else if (msg instanceof ModifyDNMsg)
- {
- ModifyDNMsg modDNMsg = (ModifyDNMsg)msg;
-
- clEntry = createChangelogEntry(
- eclmsg.getServiceId(),
- eclmsg.getCookie().toString(),
- DN.decode(modDNMsg.getDn()),
- modDNMsg.getChangeNumber(),
- null,
- modDNMsg.getUniqueId(),
- null, // real time current entry
- null, // real time attrs names
- null, // hist entry attributes
- -1, // TODO:ECL G Good changelog draft compat. modDNMsg.getSeqnum()
- "modrdn");
-
- Attribute a = Attributes.create("newrdn", modDNMsg.getNewRDN());
- clEntry.addAttribute(a, null);
-
- Attribute b = Attributes.create("newsuperior", modDNMsg.getNewSuperior());
- clEntry.addAttribute(b, null);
-
- Attribute c = Attributes.create("deleteoldrdn",
- String.valueOf(modDNMsg.deleteOldRdn()));
- clEntry.addAttribute(c, null);
-
- }
- else if (msg instanceof DeleteMsg)
- {
- DeleteMsg delMsg = (DeleteMsg)msg;
- ArrayList<RawAttribute> rattributes = new ArrayList<RawAttribute>();
- /* TODO:ECL Entry attributes for DEL op
- ArrayList<RawAttribute> rattributes = delMsg.getEntryAttributes();
- // Map the entry attributes of the DelMsg to an LDIF string
- // for the 'deletedentryattributes' attribute of the CL entry
- String delAttrs = delMsgToLDIFString(rattributes);
- */
- clEntry = createChangelogEntry(
- eclmsg.getServiceId(),
- eclmsg.getCookie().toString(),
- DN.decode(delMsg.getDn()),
- delMsg.getChangeNumber(),
- null,
- delMsg.getUniqueId(),
- null,
- null,
- null, //rattributes,
- -1, // TODO:ECL G Good changelog draft compat. delMsg.getSeqnum()
- "delete");
- }
return clEntry;
}
@@ -863,20 +841,6 @@
HashMap<AttributeType,List<Attribute>> operationalAttrs =
new LinkedHashMap<AttributeType,List<Attribute>>();
- // Add to the root entry the replication state of each domain
- // TODO:ECL Put in ECL root entry, the ServerState for each domain
- AttributeType descType = DirectoryServer.getAttributeType("description");
- List<ReplicationDomain> supportedReplicationDomains
- = new ArrayList<ReplicationDomain>();
-
- for (ReplicationDomain domain : supportedReplicationDomains)
- {
- // Crappy stuff to return the server state to the client
- LinkedList<Attribute> attrList = new LinkedList<Attribute>();
- attrList.add(Attributes.create("description",
- domain.getServiceID() + "/" + domain.getServerState().toString()));
- userAttrs.put(descType, attrList);
- }
Entry e = new Entry(this.rootBaseDN, oclasses, userAttrs,
operationalAttrs);
return e;
@@ -916,10 +880,19 @@
String changetype)
throws DirectoryException
{
- String dnString = "cn="+ changeNumber +"," +
- serviceID + "," +
+ String dnString = "";
+ if (draftChangenumber == 0)
+ {
+ // Draft uncompat mode
+ dnString = "cn="+ changeNumber +"," + serviceID + "," +
+ ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
+ }
+ else
+ {
+ // Draft compat mode
+ dnString = "cn="+ draftChangenumber + "," +
ServerConstants.DN_EXTERNAL_CHANGELOG_ROOT;
-
+ }
HashMap<ObjectClass,String> oClasses =
new LinkedHashMap<ObjectClass,String>(3);
oClasses.putAll(eclObjectClasses);
@@ -962,7 +935,7 @@
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
uAttrs.put(a.getAttributeType(), attrList);
- */
+ */
//
a = Attributes.create("changetype", changetype);
@@ -1017,18 +990,21 @@
uAttrs.put(a.getAttributeType(), attrList);
}
- a = Attributes.create("targetentryuuid", targetUUID);
- attrList = new ArrayList<Attribute>(1);
- attrList.add(a);
- operationalAttrs.put(a.getAttributeType(), attrList);
- if (draftChangenumber>0)
+ if (targetUUID != null)
{
- // compat mode
- a = Attributes.create("targetuniqueid",
- ECLSearchOperation.openDsToSunDseeNsUniqueId(targetUUID));
+ a = Attributes.create("targetentryuuid", targetUUID);
attrList = new ArrayList<Attribute>(1);
attrList.add(a);
operationalAttrs.put(a.getAttributeType(), attrList);
+ if (draftChangenumber>0)
+ {
+ // compat mode
+ a = Attributes.create("targetuniqueid",
+ ECLSearchOperation.openDsToSunDseeNsUniqueId(targetUUID));
+ attrList = new ArrayList<Attribute>(1);
+ attrList.add(a);
+ operationalAttrs.put(a.getAttributeType(), attrList);
+ }
}
a = Attributes.create("changelogcookie", cookie);
@@ -1061,7 +1037,7 @@
uAttrs.put(a.getAttributeType(), attrList);
}
}
- */
+ */
/*
if (targetAttrNames != null)
@@ -1082,7 +1058,7 @@
}
}
}
- */
+ */
/* TODO: Implement entry attributes historical values
if (histEntryAttributes != null)
{
@@ -1105,7 +1081,7 @@
}
}
}
- */
+ */
// at the end build the CL entry to be returned
Entry cle = new Entry(
@@ -1315,7 +1291,7 @@
*/
public CancelResult cancel(CancelRequest cancelRequest)
{
- if (eclSession!=null)
+ if (eclSession != null)
{
try
{
@@ -1327,20 +1303,16 @@
}
/**
- * The unique identifier used in DSEE is named nsUniqueId and its format is
- * HHHHHHHH-HHHHHHHH-HHHHHHHH-HHHHHHHH where H is a hex digit.
- * An nsUniqueId value is for example 3970de28-08b311d9-8095b9bf-c4d9231c
- * The unique identifier used in OpenDS is named entryUUID.
- * Its value is for example entryUUID: 50dd9673-71e1-4478-b13c-dba387c4d7e1
- * @param entryUid the OpenDS entry UID
- * @return the Dsee format for the entry UID
- */
+ * The unique identifier used in DSEE is named nsUniqueId and its format is
+ * HHHHHHHH-HHHHHHHH-HHHHHHHH-HHHHHHHH where H is a hex digit.
+ * An nsUniqueId value is for example 3970de28-08b311d9-8095b9bf-c4d9231c
+ * The unique identifier used in OpenDS is named entryUUID.
+ * Its value is for example entryUUID: 50dd9673-71e1-4478-b13c-dba387c4d7e1
+ * @param entryUid the OpenDS entry UID
+ * @return the Dsee format for the entry UID
+ */
private static String openDsToSunDseeNsUniqueId(String entryUid)
{
-
- if (entryUid == null)
- return null;
-
// the conversion from one unique identifier to an other is
// a question of formating : the last "-" is placed
StringBuffer buffer = new StringBuffer(entryUid);
@@ -1355,5 +1327,106 @@
return buffer.toString();
}
-}
+ /**
+ * Traverse the provided search filter, looking for some conditions
+ * on attributes that can be optimized in the ECL.
+ * When found, populate the provided StartECLSessionMsg.
+ * @param startCLmsg the startCLMsg to be populated.
+ * @param sf the provided search filter.
+ * @throws DirectoryException when an exception occurs.
+ */
+ public static void evaluateFilter(StartECLSessionMsg startCLmsg,
+ SearchFilter sf)
+ throws DirectoryException
+ {
+ StartECLSessionMsg msg = evaluateFilter2(sf);
+ startCLmsg.setFirstDraftChangeNumber(msg.getFirstDraftChangeNumber());
+ startCLmsg.setLastDraftChangeNumber(msg.getLastDraftChangeNumber());
+ startCLmsg.setChangeNumber(msg.getChangeNumber());
+ }
+
+ private static StartECLSessionMsg evaluateFilter2(SearchFilter sf)
+ throws DirectoryException
+ {
+ StartECLSessionMsg startCLmsg = new StartECLSessionMsg();
+ startCLmsg.setFirstDraftChangeNumber(-1);
+ startCLmsg.setLastDraftChangeNumber(-1);
+ startCLmsg.setChangeNumber(new ChangeNumber(0,0,(short)0));
+
+ // Here are the 3 elementary cases we know how to optimize
+ if ((sf != null)
+ && (sf.getFilterType() == FilterType.GREATER_OR_EQUAL)
+ && (sf.getAttributeType() != null)
+ && (sf.getAttributeType().getPrimaryName().
+ equalsIgnoreCase("changeNumber")))
+ {
+ int sn = Integer.decode(
+ sf.getAssertionValue().getNormalizedValue().toString());
+ startCLmsg.setFirstDraftChangeNumber(sn);
+ return startCLmsg;
+ }
+ else if ((sf != null)
+ && (sf.getFilterType() == FilterType.LESS_OR_EQUAL)
+ && (sf.getAttributeType() != null)
+ && (sf.getAttributeType().getPrimaryName().
+ equalsIgnoreCase("changeNumber")))
+ {
+ int sn = Integer.decode(
+ sf.getAssertionValue().getNormalizedValue().toString());
+ startCLmsg.setLastDraftChangeNumber(sn);
+ return startCLmsg;
+ }
+ else if ((sf != null)
+ && (sf.getFilterType() == FilterType.EQUALITY)
+ && (sf.getAttributeType() != null)
+ && (sf.getAttributeType().getPrimaryName().
+ equalsIgnoreCase("replicationcsn")))
+ {
+ // == exact changenumber
+ ChangeNumber cn = new ChangeNumber(sf.getAssertionValue().toString());
+ startCLmsg.setChangeNumber(cn);
+ return startCLmsg;
+ }
+ else if ((sf != null)
+ && (sf.getFilterType() == FilterType.EQUALITY)
+ && (sf.getAttributeType() != null)
+ && (sf.getAttributeType().getPrimaryName().
+ equalsIgnoreCase("changenumber")))
+ {
+ int sn = Integer.decode(
+ sf.getAssertionValue().getNormalizedValue().toString());
+ startCLmsg.setFirstDraftChangeNumber(sn);
+ startCLmsg.setLastDraftChangeNumber(sn);
+ return startCLmsg;
+ }
+ else if ((sf != null)
+ && (sf.getFilterType() == FilterType.AND))
+ {
+ // Here is the only binary operation we know how to optimize
+ Collection<SearchFilter> comps = sf.getFilterComponents();
+ SearchFilter sfs[] = comps.toArray(new SearchFilter[0]);
+ StartECLSessionMsg m1 = evaluateFilter2(sfs[0]);
+ StartECLSessionMsg m2 = evaluateFilter2(sfs[1]);
+
+ int l1 = m1.getLastDraftChangeNumber();
+ int l2 = m2.getLastDraftChangeNumber();
+ if (l1 == -1)
+ startCLmsg.setLastDraftChangeNumber(l2);
+ else
+ if (l2 == -1)
+ startCLmsg.setLastDraftChangeNumber(l1);
+ else
+ startCLmsg.setLastDraftChangeNumber(Math.min(l1,l2));
+
+ int f1 = m1.getFirstDraftChangeNumber();
+ int f2 = m2.getFirstDraftChangeNumber();
+ startCLmsg.setFirstDraftChangeNumber(Math.max(f1,f2));
+ return startCLmsg;
+ }
+ else
+ {
+ return startCLmsg;
+ }
+ }
+}
--
Gitblit v1.10.0