Added new constructor. May need to tighten down interfaces in the future.
[packetcable.git] / packetcable-driver / src / main / java / org / umu / cops / stack / COPSClientSI.java
index 69b5fddb4716aac415e24479f65f76f00cb3cc9d..293332951c22c2356d9dcd09bcd7beeba6a003b7 100644 (file)
-/*\r
- * Copyright (c) 2003 University of Murcia.  All rights reserved.\r
- * --------------------------------------------------------------\r
- * For more information, please see <http://www.umu.euro6ix.org/>.\r
- */\r
-\r
-package org.umu.cops.stack;\r
-\r
-import java.io.IOException;\r
-import java.io.OutputStream;\r
-import java.net.Socket;\r
-\r
-/**\r
- * COPS Client Specific Information Object\r
- *\r
- * @version COPSClientSI.java, v 1.00 2003\r
- *\r
- */\r
-public class COPSClientSI extends COPSObjBase {\r
-    public final static byte CSI_SIGNALED = 1;\r
-    public final static byte CSI_NAMED = 2;\r
-\r
-    private COPSObjHeader _objHdr;\r
-    private COPSData _data;\r
-    private COPSData _padding;\r
-\r
-    ///\r
-    public COPSClientSI(byte type) {\r
-        _objHdr = new COPSObjHeader();\r
-        _objHdr.setCNum(COPSObjHeader.COPS_CSI);\r
-        _objHdr.setCType(type);\r
-    }\r
-\r
-    public COPSClientSI(byte cnum, byte ctype) {\r
-        _objHdr = new COPSObjHeader();\r
-        _objHdr.setCNum(cnum);\r
-        _objHdr.setCType(ctype);\r
-    }\r
-\r
-    /**\r
-     Parse the data and create a ClientSI object\r
-     */\r
-    protected COPSClientSI(byte[] dataPtr) {\r
-        _objHdr = new COPSObjHeader();\r
-        _objHdr.parse(dataPtr);\r
-        // _objHdr.checkDataLength();\r
-\r
-        //Get the length of data following the obj header\r
-        short dLen = (short) (_objHdr.getDataLength() - 4);\r
-        COPSData d = new COPSData(dataPtr, 4, dLen);\r
-        setData(d);\r
-    }\r
-\r
-    /**\r
-     * Method setData\r
-     *\r
-     * @param    data                a  COPSData\r
-     *\r
-     */\r
-    public void setData(COPSData data) {\r
-        _data = data;\r
-        if (_data.length() % 4 != 0) {\r
-            int padLen = 4 - _data.length() % 4;\r
-            _padding = getPadding(padLen);\r
-        }\r
-        _objHdr.setDataLength((short) _data.length());\r
-    }\r
-\r
-    /**\r
-     * Returns size in number of octects, including header\r
-     *\r
-     * @return   a short\r
-     *\r
-     */\r
-    public short getDataLength() {\r
-        //Add the size of the header also\r
-        int lpadding = 0;\r
-        if (_padding != null) lpadding = _padding.length();\r
-        return (short) (_objHdr.getDataLength() + lpadding);\r
-    }\r
-\r
-    /**\r
-     * Method getData\r
-     *\r
-     * @return   a COPSData\r
-     *\r
-     */\r
-    public COPSData getData() {\r
-        return _data;\r
-    };\r
-\r
-    /**\r
-     * Method isClientSI\r
-     *\r
-     * @return   a boolean\r
-     *\r
-     */\r
-    public boolean isClientSI() {\r
-        return true;\r
-    }\r
-\r
-    /**\r
-     * Write data on a given network socket\r
-     *\r
-     * @param    id                  a  Socket\r
-     *\r
-     * @throws   IOException\r
-     *\r
-     */\r
-    public void writeData(Socket id) throws IOException {\r
-        _objHdr.writeData(id);\r
-        COPSUtil.writeData(id, _data.getData(), _data.length());\r
-        if (_padding != null) {\r
-            COPSUtil.writeData(id, _padding.getData(), _padding.length());\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Write an object textual description in the output stream\r
-     *\r
-     * @param    os                  an OutputStream\r
-     *\r
-     * @throws   IOException\r
-     *\r
-     */\r
-    public void dump(OutputStream os) throws IOException {\r
-        _objHdr.dump(os);\r
-        os.write(new String("client-SI: " + _data.str() + "\n").getBytes());\r
-    }\r
-}\r
-\r
+/*
+ * Copyright (c) 2003 University of Murcia.  All rights reserved.
+ * --------------------------------------------------------------
+ * For more information, please see <http://www.umu.euro6ix.org/>.
+ */
+
+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 Client Specific Information Object (RFC 2748)
+ *
+ * The various types of this object are required for requests, and used
+ * in reports and opens when required. It contains client-type specific
+ * information.
+ *
+ * C-Num = 9,
+ *
+ * C-Type = 1, Signaled ClientSI.
+ *
+ * Variable-length field. All objects/attributes specific to a client's
+ * signaling protocol or internal state are encapsulated within one or
+ * more signaled Client Specific Information Objects. The format of the
+ * data encapsulated in the ClientSI object is determined by the
+ * client-type.
+ *
+ * C-Type = 2, Named ClientSI.
+ *
+ * Variable-length field. Contains named configuration information
+ * useful for relaying specific information about the PEP, a request, or
+ * configured state to the PDP server.
+ */
+public class COPSClientSI extends COPSObjBase {
+
+    private final static Map<Integer, CSIType> VAL_TO_CSI = new ConcurrentHashMap<>();
+    static {
+        VAL_TO_CSI.put(CSIType.NA.ordinal(), CSIType.NA);
+        VAL_TO_CSI.put(CSIType.SIGNALED.ordinal(), CSIType.SIGNALED);
+        VAL_TO_CSI.put(CSIType.NAMED.ordinal(), CSIType.NAMED);
+    }
+
+    /**
+     * This value is not being used here but stored only for clarity as it is being mapped directly to the
+     * ordinal value of the CType
+     */
+    private final CSIType _csiType;
+
+    /**
+     * The payload data
+     */
+    private final COPSData _data;
+
+    /**
+     * Bytes to add to outbound payload to ensure the length is divisible by 4 bytes
+     */
+    private final COPSData _padding;
+
+    /**
+     * Constructor generally used for sending messages
+     * @param ctype - the CSIType
+     * @param data - the data
+     * @throws java.lang.IllegalArgumentException
+     */
+    public COPSClientSI(final CNum cnum, final CType ctype, final COPSData data) {
+        /* The CSIType does not map directly to the CType, therefore the hook to map to a CType below is
+           required to ensure the header value outputs the correct value when streamed
+         */
+        this(new COPSObjHeader(cnum, ctype), data);
+    }
+
+    /**
+     * Constructor generally used for sending messages
+     * @param csitype - the CSIType
+     * @param data - the data
+     * @throws java.lang.IllegalArgumentException
+     */
+    public COPSClientSI(final CSIType csitype, final COPSData data) {
+        /* The CSIType does not map directly to the CType, therefore the hook to map to a CType below is
+           required to ensure the header value outputs the correct value when streamed
+         */
+        this(new COPSObjHeader(CNum.CSI, COPSObjHeader.VAL_TO_CTYPE.get(csitype.ordinal())), data);
+    }
+
+    /**
+     * 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 data - the data
+     * @throws java.lang.IllegalArgumentException
+     */
+    protected COPSClientSI(final COPSObjHeader hdr, final COPSData data) {
+        super(hdr);
+        if (VAL_TO_CSI.get(hdr.getCType().ordinal()) == null) {
+            // TODO - determine if this is a good default value???
+            _csiType = CSIType.NAMED;
+        } else {
+            _csiType = VAL_TO_CSI.get(hdr.getCType().ordinal());
+        }
+
+        if (!hdr.getCNum().equals(CNum.CSI) && !hdr.getCNum().equals(CNum.DEC))
+            throw new IllegalArgumentException("CNum must be equal to " + CNum.CSI + " or " + CNum.DEC);
+        if (_csiType == null || _csiType.equals(CSIType.NA))
+            throw new IllegalArgumentException("Invalid CSIType");
+        if (data == null) throw new IllegalArgumentException("Data must not be null");
+
+        _data = data;
+        if ((_data.length() % 4) != 0) {
+            final int padLen = 4 - (_data.length() % 4);
+            _padding = COPSObjectParser.getPadding(padLen);
+        } else {
+            _padding = new COPSData();
+        }
+    }
+
+    /**
+     * Returns the CSIType
+     * @return - the type
+     */
+    public CSIType getCsiType() { return _csiType; }
+
+    /**
+     * Returns the data
+     * @return - the data
+     */
+    public COPSData getData() { return _data; }
+
+    @Override
+    /* The super says protected but this needs to be public due to usage in COPSDecisionMsgEX.java which is currently
+       calling this method. */
+    public int getDataLength() {
+        return _data.length() + _padding.length();
+    }
+
+    @Override
+    public void writeBody(final Socket socket) throws IOException {
+        COPSUtil.writeData(socket, _data.getData(), _data.length());
+        if (_padding.length() > 0) COPSUtil.writeData(socket, _padding.getData(), _padding.length());
+    }
+
+    @Override
+    public void dumpBody(final OutputStream os) throws IOException {
+        os.write(("CSI-type: " + _csiType + "\n").getBytes());
+        os.write(("client-SI: " + _data.str() + "\n").getBytes());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof COPSClientSI)) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+
+        final COPSClientSI that = (COPSClientSI) o;
+        return _data.equals(that._data) && _padding.equals(that._padding) ||
+                COPSUtil.copsDataPaddingEquals(this._data, this._padding, that._data, that._padding);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (_data != null ? _data.hashCode() : 0);
+        result = 31 * result + (_padding != null ? _padding.hashCode() : 0);
+        return result;
+    }
+
+    /**
+     * Parses bytes to return a COPSClientSI object
+     * @param objHdrData - the associated header
+     * @param dataPtr - the data to parse
+     * @return - the object
+     * @throws java.lang.IllegalArgumentException
+     */
+    public static COPSClientSI parse(final COPSObjHeaderData objHdrData, final byte[] dataPtr) {
+        short dLen = (short) (objHdrData.msgByteCount - 4);
+        return new COPSClientSI(objHdrData.header, new COPSData(dataPtr, 4, dLen));
+    }
+
+    /**
+     * The different CSI types. NA does not exist but is a placeholder for 0 as the ordinal values will be used
+     * to determine which type for marshalling
+     */
+    public enum CSIType {
+        NA, SIGNALED, NAMED
+    }
+}
+