/*
* Copyright (c) 2003 University of Murcia. All rights reserved.
* --------------------------------------------------------------
* For more information, please see .
*/
package org.umu.cops.stack;
import org.umu.cops.stack.COPSObjHeader.CNum;
import org.umu.cops.stack.COPSObjHeader.CType;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* COPS Reason Object (RFC 2748 page. 12)
*
* This object specifies the reason why the request state was deleted.
* It appears in the delete request (DRQ) message. The Reason Sub-code
* field is reserved for more detailed client-specific reason codes
* defined in the corresponding documents.
*
* C-Num = 5, C-Type = 1
*
* 0 1 2 3
* +--------------+--------------+--------------+--------------+
* | Reason-Code | Reason Sub-code |
* +--------------+--------------+--------------+--------------+
*
* Reason Code:
* 1 = Unspecified
* 2 = Management
* 3 = Preempted (Another request state takes precedence)
* 4 = Tear (Used to communicate a signaled state removal)
* 5 = Timeout (Local state has timed-out)
* 6 = Route Change (Change invalidates request state)
* 7 = Insufficient Resources (No local resource available)
* 8 = PDP's Directive (PDP decision caused the delete)
* 9 = Unsupported decision (PDP decision not supported)
* 10= Synchronize Handle Unknown
* 11= Transient Handle (stateless event)
* 12= Malformed Decision (could not recover)
* 13= Unknown COPS Object from PDP:
* Sub-code (octet 2) contains unknown object's C-Num
* and (octet 3) contains unknown object's C-Type.
*
* @version COPSReason.java, v 1.00 2003
*
*/
public class COPSReason extends COPSObjBase {
private final static Map VAL_TO_REASON = new ConcurrentHashMap<>();
static {
VAL_TO_REASON.put(ReasonCode.NA.ordinal(), ReasonCode.NA);
VAL_TO_REASON.put(ReasonCode.UNSPECIFIED.ordinal(), ReasonCode.UNSPECIFIED);
VAL_TO_REASON.put(ReasonCode.MANAGEMENT.ordinal(), ReasonCode.MANAGEMENT);
VAL_TO_REASON.put(ReasonCode.PREEMPTED.ordinal(), ReasonCode.PREEMPTED);
VAL_TO_REASON.put(ReasonCode.TEAR.ordinal(), ReasonCode.TEAR);
VAL_TO_REASON.put(ReasonCode.TIMEOUT.ordinal(), ReasonCode.TIMEOUT);
VAL_TO_REASON.put(ReasonCode.ROUTE_CHANGE.ordinal(), ReasonCode.ROUTE_CHANGE);
VAL_TO_REASON.put(ReasonCode.INSUFF_RESOURCES.ordinal(), ReasonCode.INSUFF_RESOURCES);
VAL_TO_REASON.put(ReasonCode.PDP_DIRECTIVE.ordinal(), ReasonCode.PDP_DIRECTIVE);
VAL_TO_REASON.put(ReasonCode.UNSUPPORT_DEC.ordinal(), ReasonCode.UNSUPPORT_DEC);
VAL_TO_REASON.put(ReasonCode.SYNC_HANDLE.ordinal(), ReasonCode.SYNC_HANDLE);
VAL_TO_REASON.put(ReasonCode.TRANS_HANDLE.ordinal(), ReasonCode.TRANS_HANDLE);
VAL_TO_REASON.put(ReasonCode.MALFORMED_DEC.ordinal(), ReasonCode.MALFORMED_DEC);
VAL_TO_REASON.put(ReasonCode.UNKNOWN_COPS_OBJ.ordinal(), ReasonCode.UNKNOWN_COPS_OBJ);
}
private final static Map REASON_TO_STRING = new ConcurrentHashMap<>();
static {
REASON_TO_STRING.put(ReasonCode.NA, "Unknown.");
REASON_TO_STRING.put(ReasonCode.UNSPECIFIED, "Unspecified.");
REASON_TO_STRING.put(ReasonCode.MANAGEMENT, "Management.");
REASON_TO_STRING.put(ReasonCode.PREEMPTED, "Preempted (Another request state takes precedence).");
REASON_TO_STRING.put(ReasonCode.TEAR, "Tear (Used to communicate a signaled state removal).");
REASON_TO_STRING.put(ReasonCode.TIMEOUT, "Timeout ( Local state has timed-out).");
REASON_TO_STRING.put(ReasonCode.ROUTE_CHANGE, "Route change (Change invalidates request state).");
REASON_TO_STRING.put(ReasonCode.INSUFF_RESOURCES, "Insufficient Resources.");
REASON_TO_STRING.put(ReasonCode.PDP_DIRECTIVE, "PDP's Directive.");
REASON_TO_STRING.put(ReasonCode.UNSUPPORT_DEC, "Unsupported decision.");
REASON_TO_STRING.put(ReasonCode.SYNC_HANDLE, "Synchronize handle unknown.");
REASON_TO_STRING.put(ReasonCode.TRANS_HANDLE, "Transient handle.");
REASON_TO_STRING.put(ReasonCode.MALFORMED_DEC, "Malformed decision.");
REASON_TO_STRING.put(ReasonCode.UNKNOWN_COPS_OBJ, "Unknown COPS object from PDP.");
}
/**
* The reason
*/
private final ReasonCode _reasonCode;
/**
* Reserved for more detailed client-specific reasons
*/
private final ReasonCode _reasonSubCode;
/**
* Constructor generally used for sending messages
* @param reasonCode - the reason code
* @param subCode - more detailed reasons
* @throws java.lang.IllegalArgumentException
*/
public COPSReason(final ReasonCode reasonCode, final ReasonCode subCode) {
this(new COPSObjHeader(CNum.REASON_CODE, CType.DEF), reasonCode, subCode);
}
/**
* Constructor generally used when parsing the bytes of an inbound COPS message but can also be used when the
* COPSObjHeader information is known
* @param hdr - the object header
* @param reasonCode - the reason code
* @param subCode - the type of message
* @throws java.lang.IllegalArgumentException
*/
protected COPSReason(final COPSObjHeader hdr, final ReasonCode reasonCode, final ReasonCode subCode) {
super(hdr);
if (!hdr.getCNum().equals(CNum.REASON_CODE))
throw new IllegalArgumentException("Must have a CNum value of " + CNum.REASON_CODE);
if (!hdr.getCType().equals(CType.DEF))
throw new IllegalArgumentException("Must have a CType value of " + CType.DEF);
if (reasonCode == null || subCode == null) throw new IllegalArgumentException("Error codes must not be null");
if (reasonCode.equals(ReasonCode.NA))
throw new IllegalArgumentException("Error code must not be of type " + ReasonCode.NA);
_reasonCode = reasonCode;
_reasonSubCode = subCode;
}
public ReasonCode getReasonCode() { return _reasonCode; }
public ReasonCode getReasonSubCode() { return _reasonSubCode; }
@Override
protected int getDataLength() {
return 4;
}
/**
* Get Reason description
* @return a String
*/
public String getDescription() {
return (REASON_TO_STRING.get(_reasonCode) + ":");
}
@Override
protected void writeBody(final Socket id) throws IOException {
final byte[] buf = new byte[4];
buf[0] = (byte) (_reasonCode.ordinal() >> 8);
buf[1] = (byte) _reasonCode.ordinal();
buf[2] = (byte) (_reasonSubCode.ordinal() >> 8);
buf[3] = (byte) _reasonSubCode.ordinal();
COPSUtil.writeData(id, buf, 4);
}
@Override
public void dumpBody(final OutputStream os) throws IOException {
os.write(("Reason Code: " + _reasonCode + "\n").getBytes());
os.write(("Reason Sub Code: " + _reasonSubCode + "\n").getBytes());
}
/**
* Creates this object from a byte array
* @param objHdrData - the header
* @param dataPtr - the data to parse
* @return - a new Timer
* @throws java.lang.IllegalArgumentException
*/
public static COPSReason parse(final COPSObjHeaderData objHdrData, byte[] dataPtr) {
short reasonCode = 0;
reasonCode |= ((short) dataPtr[4]) << 8;
reasonCode |= ((short) dataPtr[5]) & 0xFF;
short reasonSubCode = 0;
reasonSubCode |= ((short) dataPtr[6]) << 8;
reasonSubCode |= ((short) dataPtr[7]) & 0xFF;
return new COPSReason(objHdrData.header, VAL_TO_REASON.get((int)reasonCode),
VAL_TO_REASON.get((int)reasonSubCode));
}
/**
* All of the supported reason codes
*/
public enum ReasonCode {
NA, UNSPECIFIED, MANAGEMENT, PREEMPTED, TEAR, TIMEOUT, ROUTE_CHANGE, INSUFF_RESOURCES, PDP_DIRECTIVE,
UNSUPPORT_DEC, SYNC_HANDLE, TRANS_HANDLE, MALFORMED_DEC, UNKNOWN_COPS_OBJ
}
}