package com.hwlcn.ldap.ldap.sdk.extensions;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import com.hwlcn.ldap.asn1.ASN1Constants;
import com.hwlcn.ldap.asn1.ASN1Element;
import com.hwlcn.ldap.asn1.ASN1Exception;
import com.hwlcn.ldap.asn1.ASN1Integer;
import com.hwlcn.ldap.asn1.ASN1OctetString;
import com.hwlcn.ldap.asn1.ASN1Sequence;
import com.hwlcn.ldap.ldap.sdk.Control;
import com.hwlcn.ldap.ldap.sdk.ExtendedResult;
import com.hwlcn.ldap.ldap.sdk.LDAPException;
import com.hwlcn.ldap.ldap.sdk.ResultCode;
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.extensions.ExtOpMessages.*;
import static com.hwlcn.ldap.util.Debug.*;
import static com.hwlcn.ldap.util.StaticUtils.*;
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class EndTransactionExtendedResult
extends ExtendedResult
{
private static final long serialVersionUID = 1514265185948328221L;
private final int failedOpMessageID;
private final TreeMap<Integer,Control[]> opResponseControls;
public EndTransactionExtendedResult(final ExtendedResult extendedResult)
throws LDAPException
{
super(extendedResult);
opResponseControls = new TreeMap<Integer,Control[]>();
final ASN1OctetString value = extendedResult.getValue();
if (value == null)
{
failedOpMessageID = -1;
return;
}
final ASN1Sequence valueSequence;
try
{
final ASN1Element valueElement = ASN1Element.decode(value.getValue());
valueSequence = ASN1Sequence.decodeAsSequence(valueElement);
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_VALUE_NOT_SEQUENCE.get(ae.getMessage()), ae);
}
final ASN1Element[] valueElements = valueSequence.elements();
if (valueElements.length == 0)
{
failedOpMessageID = -1;
return;
}
else if (valueElements.length > 2)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_INVALID_ELEMENT_COUNT.get(
valueElements.length));
}
int msgID = -1;
for (final ASN1Element e : valueElements)
{
if (e.getType() == ASN1Constants.UNIVERSAL_INTEGER_TYPE)
{
try
{
msgID = ASN1Integer.decodeAsInteger(e).intValue();
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_CANNOT_DECODE_MSGID.get(ae), ae);
}
}
else if (e.getType() == ASN1Constants.UNIVERSAL_SEQUENCE_TYPE)
{
decodeOpControls(e, opResponseControls);
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_INVALID_TYPE.get(toHex(e.getType())));
}
}
failedOpMessageID = msgID;
}
public EndTransactionExtendedResult(final int messageID,
final ResultCode resultCode, final String diagnosticMessage,
final String matchedDN, final String[] referralURLs,
final Integer failedOpMessageID,
final Map<Integer,Control[]> opResponseControls,
final Control[] responseControls)
{
super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
null, encodeValue(failedOpMessageID, opResponseControls),
responseControls);
if ((failedOpMessageID == null) || (failedOpMessageID <= 0))
{
this.failedOpMessageID = -1;
}
else
{
this.failedOpMessageID = failedOpMessageID;
}
if (opResponseControls == null)
{
this.opResponseControls = new TreeMap<Integer,Control[]>();
}
else
{
this.opResponseControls =
new TreeMap<Integer,Control[]>(opResponseControls);
}
}
private static void decodeOpControls(final ASN1Element element,
final Map<Integer,Control[]> controlMap)
throws LDAPException
{
final ASN1Sequence ctlsSequence;
try
{
ctlsSequence = ASN1Sequence.decodeAsSequence(element);
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_CONTROLS_NOT_SEQUENCE.get(ae), ae);
}
for (final ASN1Element e : ctlsSequence.elements())
{
final ASN1Sequence ctlSequence;
try
{
ctlSequence = ASN1Sequence.decodeAsSequence(e);
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_CONTROL_NOT_SEQUENCE.get(ae), ae);
}
final ASN1Element[] ctlSequenceElements = ctlSequence.elements();
if (ctlSequenceElements.length != 2)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_CONTROL_INVALID_ELEMENT_COUNT.get(
ctlSequenceElements.length));
}
final int msgID;
try
{
msgID = ASN1Integer.decodeAsInteger(ctlSequenceElements[0]).intValue();
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_CONTROL_MSGID_NOT_INT.get(ae), ae);
}
final ASN1Sequence controlsSequence;
try
{
controlsSequence =
ASN1Sequence.decodeAsSequence(ctlSequenceElements[1]);
}
catch (final ASN1Exception ae)
{
debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_END_TXN_RESPONSE_CONTROLS_ELEMENT_NOT_SEQUENCE.get(ae), ae);
}
final Control[] controls = Control.decodeControls(controlsSequence);
if (controls.length == 0)
{
continue;
}
controlMap.put(msgID, controls);
}
}
private static ASN1OctetString encodeValue(final Integer failedOpMessageID,
final Map<Integer,Control[]> opResponseControls)
{
if ((failedOpMessageID == null) && (opResponseControls == null))
{
return null;
}
final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
if (failedOpMessageID != null)
{
elements.add(new ASN1Integer(failedOpMessageID));
}
if ((opResponseControls != null) && (! opResponseControls.isEmpty()))
{
final ArrayList<ASN1Element> controlElements =
new ArrayList<ASN1Element>();
for (final Map.Entry<Integer,Control[]> e : opResponseControls.entrySet())
{
final ASN1Element[] ctlElements =
{
new ASN1Integer(e.getKey()),
Control.encodeControls(e.getValue())
};
controlElements.add(new ASN1Sequence(ctlElements));
}
elements.add(new ASN1Sequence(controlElements));
}
return new ASN1OctetString(new ASN1Sequence(elements).encode());
}
public int getFailedOpMessageID()
{
return failedOpMessageID;
}
public Map<Integer,Control[]> getOperationResponseControls()
{
return opResponseControls;
}
public Control[] getOperationResponseControls(final int messageID)
{
return opResponseControls.get(messageID);
}
@Override()
public String getExtendedResultName()
{
return INFO_EXTENDED_RESULT_NAME_END_TXN.get();
}
@Override()
public void toString(final StringBuilder buffer)
{
buffer.append("EndTransactionExtendedResult(resultCode=");
buffer.append(getResultCode());
final int messageID = getMessageID();
if (messageID >= 0)
{
buffer.append(", messageID=");
buffer.append(messageID);
}
if (failedOpMessageID > 0)
{
buffer.append(", failedOpMessageID=");
buffer.append(failedOpMessageID);
}
if (! opResponseControls.isEmpty())
{
buffer.append(", opResponseControls={");
for (final int msgID : opResponseControls.keySet())
{
buffer.append("opMsgID=");
buffer.append(msgID);
buffer.append(", opControls={");
boolean first = true;
for (final Control c : opResponseControls.get(msgID))
{
if (first)
{
first = false;
}
else
{
buffer.append(", ");
}
buffer.append(c);
}
buffer.append('}');
}
buffer.append('}');
}
final String diagnosticMessage = getDiagnosticMessage();
if (diagnosticMessage != null)
{
buffer.append(", diagnosticMessage='");
buffer.append(diagnosticMessage);
buffer.append('\'');
}
final String matchedDN = getMatchedDN();
if (matchedDN != null)
{
buffer.append(", matchedDN='");
buffer.append(matchedDN);
buffer.append('\'');
}
final String[] referralURLs = getReferralURLs();
if (referralURLs.length > 0)
{
buffer.append(", referralURLs={");
for (int i=0; i < referralURLs.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append('\'');
buffer.append(referralURLs[i]);
buffer.append('\'');
}
buffer.append('}');
}
final Control[] responseControls = getResponseControls();
if (responseControls.length > 0)
{
buffer.append(", responseControls={");
for (int i=0; i < responseControls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(responseControls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
}