Merge changes If0630105,I9d2d5e61,I1cea2a32,Icc05b6a7,Ic57eb4f8, ...
[packetcable.git] / packetcable-driver / src / main / java / org / umu / cops / stack / COPSClientSI.java
1 /*
2  * Copyright (c) 2003 University of Murcia.  All rights reserved.
3  * --------------------------------------------------------------
4  * For more information, please see <http://www.umu.euro6ix.org/>.
5  */
6
7 package org.umu.cops.stack;
8
9 import org.umu.cops.stack.COPSObjHeader.CNum;
10 import org.umu.cops.stack.COPSObjHeader.CType;
11
12 import java.io.IOException;
13 import java.io.OutputStream;
14 import java.net.Socket;
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17
18 /**
19  * COPS Client Specific Information Object (RFC 2748)
20  *
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
23  * information.
24  *
25  * C-Num = 9,
26  *
27  * C-Type = 1, Signaled ClientSI.
28  *
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
33  * client-type.
34  *
35  * C-Type = 2, Named ClientSI.
36  *
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.
40  */
41 public class COPSClientSI extends COPSObjBase {
42
43     private final static Map<Integer, CSIType> VAL_TO_CSI = new ConcurrentHashMap<>();
44     static {
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);
48     }
49
50     /**
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
53      */
54     private final CSIType _csiType;
55
56     /**
57      * The payload data
58      */
59     private final COPSData _data;
60
61     /**
62      * Bytes to add to outbound payload to ensure the length is divisible by 4 bytes
63      */
64     private final COPSData _padding;
65
66     /**
67      * Constructor generally used for sending messages
68      * @param ctype - the CSIType
69      * @param data - the data
70      * @throws java.lang.IllegalArgumentException
71      */
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
75          */
76         this(new COPSObjHeader(cnum, ctype), data);
77     }
78
79     /**
80      * Constructor generally used for sending messages
81      * @param csitype - the CSIType
82      * @param data - the data
83      * @throws java.lang.IllegalArgumentException
84      */
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
88          */
89         this(new COPSObjHeader(CNum.CSI, COPSObjHeader.VAL_TO_CTYPE.get(csitype.ordinal())), data);
90     }
91
92     /**
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
98      */
99     protected COPSClientSI(final COPSObjHeader hdr, final COPSData data) {
100         super(hdr);
101         if (VAL_TO_CSI.get(hdr.getCType().ordinal()) == null) {
102             // TODO - determine if this is a good default value???
103             _csiType = CSIType.NAMED;
104         } else {
105             _csiType = VAL_TO_CSI.get(hdr.getCType().ordinal());
106         }
107
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");
113
114         _data = data;
115         if ((_data.length() % 4) != 0) {
116             final int padLen = 4 - (_data.length() % 4);
117             _padding = COPSObjectParser.getPadding(padLen);
118         } else {
119             _padding = new COPSData();
120         }
121     }
122
123     /**
124      * Returns the CSIType
125      * @return - the type
126      */
127     public CSIType getCsiType() { return _csiType; }
128
129     /**
130      * Returns the data
131      * @return - the data
132      */
133     public COPSData getData() { return _data; }
134
135     @Override
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();
140     }
141
142     @Override
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());
146     }
147
148     @Override
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());
152     }
153
154     @Override
155     public boolean equals(Object o) {
156         if (this == o) {
157             return true;
158         }
159         if (!(o instanceof COPSClientSI)) {
160             return false;
161         }
162         if (!super.equals(o)) {
163             return false;
164         }
165
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);
169     }
170
171     @Override
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);
176         return result;
177     }
178
179     /**
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
185      */
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));
189     }
190
191     /**
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
194      */
195     public enum CSIType {
196         NA, SIGNALED, NAMED
197     }
198 }
199