Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2007-2019 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright (C) 2008-2019 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import com.unboundid.asn1.ASN1Buffer;
import com.unboundid.asn1.ASN1BufferSequence;
import com.unboundid.asn1.ASN1Element;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.asn1.ASN1Sequence;
import com.unboundid.ldap.protocol.LDAPMessage;
import com.unboundid.ldap.protocol.LDAPResponse;
import com.unboundid.ldap.protocol.ProtocolOp;
import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
import com.unboundid.util.Debug;
import com.unboundid.util.Extensible;
import com.unboundid.util.InternalUseOnly;
import com.unboundid.util.NotMutable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import static com.unboundid.ldap.sdk.LDAPMessages.*;
/**
* This class implements the processing necessary to perform an LDAPv3 extended
* operation, which provides a way to request actions not included in the core
* LDAP protocol. Subclasses can provide logic to help implement more specific
* types of extended operations, but it is important to note that if such
* subclasses include an extended request value, then the request value must be
* kept up-to-date if any changes are made to custom elements in that class that
* would impact the request value encoding.
*/
@Extensible()
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public class ExtendedRequest
extends LDAPRequest
implements ResponseAcceptor, ProtocolOp
{
/**
* The BER type for the extended request OID element.
*/
protected static final byte TYPE_EXTENDED_REQUEST_OID = (byte) 0x80;
/**
* The BER type for the extended request value element.
*/
protected static final byte TYPE_EXTENDED_REQUEST_VALUE = (byte) 0x81;
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 5572410770060685796L;
// The encoded value for this extended request, if available.
private final ASN1OctetString value;
// The message ID from the last LDAP message sent from this request.
private int messageID = -1;
// The queue that will be used to receive response messages from the server.
private final LinkedBlockingQueue responseQueue =
new LinkedBlockingQueue<>();
// The OID for this extended request.
private final String oid;
/**
* Creates a new extended request with the provided OID and no value.
*
* @param oid The OID for this extended request. It must not be
* {@code null}.
*/
public ExtendedRequest(final String oid)
{
super(null);
Validator.ensureNotNull(oid);
this.oid = oid;
value = null;
}
/**
* Creates a new extended request with the provided OID and no value.
*
* @param oid The OID for this extended request. It must not be
* {@code null}.
* @param controls The set of controls for this extended request.
*/
public ExtendedRequest(final String oid, final Control[] controls)
{
super(controls);
Validator.ensureNotNull(oid);
this.oid = oid;
value = null;
}
/**
* Creates a new extended request with the provided OID and value.
*
* @param oid The OID for this extended request. It must not be
* {@code null}.
* @param value The encoded value for this extended request. It may be
* {@code null} if this request should not have a value.
*/
public ExtendedRequest(final String oid, final ASN1OctetString value)
{
super(null);
Validator.ensureNotNull(oid);
this.oid = oid;
this.value = value;
}
/**
* Creates a new extended request with the provided OID and value.
*
* @param oid The OID for this extended request. It must not be
* {@code null}.
* @param value The encoded value for this extended request. It may be
* {@code null} if this request should not have a value.
* @param controls The set of controls for this extended request.
*/
public ExtendedRequest(final String oid, final ASN1OctetString value,
final Control[] controls)
{
super(controls);
Validator.ensureNotNull(oid);
this.oid = oid;
this.value = value;
}
/**
* Creates a new extended request with the information from the provided
* extended request.
*
* @param extendedRequest The extended request that should be used to create
* this new extended request.
*/
protected ExtendedRequest(final ExtendedRequest extendedRequest)
{
super(extendedRequest.getControls());
messageID = extendedRequest.messageID;
oid = extendedRequest.oid;
value = extendedRequest.value;
}
/**
* Retrieves the OID for this extended request.
*
* @return The OID for this extended request.
*/
public final String getOID()
{
return oid;
}
/**
* Indicates whether this extended request has a value.
*
* @return {@code true} if this extended request has a value, or
* {@code false} if not.
*/
public final boolean hasValue()
{
return (value != null);
}
/**
* Retrieves the encoded value for this extended request, if available.
*
* @return The encoded value for this extended request, or {@code null} if
* this request does not have a value.
*/
public final ASN1OctetString getValue()
{
return value;
}
/**
* {@inheritDoc}
*/
@Override()
public final byte getProtocolOpType()
{
return LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST;
}
/**
* {@inheritDoc}
*/
@Override()
public final void writeTo(final ASN1Buffer writer)
{
final ASN1BufferSequence requestSequence =
writer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST);
writer.addOctetString(TYPE_EXTENDED_REQUEST_OID, oid);
if (value != null)
{
writer.addOctetString(TYPE_EXTENDED_REQUEST_VALUE, value.getValue());
}
requestSequence.end();
}
/**
* Encodes the extended request protocol op to an ASN.1 element.
*
* @return The ASN.1 element with the encoded extended request protocol op.
*/
@Override()
public ASN1Element encodeProtocolOp()
{
// Create the extended request protocol op.
final ASN1Element[] protocolOpElements;
if (value == null)
{
protocolOpElements = new ASN1Element[]
{
new ASN1OctetString(TYPE_EXTENDED_REQUEST_OID, oid)
};
}
else
{
protocolOpElements = new ASN1Element[]
{
new ASN1OctetString(TYPE_EXTENDED_REQUEST_OID, oid),
new ASN1OctetString(TYPE_EXTENDED_REQUEST_VALUE, value.getValue())
};
}
return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST,
protocolOpElements);
}
/**
* Sends this extended request to the directory server over the provided
* connection and returns the associated response.
*
* @param connection The connection to use to communicate with the directory
* server.
* @param depth The current referral depth for this request. It should
* always be one for the initial request, and should only
* be incremented when following referrals.
*
* @return An LDAP result object that provides information about the result
* of the extended operation processing.
*
* @throws LDAPException If a problem occurs while sending the request or
* reading the response.
*/
@Override()
protected ExtendedResult process(final LDAPConnection connection,
final int depth)
throws LDAPException
{
if (connection.synchronousMode())
{
return processSync(connection);
}
// Create the LDAP message.
messageID = connection.nextMessageID();
final LDAPMessage message = new LDAPMessage(messageID, this, getControls());
// Register with the connection reader to be notified of responses for the
// request that we've created.
connection.registerResponseAcceptor(messageID, this);
try
{
// Send the request to the server.
final long responseTimeout = getResponseTimeoutMillis(connection);
Debug.debugLDAPRequest(Level.INFO, this, messageID, connection);
final long requestTime = System.nanoTime();
connection.getConnectionStatistics().incrementNumExtendedRequests();
if (this instanceof StartTLSExtendedRequest)
{
connection.sendMessage(message, 50L);
}
else
{
connection.sendMessage(message, responseTimeout);
}
// Wait for and process the response.
final LDAPResponse response;
try
{
if (responseTimeout > 0)
{
response = responseQueue.poll(responseTimeout, TimeUnit.MILLISECONDS);
}
else
{
response = responseQueue.take();
}
}
catch (final InterruptedException ie)
{
Debug.debugException(ie);
Thread.currentThread().interrupt();
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_EXTOP_INTERRUPTED.get(connection.getHostPort()), ie);
}
return handleResponse(connection, response, requestTime);
}
finally
{
connection.deregisterResponseAcceptor(messageID);
}
}
/**
* Processes this extended operation in synchronous mode, in which the same
* thread will send the request and read the response.
*
* @param connection The connection to use to communicate with the directory
* server.
*
* @return An LDAP result object that provides information about the result
* of the extended processing.
*
* @throws LDAPException If a problem occurs while sending the request or
* reading the response.
*/
private ExtendedResult processSync(final LDAPConnection connection)
throws LDAPException
{
// Create the LDAP message.
messageID = connection.nextMessageID();
final LDAPMessage message =
new LDAPMessage(messageID, this, getControls());
// Send the request to the server.
final long requestTime = System.nanoTime();
Debug.debugLDAPRequest(Level.INFO, this, messageID, connection);
connection.getConnectionStatistics().incrementNumExtendedRequests();
connection.sendMessage(message, getResponseTimeoutMillis(connection));
while (true)
{
final LDAPResponse response;
try
{
response = connection.readResponse(messageID);
}
catch (final LDAPException le)
{
Debug.debugException(le);
if ((le.getResultCode() == ResultCode.TIMEOUT) &&
connection.getConnectionOptions().abandonOnTimeout())
{
connection.abandon(messageID);
}
throw le;
}
if (response instanceof IntermediateResponse)
{
final IntermediateResponseListener listener =
getIntermediateResponseListener();
if (listener != null)
{
listener.intermediateResponseReturned(
(IntermediateResponse) response);
}
}
else
{
return handleResponse(connection, response, requestTime);
}
}
}
/**
* Performs the necessary processing for handling a response.
*
* @param connection The connection used to read the response.
* @param response The response to be processed.
* @param requestTime The time the request was sent to the server.
*
* @return The extended result.
*
* @throws LDAPException If a problem occurs.
*/
private ExtendedResult handleResponse(final LDAPConnection connection,
final LDAPResponse response,
final long requestTime)
throws LDAPException
{
if (response == null)
{
final long waitTime =
StaticUtils.nanosToMillis(System.nanoTime() - requestTime);
if (connection.getConnectionOptions().abandonOnTimeout())
{
connection.abandon(messageID);
}
throw new LDAPException(ResultCode.TIMEOUT,
ERR_EXTENDED_CLIENT_TIMEOUT.get(waitTime, messageID, oid,
connection.getHostPort()));
}
if (response instanceof ConnectionClosedResponse)
{
final ConnectionClosedResponse ccr = (ConnectionClosedResponse) response;
final String msg = ccr.getMessage();
if (msg == null)
{
// The connection was closed while waiting for the response.
throw new LDAPException(ccr.getResultCode(),
ERR_CONN_CLOSED_WAITING_FOR_EXTENDED_RESPONSE.get(
connection.getHostPort(), toString()));
}
else
{
// The connection was closed while waiting for the response.
throw new LDAPException(ccr.getResultCode(),
ERR_CONN_CLOSED_WAITING_FOR_EXTENDED_RESPONSE_WITH_MESSAGE.get(
connection.getHostPort(), toString(), msg));
}
}
connection.getConnectionStatistics().incrementNumExtendedResponses(
System.nanoTime() - requestTime);
return (ExtendedResult) response;
}
/**
* {@inheritDoc}
*/
@InternalUseOnly()
@Override()
public final void responseReceived(final LDAPResponse response)
throws LDAPException
{
try
{
responseQueue.put(response);
}
catch (final Exception e)
{
Debug.debugException(e);
if (e instanceof InterruptedException)
{
Thread.currentThread().interrupt();
}
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_EXCEPTION_HANDLING_RESPONSE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* {@inheritDoc}
*/
@Override()
public final int getLastMessageID()
{
return messageID;
}
/**
* {@inheritDoc}
*/
@Override()
public final OperationType getOperationType()
{
return OperationType.EXTENDED;
}
/**
* {@inheritDoc}. Subclasses should override this method to return a
* duplicate of the appropriate type.
*/
@Override()
public ExtendedRequest duplicate()
{
return duplicate(getControls());
}
/**
* {@inheritDoc}. Subclasses should override this method to return a
* duplicate of the appropriate type.
*/
@Override()
public ExtendedRequest duplicate(final Control[] controls)
{
final ExtendedRequest r = new ExtendedRequest(oid, value, controls);
r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
return r;
}
/**
* Retrieves the user-friendly name for the extended request, if available.
* If no user-friendly name has been defined, then the OID will be returned.
*
* @return The user-friendly name for this extended request, or the OID if no
* user-friendly name is available.
*/
public String getExtendedRequestName()
{
// By default, we will return the OID. Subclasses should override this to
// provide the user-friendly name.
return oid;
}
/**
* {@inheritDoc}
*/
@Override()
public void toString(final StringBuilder buffer)
{
buffer.append("ExtendedRequest(oid='");
buffer.append(oid);
buffer.append('\'');
final Control[] controls = getControls();
if (controls.length > 0)
{
buffer.append(", controls={");
for (int i=0; i < controls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(controls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
/**
* {@inheritDoc}
*/
@Override()
public void toCode(final List lineList, final String requestID,
final int indentSpaces, final boolean includeProcessing)
{
// Create the request variable.
final ArrayList constructorArgs = new ArrayList<>(3);
constructorArgs.add(ToCodeArgHelper.createString(oid, "Request OID"));
constructorArgs.add(ToCodeArgHelper.createASN1OctetString(value,
"Request Value"));
final Control[] controls = getControls();
if (controls.length > 0)
{
constructorArgs.add(ToCodeArgHelper.createControlArray(controls,
"Request Controls"));
}
ToCodeHelper.generateMethodCall(lineList, indentSpaces, "ExtendedRequest",
requestID + "Request", "new ExtendedRequest", constructorArgs);
// Add lines for processing the request and obtaining the result.
if (includeProcessing)
{
// Generate a string with the appropriate indent.
final StringBuilder buffer = new StringBuilder();
for (int i=0; i < indentSpaces; i++)
{
buffer.append(' ');
}
final String indent = buffer.toString();
lineList.add("");
lineList.add(indent + "try");
lineList.add(indent + '{');
lineList.add(indent + " ExtendedResult " + requestID +
"Result = connection.processExtendedOperation(" + requestID +
"Request);");
lineList.add(indent + " // The extended operation was processed and " +
"we have a result.");
lineList.add(indent + " // This does not necessarily mean that the " +
"operation was successful.");
lineList.add(indent + " // Examine the result details for more " +
"information.");
lineList.add(indent + " ResultCode resultCode = " + requestID +
"Result.getResultCode();");
lineList.add(indent + " String message = " + requestID +
"Result.getMessage();");
lineList.add(indent + " String matchedDN = " + requestID +
"Result.getMatchedDN();");
lineList.add(indent + " String[] referralURLs = " + requestID +
"Result.getReferralURLs();");
lineList.add(indent + " String responseOID = " + requestID +
"Result.getOID();");
lineList.add(indent + " ASN1OctetString responseValue = " + requestID +
"Result.getValue();");
lineList.add(indent + " Control[] responseControls = " + requestID +
"Result.getResponseControls();");
lineList.add(indent + '}');
lineList.add(indent + "catch (LDAPException e)");
lineList.add(indent + '{');
lineList.add(indent + " // A problem was encountered while attempting " +
"to process the extended operation.");
lineList.add(indent + " // Maybe the following will help explain why.");
lineList.add(indent + " ResultCode resultCode = e.getResultCode();");
lineList.add(indent + " String message = e.getMessage();");
lineList.add(indent + " String matchedDN = e.getMatchedDN();");
lineList.add(indent + " String[] referralURLs = e.getReferralURLs();");
lineList.add(indent + " Control[] responseControls = " +
"e.getResponseControls();");
lineList.add(indent + '}');
}
}
}