package com.hwlcn.ldap.ldap.sdk; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import com.hwlcn.ldap.asn1.ASN1Buffer; import com.hwlcn.ldap.asn1.ASN1BufferSequence; import com.hwlcn.ldap.asn1.ASN1Element; import com.hwlcn.ldap.asn1.ASN1OctetString; import com.hwlcn.ldap.asn1.ASN1Sequence; import com.hwlcn.ldap.ldap.protocol.LDAPMessage; import com.hwlcn.ldap.ldap.protocol.LDAPResponse; import com.hwlcn.ldap.ldap.protocol.ProtocolOp; import com.hwlcn.core.annotation.Extensible; import com.hwlcn.core.annotation.InternalUseOnly; import com.hwlcn.core.annotation.NotMutable; import com.hwlcn.core.annotation.ThreadSafety; import com.hwlcn.ldap.util.ThreadSafetyLevel; import static com.hwlcn.ldap.ldap.sdk.LDAPMessages.*; import static com.hwlcn.ldap.util.Debug.*; import static com.hwlcn.ldap.util.StaticUtils.*; import static com.hwlcn.ldap.util.Validator.*; @Extensible() @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) public class ExtendedRequest extends LDAPRequest implements ResponseAcceptor, ProtocolOp { protected static final byte TYPE_EXTENDED_REQUEST_OID = (byte) 0x80; protected static final byte TYPE_EXTENDED_REQUEST_VALUE = (byte) 0x81; private static final long serialVersionUID = 5572410770060685796L; private final ASN1OctetString value; private int messageID = -1; private final LinkedBlockingQueue<LDAPResponse> responseQueue = new LinkedBlockingQueue<LDAPResponse>(); private final String oid; public ExtendedRequest(final String oid) { super(null); ensureNotNull(oid); this.oid = oid; value = null; } public ExtendedRequest(final String oid, final Control[] controls) { super(controls); ensureNotNull(oid); this.oid = oid; value = null; } public ExtendedRequest(final String oid, final ASN1OctetString value) { super(null); ensureNotNull(oid); this.oid = oid; this.value = value; } public ExtendedRequest(final String oid, final ASN1OctetString value, final Control[] controls) { super(controls); ensureNotNull(oid); this.oid = oid; this.value = value; } protected ExtendedRequest(final ExtendedRequest extendedRequest) { super(extendedRequest.getControls()); oid = extendedRequest.oid; value = extendedRequest.value; } public final String getOID() { return oid; } public final boolean hasValue() { return (value != null); } public final ASN1OctetString getValue() { return value; } public final byte getProtocolOpType() { return LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST; } 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(); } public ASN1Element encodeProtocolOp() { 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); } @Override() protected ExtendedResult process(final LDAPConnection connection, final int depth) throws LDAPException { if (connection.synchronousMode()) { return processSync(connection); } messageID = connection.nextMessageID(); final LDAPMessage message = new LDAPMessage(messageID, this, getControls()); connection.registerResponseAcceptor(messageID, this); try { debugLDAPRequest(this); final long requestTime = System.nanoTime(); connection.getConnectionStatistics().incrementNumExtendedRequests(); connection.sendMessage(message); final LDAPResponse response; try { final long responseTimeout = getResponseTimeoutMillis(connection); if (responseTimeout > 0) { response = responseQueue.poll(responseTimeout, TimeUnit.MILLISECONDS); } else { response = responseQueue.take(); } } catch (InterruptedException ie) { debugException(ie); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_EXTOP_INTERRUPTED.get(connection.getHostPort()), ie); } return handleResponse(connection, response, requestTime); } finally { connection.deregisterResponseAcceptor(messageID); } } private ExtendedResult processSync(final LDAPConnection connection) throws LDAPException { messageID = connection.nextMessageID(); final LDAPMessage message = new LDAPMessage(messageID, this, getControls()); try { connection.getConnectionInternals(true).getSocket().setSoTimeout( (int) getResponseTimeoutMillis(connection)); } catch (Exception e) { debugException(e); } final long requestTime = System.nanoTime(); debugLDAPRequest(this); connection.getConnectionStatistics().incrementNumExtendedRequests(); connection.sendMessage(message); while (true) { final LDAPResponse response; try { response = connection.readResponse(messageID); } catch (final LDAPException le) { 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); } } } private ExtendedResult handleResponse(final LDAPConnection connection, final LDAPResponse response, final long requestTime) throws LDAPException { if (response == null) { final long waitTime = nanosToMillis(System.nanoTime() - requestTime); if (connection.getConnectionOptions().abandonOnTimeout()) { connection.abandon(messageID); } throw new LDAPException(ResultCode.TIMEOUT, ERR_EXTENDED_CLIENT_TIMEOUT.get(waitTime, connection.getHostPort())); } if (response instanceof ConnectionClosedResponse) { final ConnectionClosedResponse ccr = (ConnectionClosedResponse) response; final String msg = ccr.getMessage(); if (msg == null) { throw new LDAPException(ccr.getResultCode(), ERR_CONN_CLOSED_WAITING_FOR_EXTENDED_RESPONSE.get( connection.getHostPort(), toString())); } else { 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; } @InternalUseOnly() public final void responseReceived(final LDAPResponse response) throws LDAPException { try { responseQueue.put(response); } catch (Exception e) { debugException(e); throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_EXCEPTION_HANDLING_RESPONSE.get(getExceptionMessage(e)), e); } } @Override() public final int getLastMessageID() { return messageID; } @Override() public final OperationType getOperationType() { return OperationType.EXTENDED; } public ExtendedRequest duplicate() { return duplicate(getControls()); } public ExtendedRequest duplicate(final Control[] controls) { final ExtendedRequest r = new ExtendedRequest(oid, value, controls); r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); return r; } public String getExtendedRequestName() { return oid; } @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(')'); } }