2 * Copyright (c) 2003 University of Murcia. All rights reserved.
3 * --------------------------------------------------------------
4 * For more information, please see <http://www.umu.euro6ix.org/>.
7 package org.umu.cops.stack;
9 import org.umu.cops.stack.COPSObjHeader.CNum;
10 import org.umu.cops.stack.COPSObjHeader.CType;
12 import java.io.IOException;
13 import java.io.OutputStream;
14 import java.net.Socket;
16 import java.util.concurrent.ConcurrentHashMap;
19 * COPS Client Specific Information Object (RFC 2748)
21 * The various types of this object are required for requests, and used
22 * in reports and opens when required. It contains client-type specific
27 * C-Type = 1, Signaled ClientSI.
29 * Variable-length field. All objects/attributes specific to a client's
30 * signaling protocol or internal state are encapsulated within one or
31 * more signaled Client Specific Information Objects. The format of the
32 * data encapsulated in the ClientSI object is determined by the
35 * C-Type = 2, Named ClientSI.
37 * Variable-length field. Contains named configuration information
38 * useful for relaying specific information about the PEP, a request, or
39 * configured state to the PDP server.
41 public class COPSClientSI extends COPSObjBase {
43 private final static Map<Integer, CSIType> VAL_TO_CSI = new ConcurrentHashMap<>();
45 VAL_TO_CSI.put(CSIType.NA.ordinal(), CSIType.NA);
46 VAL_TO_CSI.put(CSIType.SIGNALED.ordinal(), CSIType.SIGNALED);
47 VAL_TO_CSI.put(CSIType.NAMED.ordinal(), CSIType.NAMED);
51 * This value is not being used here but stored only for clarity as it is being mapped directly to the
52 * ordinal value of the CType
54 private final CSIType _csiType;
59 private final COPSData _data;
62 * Bytes to add to outbound payload to ensure the length is divisible by 4 bytes
64 private final COPSData _padding;
67 * Constructor generally used for sending messages
68 * @param ctype - the CSIType
69 * @param data - the data
70 * @throws java.lang.IllegalArgumentException
72 public COPSClientSI(final CNum cnum, final CType ctype, final COPSData data) {
73 /* The CSIType does not map directly to the CType, therefore the hook to map to a CType below is
74 required to ensure the header value outputs the correct value when streamed
76 this(new COPSObjHeader(cnum, ctype), data);
80 * Constructor generally used for sending messages
81 * @param csitype - the CSIType
82 * @param data - the data
83 * @throws java.lang.IllegalArgumentException
85 public COPSClientSI(final CSIType csitype, final COPSData data) {
86 /* The CSIType does not map directly to the CType, therefore the hook to map to a CType below is
87 required to ensure the header value outputs the correct value when streamed
89 this(new COPSObjHeader(CNum.CSI, COPSObjHeader.VAL_TO_CTYPE.get(csitype.ordinal())), data);
93 * Constructor generally used when parsing the bytes of an inbound COPS message but can also be used when the
94 * COPSObjHeader information is known
95 * @param hdr - the object header
96 * @param data - the data
97 * @throws java.lang.IllegalArgumentException
99 protected COPSClientSI(final COPSObjHeader hdr, final COPSData data) {
101 if (VAL_TO_CSI.get(hdr.getCType().ordinal()) == null) {
102 // TODO - determine if this is a good default value???
103 _csiType = CSIType.NAMED;
105 _csiType = VAL_TO_CSI.get(hdr.getCType().ordinal());
108 if (!hdr.getCNum().equals(CNum.CSI) && !hdr.getCNum().equals(CNum.DEC))
109 throw new IllegalArgumentException("CNum must be equal to " + CNum.CSI + " or " + CNum.DEC);
110 if (_csiType == null || _csiType.equals(CSIType.NA))
111 throw new IllegalArgumentException("Invalid CSIType");
112 if (data == null) throw new IllegalArgumentException("Data must not be null");
115 if ((_data.length() % 4) != 0) {
116 final int padLen = 4 - (_data.length() % 4);
117 _padding = COPSObjectParser.getPadding(padLen);
119 _padding = new COPSData();
124 * Returns the CSIType
127 public CSIType getCsiType() { return _csiType; }
133 public COPSData getData() { return _data; }
136 /* The super says protected but this needs to be public due to usage in COPSDecisionMsgEX.java which is currently
137 calling this method. */
138 public int getDataLength() {
139 return _data.length() + _padding.length();
143 public void writeBody(final Socket socket) throws IOException {
144 COPSUtil.writeData(socket, _data.getData(), _data.length());
145 if (_padding.length() > 0) COPSUtil.writeData(socket, _padding.getData(), _padding.length());
149 public void dumpBody(final OutputStream os) throws IOException {
150 os.write(("CSI-type: " + _csiType + "\n").getBytes());
151 os.write(("client-SI: " + _data.str() + "\n").getBytes());
155 public boolean equals(Object o) {
159 if (!(o instanceof COPSClientSI)) {
162 if (!super.equals(o)) {
166 final COPSClientSI that = (COPSClientSI) o;
167 return _data.equals(that._data) && _padding.equals(that._padding) ||
168 COPSUtil.copsDataPaddingEquals(this._data, this._padding, that._data, that._padding);
172 public int hashCode() {
173 int result = super.hashCode();
174 result = 31 * result + (_data != null ? _data.hashCode() : 0);
175 result = 31 * result + (_padding != null ? _padding.hashCode() : 0);
180 * Parses bytes to return a COPSClientSI object
181 * @param objHdrData - the associated header
182 * @param dataPtr - the data to parse
183 * @return - the object
184 * @throws java.lang.IllegalArgumentException
186 public static COPSClientSI parse(final COPSObjHeaderData objHdrData, final byte[] dataPtr) {
187 short dLen = (short) (objHdrData.msgByteCount - 4);
188 return new COPSClientSI(objHdrData.header, new COPSData(dataPtr, 4, dLen));
192 * The different CSI types. NA does not exist but is a placeholder for 0 as the ordinal values will be used
193 * to determine which type for marshalling
195 public enum CSIType {