| | |
| | | /** |
| | | * The replication server in which the search on ECL is to be performed. |
| | | */ |
| | | protected ReplicationServer replicationServer; |
| | | private ReplicationServer replicationServer; |
| | | |
| | | /** |
| | | * The client connection for the search operation. |
| | | */ |
| | | protected ClientConnection clientConnection; |
| | | private ClientConnection clientConnection; |
| | | |
| | | /** |
| | | * The base DN for the search. |
| | | */ |
| | | protected DN baseDN; |
| | | private DN baseDN; |
| | | |
| | | /** |
| | | * The persistent search request, if applicable. |
| | | */ |
| | | protected PersistentSearch persistentSearch; |
| | | private PersistentSearch persistentSearch; |
| | | |
| | | /** |
| | | * The filter for the search. |
| | | */ |
| | | protected SearchFilter filter; |
| | | private SearchFilter filter; |
| | | |
| | | private ExternalChangeLogSession eclSession; |
| | | |
| | | // The set of supported controls for this WE |
| | | 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; |
| | | |
| | | /** |
| | | * Creates a new operation that may be used to search for entries in a local |
| | | * backend of the Directory Server. |
| | | * |
| | | * @param search The operation to process. |
| | | */ |
| | | public ECLSearchOperation(SearchOperation search) |
| | | ECLSearchOperation(SearchOperation search) |
| | | { |
| | | super(search); |
| | | |
| | |
| | | supportedControls = new HashSet<String>(0); |
| | | supportedControls.add(ServerConstants.OID_SERVER_SIDE_SORT_REQUEST_CONTROL); |
| | | supportedControls.add(ServerConstants.OID_VLV_REQUEST_CONTROL); |
| | | supportedFeatures = new HashSet<String>(0); |
| | | |
| | | ECLWorkflowElement.attachLocalOperation(search, this); |
| | | } |
| | |
| | | * @throws CanceledOperationException |
| | | * if this operation should be cancelled |
| | | */ |
| | | public void processECLSearch(ECLWorkflowElement wfe) |
| | | void processECLSearch(ECLWorkflowElement wfe) |
| | | throws CanceledOperationException |
| | | { |
| | | boolean executePostOpPlugins = false; |
| | |
| | | * @throws DirectoryException If there is a problem with any of the request |
| | | * controls. |
| | | */ |
| | | protected void handleRequestControls() |
| | | private void handleRequestControls() |
| | | throws DirectoryException |
| | | { |
| | | List<Control> requestControls = getRequestControls(); |
| | |
| | | } |
| | | } |
| | | |
| | | private void processSearch() |
| | | throws DirectoryException, CanceledOperationException |
| | | private void processSearch() throws DirectoryException, |
| | | CanceledOperationException |
| | | { |
| | | if (debugEnabled()) |
| | | TRACER.debugInfo( |
| | | " processSearch toString=[" + toString() + "] opid=[" |
| | | { |
| | | TRACER.debugInfo(" processSearch toString=[" + toString() + "] opid=[" |
| | | + startECLSessionMsg.getOperationId() + "]"); |
| | | } |
| | | |
| | | // Start a specific ECL session |
| | | eclSession = replicationServer.createECLSession(startECLSessionMsg); |
| | | boolean abortECLSession = false; |
| | | try |
| | | { |
| | | // Get first update (this is needed to determine hasSubordinates. |
| | | ECLUpdateMsg update = eclSession.getNextUpdate(); |
| | | |
| | | // Loop on result entries |
| | | int phase = 0; // 0 is initial phase, 1 is psearch |
| | | boolean returnedRoot = false; |
| | | // Return root entry if requested. |
| | | if (!getScope().equals(SearchScope.SINGLE_LEVEL)) |
| | | { |
| | | Entry entry = createRootEntry(update != null); |
| | | if (matchFilter(entry)) |
| | | { |
| | | if (!returnEntry(entry, null)) |
| | | { |
| | | // Abandon, Size limit reached. |
| | | abortECLSession = true; |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | while (true) |
| | | if (!getScope().equals(SearchScope.BASE_OBJECT)) |
| | | { |
| | | while (update != null) |
| | | { |
| | | // Check for a request to cancel this operation. |
| | | checkIfCanceled(false); |
| | | |
| | | ECLUpdateMsg update = eclSession.getNextUpdate(); |
| | | if (update!=null) |
| | | { |
| | | if (!returnedRoot) |
| | | { |
| | | returnRootEntryIfRequired(true); |
| | | returnedRoot = true; |
| | | } |
| | | if (phase == 0) |
| | | { |
| | | if (!buildAndReturnEntry(update)) |
| | | { |
| | | // Abandon, Size limit reached |
| | | eclSession.close(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (!returnedRoot) |
| | | { |
| | | returnRootEntryIfRequired(false); |
| | | returnedRoot = true; |
| | | } |
| | | if (phase == 0) |
| | | { |
| | | if (this.persistentSearch == null) |
| | | { |
| | | eclSession.close(); |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | phase = 1; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // Abandon, Size limit reached. |
| | | abortECLSession = true; |
| | | return; |
| | | } |
| | | |
| | | private void returnRootEntryIfRequired(boolean hasSubordinates) |
| | | throws DirectoryException |
| | | update = eclSession.getNextUpdate(); |
| | | } |
| | | } |
| | | } |
| | | catch (CanceledOperationException e) |
| | | { |
| | | if (!getScope().equals(SearchScope.SINGLE_LEVEL)) |
| | | abortECLSession = true; |
| | | throw e; |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | // Root entry |
| | | Entry entry = createRootEntry(hasSubordinates); |
| | | if (matchFilter(entry)) |
| | | returnEntry(entry, null); |
| | | abortECLSession = true; |
| | | throw e; |
| | | } |
| | | finally |
| | | { |
| | | if (persistentSearch == null || abortECLSession) |
| | | { |
| | | eclSession.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | ObjectClass containerOC = DirectoryServer.getObjectClass("container", true); |
| | | rootObjectClasses.put(containerOC, "container"); |
| | | oclasses.putAll(rootObjectClasses); |
| | | |
| | | // Attributes. |
| | | HashMap<AttributeType,List<Attribute>> userAttrs = |
| | | new LinkedHashMap<AttributeType,List<Attribute>>(); |
| | | HashMap<AttributeType,List<Attribute>> operationalAttrs = |
| | | new LinkedHashMap<AttributeType,List<Attribute>>(); |
| | | |
| | | // CN. |
| | | AttributeType aType = DirectoryServer.getAttributeType(ATTR_COMMON_NAME); |
| | | if (aType == null) |
| | | aType = DirectoryServer.getDefaultAttributeType(ATTR_COMMON_NAME); |
| | | Attribute a = Attributes.create(ATTR_COMMON_NAME, "changelog"); |
| | | List<Attribute> attrList = Collections.singletonList(a); |
| | | userAttrs.put(aType, attrList); |
| | | |
| | | // subSchemaSubentry |
| | | AttributeType aType = |
| | | DirectoryServer.getAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC); |
| | | aType = DirectoryServer.getAttributeType(ATTR_SUBSCHEMA_SUBENTRY_LC); |
| | | if (aType == null) |
| | | aType = DirectoryServer.getDefaultAttributeType(ATTR_SUBSCHEMA_SUBENTRY); |
| | | Attribute a = Attributes.create(ATTR_SUBSCHEMA_SUBENTRY, |
| | | a = Attributes.create(ATTR_SUBSCHEMA_SUBENTRY, |
| | | ConfigConstants.DN_DEFAULT_SCHEMA_ROOT); |
| | | List<Attribute> attrList = Collections.singletonList(a); |
| | | attrList = Collections.singletonList(a); |
| | | if (aType.isOperational()) |
| | | operationalAttrs.put(aType, attrList); |
| | | else |
| | | userAttrs.put(aType, attrList); |
| | | else userAttrs.put(aType, attrList); |
| | | |
| | | // TODO:numSubordinates |
| | | |
| | |
| | | * @throws DirectoryException |
| | | * When any error occurs. |
| | | */ |
| | | public static Entry createChangelogEntry( |
| | | private static Entry createChangelogEntry( |
| | | String serviceID, |
| | | String cookie, |
| | | DN targetDN, |
| | |
| | | * @param mods The provided list of modifications. |
| | | * @return The LDIF string. |
| | | */ |
| | | public static String modToLDIF(List<Modification> mods) |
| | | private static String modToLDIF(List<Modification> mods) |
| | | { |
| | | if (mods==null) |
| | | { |
| | |
| | | { |
| | | Modification m = iterator.next(); |
| | | Attribute a = m.getAttribute(); |
| | | String attrName = a.getName(); |
| | | String attrName = a.getNameWithOptions(); |
| | | modTypeLine.append(m.getModificationType().getLDIFName()); |
| | | modTypeLine.append(": "); |
| | | modTypeLine.append(attrName); |