Skip to content

Instantly share code, notes, and snippets.

@aldaris
Created September 29, 2016 14:24
Show Gist options
  • Save aldaris/ae5c323cdfb501768701bfd84ccff30d to your computer and use it in GitHub Desktop.
Save aldaris/ae5c323cdfb501768701bfd84ccff30d to your computer and use it in GitHub Desktop.
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2016 ForgeRock AS.
*/
package org.forgerock.opendj.plugins;
import static org.forgerock.opendj.plugins.ExamplePluginMessages.*;
import static org.opends.server.util.StaticUtils.getExceptionMessage;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.io.ASN1;
import org.forgerock.opendj.io.ASN1Reader;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.server.config.server.SearchAndDeleteExtendedOperationHandlerCfg;
import org.opends.server.api.ExtendedOperationHandler;
import org.opends.server.controls.PagedResultsControl;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchListener;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.Requests;
import org.opends.server.protocols.internal.SearchRequest;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
public class SearchAndDeleteExtendedOperation
extends ExtendedOperationHandler<SearchAndDeleteExtendedOperationHandlerCfg> {
public static final byte TYPE_SEARCH_BASE_ELEMENT = (byte) 0x80;
public static final byte TYPE_SEARCH_FILTER_ELEMENT = (byte) 0x81;
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
@Override
public void initializeExtendedOperationHandler(SearchAndDeleteExtendedOperationHandlerCfg config)
throws ConfigException, InitializationException {
super.initializeExtendedOperationHandler(config);
}
@Override
public void processExtendedOperation(ExtendedOperation operation) {
// Parse the encoded request, if there is one.
ByteString requestValue = operation.getRequestValue();
if (requestValue == null) {
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
operation.appendErrorMessage(ExamplePluginMessages.ERR_MISSING_REQUEST_VALUE.get());
return;
}
ByteString searchBase = null;
ByteString searchFilter = null;
try {
ASN1Reader reader = ASN1.getReader(requestValue);
reader.readStartSequence();
if (reader.hasNextElement() && reader.peekType() == TYPE_SEARCH_BASE_ELEMENT) {
searchBase = reader.readOctetString();
}
if (reader.hasNextElement() && reader.peekType() == TYPE_SEARCH_FILTER_ELEMENT) {
searchFilter = reader.readOctetString();
}
reader.readEndSequence();
} catch (Exception ae) {
logger.traceException(ae);
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
operation.appendErrorMessage(ERR_PARSING_ERROR.get(getExceptionMessage(ae)));
return;
}
if (searchBase.isEmpty()) {
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
operation.appendErrorMessage(ERR_MISSING_SEARCH_BASE.get());
return;
} else if (searchFilter.isEmpty()) {
operation.setResultCode(ResultCode.PROTOCOL_ERROR);
operation.appendErrorMessage(ERR_MISSING_SEARCH_FILTER.get());
return;
}
final AuthenticationInfo authenticationInfo = operation.getClientConnection().getAuthenticationInfo();
if (!authenticationInfo.isAuthenticated()) {
operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
operation.appendErrorMessage(ERR_UNAUTHENTICATED_REQUEST.get());
}
final InternalClientConnection icc = new InternalClientConnection(authenticationInfo);
try {
final SearchRequest searchRequest = Requests.newSearchRequest(searchBase.toString(),
SearchScope.WHOLE_SUBTREE, searchFilter.toString());
searchRequest.addAttribute("1.1");
searchRequest.addControl(new PagedResultsControl(true, 500, null));
final LinkedBlockingQueue<InternalClientConnection> queue = new LinkedBlockingQueue<>(10);
for (int i = 0; i < 10; i++) {
queue.offer(new InternalClientConnection(authenticationInfo));
}
final InternalSearchOperation searchOperation = icc.processSearch(searchRequest, new InternalSearchListener() {
@Override
public void handleInternalSearchEntry(InternalSearchOperation searchOperation, SearchResultEntry searchEntry) throws DirectoryException {
final InternalClientConnection conn = queue.poll();
try {
conn.processDelete(searchEntry.getName());
} finally {
queue.offer(conn);
}
}
@Override
public void handleInternalSearchReference(InternalSearchOperation searchOperation, SearchResultReference searchReference) throws DirectoryException {
}
});
} catch (DirectoryException de) {
logger.traceException(de);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment