910c94a5c4cf7191c77d7b085e126af4b2a1b1f6
[packetcable.git] / packetcable-driver / src / main / java / org / pcmm / gates / impl / DOCSISFlowSpecTrafficProfile.java
1 /*
2  * Copyright (c) 2016 Applied Broadband, Inc. All Rights Reserved
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.pcmm.gates.impl;
10
11 import org.pcmm.base.impl.PCMMBaseObject;
12 import org.pcmm.gates.ITrafficProfile;
13 import org.pcmm.utils.PCMMUtils;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16
17 import java.util.Arrays;
18 import java.nio.ByteBuffer;
19
20 /**
21  * The DOCSIS Flow Spec object defines the Flow Spec Traffic Profile of a Gate.
22  *
23  */
24 public class DOCSISFlowSpecTrafficProfile extends PCMMBaseObject implements ITrafficProfile {
25
26     private final Logger logger = LoggerFactory.getLogger(DOCSISFlowSpecTrafficProfile.class);
27     public static final byte STYPE = 1;
28     public static final byte SERVICE_NUMBER = 2;
29
30     /**
31      * The envelope
32      */
33     private final byte envelope;
34     private final int tokenBucketRate;
35     private final int tokenBucketSize;
36     private final int peakDataRate;
37     private final int minimumPolicedUnit;
38     private final int maximumPacketSize;
39     private final int rate;
40     private final int slackTerm;
41     
42     /**
43      * Constructor using the default envelope values
44      * @param tokenBucketRate - Token Bucket Rate value [r]
45      * @param tokenBucketSize - Token Bucket Size value [b]
46      * @param peakDataRate - Peak Data Rate value [p]
47      * @param minimumPolicedUnit - Minimum Policed Unit value [m]
48      * @param maximumPacketSize - Maximum Packet Size value [M]
49      * @param rate - Rate value [R]
50      * @param slackTerm - Slack Term value [S]
51      */
52     public DOCSISFlowSpecTrafficProfile(final int tokenBucketRate,
53                                         final int tokenBucketSize,
54                                         final int peakDataRate,
55                                         final int minimumPolicedUnit,
56                                         final int maximumPacketSize,
57                                         final int rate,
58                                         final int slackTerm ) {
59         this(DEFAULT_ENVELOP, tokenBucketRate, tokenBucketSize, peakDataRate,
60              minimumPolicedUnit, maximumPacketSize, rate, slackTerm);
61     }
62
63     /**
64      * Constructor to set all values
65      * @param envelope - the envelope value
66      * @param tokenBucketRate - Token Bucket Rate value [r]
67      * @param tokenBucketSize - Token Bucket Size value [b]
68      * @param peakDataRate - Peak Data Rate value [p]
69      * @param minimumPolicedUnit - Minimum Policed Unit value [m]
70      * @param maximumPacketSize - Maximum Packet Size value [M]
71      * @param rate - Rate value [R]
72      * @param slackTerm - Slack Term value [S]
73      */
74     protected DOCSISFlowSpecTrafficProfile(final byte envelope,
75                                            final int tokenBucketRate,
76                                            final int tokenBucketSize,
77                                            final int peakDataRate,
78                                            final int minimumPolicedUnit,
79                                            final int maximumPacketSize,
80                                            final int rate,
81                                            final int slackTerm) {
82         super(SNum.TRAFFIC_PROFILE, STYPE);
83         this.tokenBucketRate = tokenBucketRate;
84         this.tokenBucketSize = tokenBucketSize;
85         this.peakDataRate = peakDataRate;
86         this.minimumPolicedUnit = minimumPolicedUnit;
87         this.maximumPacketSize = maximumPacketSize;
88         this.rate = rate;
89         this.slackTerm = slackTerm;
90         this.envelope = envelope;
91     }
92
93     @Override
94     public byte getEnvelop() {
95         return envelope;
96     }
97
98     /**
99      * Returns the token bucket rate value
100      * @return - the token bucket rate value
101      */
102     public int getTokenBucketRate() {
103         return tokenBucketRate;
104     }
105
106     /**
107      * Returns the token bucket size value
108      * @return - the token bucket size value
109      */
110     public int getTokenBucketSize() {
111         return tokenBucketSize;
112     }
113
114     /**
115      * Returns the peak data rate value
116      * @return - the peak data rate value
117      */
118     public int getPeakDataRate() {
119         return peakDataRate;
120     }
121
122     /**
123      * Returns the minimum policed unit value
124      * @return - the minimum policed unit value
125      */
126     public int getMinimumPolicedUnit() {
127         return minimumPolicedUnit;
128     }
129
130     /**
131      * Returns the maximum packet size value
132      * @return - the maximum packet size value
133      */
134     public int getMaximumPacketSize() {
135         return maximumPacketSize;
136     }
137
138     /**
139      * Returns the rate value
140      * @return - the rate value
141      */
142     public int getRate() {
143         return rate;
144     }
145
146     /**
147      * Returns the slack term value
148      * @return - the slack term value
149      */
150     public int getSlackTerm() {
151         return slackTerm;
152     }
153
154     @Override
155     protected byte[] getBytes() {
156         final byte[] data = new byte[4+(4*7*3)];
157         
158         float fTokenBucketRate = tokenBucketRate;
159         float fTokenBucketSize = tokenBucketSize;
160         float fPeakDataRate = peakDataRate;
161         float fRate = rate;
162
163         //
164         // Ok I know this looks crazy but PCMM Flow Spec encodes some values as floats
165         // even though they do not contain fractional values, so we 'integerize' them
166         // in the constructor and class internals
167         //
168         Arrays.fill(data, (byte) 0);
169         data[0] = envelope;
170         data[1] = SERVICE_NUMBER;
171         data[2] = 0; // reserved
172         data[3] = 0; // reserved
173         
174         // Authorized Envelope
175         System.arraycopy(ByteBuffer.allocate(4).putFloat(fTokenBucketRate).array(), 0, data, 4, 4);
176         System.arraycopy(ByteBuffer.allocate(4).putFloat(fTokenBucketSize).array(), 0, data, 8, 4);
177         System.arraycopy(ByteBuffer.allocate(4).putFloat(fPeakDataRate).array(), 0, data, 12, 4);
178         System.arraycopy(ByteBuffer.allocate(4).putInt(minimumPolicedUnit).array(), 0, data, 16, 4);
179         System.arraycopy(ByteBuffer.allocate(4).putInt(maximumPacketSize).array(), 0, data, 20, 4);
180         System.arraycopy(ByteBuffer.allocate(4).putFloat(fRate).array(), 0, data, 24, 4);
181         System.arraycopy(ByteBuffer.allocate(4).putInt(slackTerm).array(), 0, data, 28, 4);
182         
183         // Reserved Envelope
184         System.arraycopy(ByteBuffer.allocate(4).putFloat(fTokenBucketRate).array(), 0, data, 32, 4);
185         System.arraycopy(ByteBuffer.allocate(4).putFloat(fTokenBucketSize).array(), 0, data, 36, 4);
186         System.arraycopy(ByteBuffer.allocate(4).putFloat(fPeakDataRate).array(), 0, data, 40, 4);
187         System.arraycopy(ByteBuffer.allocate(4).putInt(minimumPolicedUnit).array(), 0, data, 44, 4);
188         System.arraycopy(ByteBuffer.allocate(4).putInt(maximumPacketSize).array(), 0, data, 48, 4);
189         System.arraycopy(ByteBuffer.allocate(4).putFloat(fRate).array(), 0, data, 52, 4);
190         System.arraycopy(ByteBuffer.allocate(4).putInt(slackTerm).array(), 0, data, 56, 4);
191         
192         // Committed Envelope
193         System.arraycopy(ByteBuffer.allocate(4).putFloat(fTokenBucketRate).array(), 0, data, 60, 4);
194         System.arraycopy(ByteBuffer.allocate(4).putFloat(fTokenBucketSize).array(), 0, data, 64, 4);
195         System.arraycopy(ByteBuffer.allocate(4).putFloat(fPeakDataRate).array(), 0, data, 68, 4);
196         System.arraycopy(ByteBuffer.allocate(4).putInt(minimumPolicedUnit).array(), 0, data, 72, 4);
197         System.arraycopy(ByteBuffer.allocate(4).putInt(maximumPacketSize).array(), 0, data, 76, 4);
198         System.arraycopy(ByteBuffer.allocate(4).putFloat(fRate).array(), 0, data, 80, 4);
199         System.arraycopy(ByteBuffer.allocate(4).putInt(slackTerm).array(), 0, data, 84, 4);
200         return data;
201     }
202
203     @Override
204     public boolean equals(final Object o) {
205         if (this == o) {
206             return true;
207         }
208         if (!(o instanceof DOCSISFlowSpecTrafficProfile)) {
209             return false;
210         }
211         if (!super.equals(o)) {
212             return false;
213         }
214         final DOCSISFlowSpecTrafficProfile that = (DOCSISFlowSpecTrafficProfile) o;
215         return (envelope == that.envelope) &&
216             (tokenBucketRate == that.tokenBucketRate) &&
217             (tokenBucketSize == that.tokenBucketSize) &&
218             (peakDataRate == that.peakDataRate) &&
219             (minimumPolicedUnit == that.minimumPolicedUnit) &&
220             (maximumPacketSize == that.maximumPacketSize) &&
221             (rate == that.rate) &&
222             (slackTerm == that.slackTerm);
223     }
224
225     @Override
226     public int hashCode() {
227         int result = super.hashCode();
228         result = 31 * result + tokenBucketRate;
229         result = 31 * result + tokenBucketSize;
230         result = 31 * result + peakDataRate;
231         result = 31 * result + minimumPolicedUnit;
232         result = 31 * result + maximumPacketSize;
233         result = 31 * result + rate;
234         result = 31 * result + slackTerm;        
235         result = 31 * result + (int) envelope;
236         return result;
237     }
238
239     private static int byteToInt(final byte[] data, int start) {
240         return (int)(data[start]   << 24 |
241                      data[start+1] << 16 |
242                      data[start+2] << 8  |
243                      data[start+3]);
244     }
245
246     private static float byteToFloat(final byte[] data, int start) {
247         return (float)(data[start]   << 24 |
248                        data[start+1] << 16 |
249                        data[start+2] << 8  |
250                        data[start+3]);
251     }
252     
253     /**
254      * Returns a DOCSISFlowSpecTrafficProfile object from a byte array
255      * @param data - the data to parse
256      * @return - the object
257      * TODO - make me more robust as RuntimeExceptions can be thrown here.
258      */
259     public static DOCSISFlowSpecTrafficProfile parse(final byte[] data) {
260         byte env = 0;
261         int mpu=0,mps=0,st=0;
262         float tbr=0,tbs=0,pdr=0,r=0;
263
264         env = data[0];
265
266         tbr = byteToFloat(data, 4);
267         tbs = byteToFloat(data, 8);
268         pdr = byteToFloat(data, 12);
269         mpu = byteToInt(data, 16);
270         mps = byteToInt(data, 20);
271         r   = byteToFloat(data, 24);
272         st  = byteToInt(data, 28);
273         //
274         // Ok I know this looks crazy but PCMM Flow Spec encodes some values as floats
275         // even though they do not contain fractional values, so we 'integerize' them
276         // in the constructor and class internals
277         //
278         int itbr = Math.round(tbr), itbs = Math.round(tbs),
279             ipdr = Math.round(pdr), ir = Math.round(r);
280         
281         return new DOCSISFlowSpecTrafficProfile(env, itbr, itbs, ipdr,
282                                                 mpu, mps, ir, st);
283     }
284
285   /**
286    * {@inheritDoc}
287    */
288   public String toString() {
289     final int sbSize = 1000;
290     final String variableSeparator = "\n";
291     final StringBuffer sb = new StringBuffer(sbSize);
292
293     sb.append("Envelope: ").append(envelope);
294     sb.append(variableSeparator);
295     sb.append("TokenBucketRate: ").append(tokenBucketRate);
296     sb.append(variableSeparator);
297     sb.append("TokenBucketSize: ").append(tokenBucketSize);
298     sb.append(variableSeparator);
299     sb.append("PeakDataRate: ").append(peakDataRate);
300     sb.append(variableSeparator);
301     sb.append("MinimumPolicedUnit: ").append(minimumPolicedUnit);
302     sb.append(variableSeparator);
303     sb.append("MaximumPacketSize: ").append(maximumPacketSize);
304     sb.append(variableSeparator);
305     sb.append("Rate: ").append(rate);
306     sb.append(variableSeparator);
307     sb.append("SlackTerm: ").append(slackTerm);
308
309     return sb.toString();
310   }
311 }