Revert "BUG-47 : unfinished PCEP migration to generated DTOs."
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / object / PCEPMetricObjectParser.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  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 package org.opendaylight.protocol.pcep.impl.object;
9
10 import java.util.BitSet;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.NoSuchElementException;
14
15 import org.opendaylight.protocol.concepts.AbstractMetric;
16 import org.opendaylight.protocol.concepts.IGPMetric;
17 import org.opendaylight.protocol.concepts.TEMetric;
18 import org.opendaylight.protocol.pcep.PCEPDeserializerException;
19 import org.opendaylight.protocol.pcep.PCEPObject;
20 import org.opendaylight.protocol.pcep.concepts.AggregateBandwidthConsumptionMetric;
21 import org.opendaylight.protocol.pcep.concepts.CumulativeIGPCostMetric;
22 import org.opendaylight.protocol.pcep.concepts.CumulativeTECostMetric;
23 import org.opendaylight.protocol.pcep.concepts.MostLoadedLinkLoadMetric;
24 import org.opendaylight.protocol.pcep.concepts.P2MPHopCountMetric;
25 import org.opendaylight.protocol.pcep.concepts.P2MPIGPMetric;
26 import org.opendaylight.protocol.pcep.concepts.P2MPTEMetric;
27 import org.opendaylight.protocol.pcep.impl.PCEPObjectParser;
28 import org.opendaylight.protocol.pcep.object.PCEPMetricObject;
29 import org.opendaylight.protocol.util.ByteArray;
30
31 /**
32  * Parser for {@link org.opendaylight.protocol.pcep.object.PCEPMetricObject
33  * PCEPMetricObject}
34  */
35 public class PCEPMetricObjectParser implements PCEPObjectParser {
36
37         /*
38          * lengths of fields in bytes
39          */
40         private static final int FLAGS_F_LENGTH = 1;
41         private static final int TYPE_F_LENGTH = 1;
42         private static final int METRIC_VALUE_F_LENGTH = 4;
43
44         /*
45          * offsets of fields in bytes
46          */
47         public static final int FLAGS_F_OFFSET = 2;
48         public static final int TYPE_F_OFFSET = FLAGS_F_OFFSET + FLAGS_F_LENGTH;
49         public static final int METRIC_VALUE_F_OFFSET = TYPE_F_OFFSET + TYPE_F_LENGTH;
50
51         /*
52          * flags offsets inside flags field in bits
53          */
54         private static final int C_FLAG_OFFSET = 6;
55         private static final int B_FLAG_OFFSET = 7;
56
57         public static final int SIZE = METRIC_VALUE_F_OFFSET + METRIC_VALUE_F_LENGTH;
58
59         /**
60          * Bidirectional mapping for metrics. Maps metric class to integer and
61          * integer to metrics instantiable.
62          */
63         public static class PCEPMetricsMapping {
64                 private static final PCEPMetricsMapping instance = new PCEPMetricsMapping();
65
66                 private final Map<Class<?>, Integer> metricsMap = new HashMap<Class<?>, Integer>();
67                 private final Map<Integer, InstantiableMetric> metrictTypesMap = new HashMap<Integer, InstantiableMetric>();
68
69                 private interface InstantiableMetric {
70                         public AbstractMetric<?> getMetric(long metric);
71                 }
72
73                 private PCEPMetricsMapping() {
74                         this.fillIn();
75                 }
76
77                 private void fillIn() {
78                         this.fillIn(1, IGPMetric.class, new InstantiableMetric() {
79
80                                 @Override
81                                 public AbstractMetric<?> getMetric(long metric) {
82                                         return new IGPMetric(metric);
83                                 }
84
85                         });
86                         this.fillIn(2, TEMetric.class, new InstantiableMetric() {
87
88                                 @Override
89                                 public AbstractMetric<?> getMetric(long metric) {
90                                         return new TEMetric(metric);
91                                 }
92
93                         });
94                         this.fillIn(4, AggregateBandwidthConsumptionMetric.class, new InstantiableMetric() {
95
96                                 @Override
97                                 public AbstractMetric<?> getMetric(long metric) {
98                                         return new AggregateBandwidthConsumptionMetric(metric);
99                                 }
100
101                         });
102                         this.fillIn(5, MostLoadedLinkLoadMetric.class, new InstantiableMetric() {
103
104                                 @Override
105                                 public AbstractMetric<?> getMetric(long metric) {
106                                         return new MostLoadedLinkLoadMetric(metric);
107                                 }
108
109                         });
110                         this.fillIn(6, CumulativeIGPCostMetric.class, new InstantiableMetric() {
111
112                                 @Override
113                                 public AbstractMetric<?> getMetric(long metric) {
114                                         return new CumulativeIGPCostMetric(metric);
115                                 }
116
117                         });
118                         this.fillIn(7, CumulativeTECostMetric.class, new InstantiableMetric() {
119
120                                 @Override
121                                 public AbstractMetric<?> getMetric(long metric) {
122                                         return new CumulativeTECostMetric(metric);
123                                 }
124
125                         });
126                         this.fillIn(8, P2MPIGPMetric.class, new InstantiableMetric() {
127
128                                 @Override
129                                 public AbstractMetric<?> getMetric(long metric) {
130                                         return new P2MPIGPMetric(metric);
131                                 }
132
133                         });
134                         this.fillIn(9, P2MPTEMetric.class, new InstantiableMetric() {
135
136                                 @Override
137                                 public AbstractMetric<?> getMetric(long metric) {
138                                         return new P2MPHopCountMetric(metric);
139                                 }
140
141                         });
142                         this.fillIn(10, P2MPHopCountMetric.class, new InstantiableMetric() {
143
144                                 @Override
145                                 public AbstractMetric<?> getMetric(long metric) {
146                                         return new P2MPHopCountMetric(metric);
147                                 }
148
149                         });
150                 }
151
152                 private void fillIn(int type, Class<?> metricClazz, InstantiableMetric instantiable) {
153                         this.metricsMap.put(metricClazz, type);
154                         this.metrictTypesMap.put(type, instantiable);
155                 }
156
157                 public int getFromMetricClass(Class<? extends AbstractMetric<?>> clazz) {
158                         final Integer mi = this.metricsMap.get(clazz);
159                         if (mi == null)
160                                 throw new NoSuchElementException("Unknown Metric: " + clazz);
161                         return mi;
162                 }
163
164                 public AbstractMetric<?> getFromMetricTypeIdentifier(int identifier, long metric) {
165                         final InstantiableMetric e = this.metrictTypesMap.get(identifier);
166                         if (e == null)
167                                 throw new NoSuchElementException("Unknown metric type identifier. Passed: " + identifier);
168                         return e.getMetric(metric);
169                 }
170
171                 public static PCEPMetricsMapping getInstance() {
172                         return instance;
173                 }
174         }
175
176         @Override
177         public PCEPObject parse(byte[] bytes, boolean processed, boolean ignored) throws PCEPDeserializerException {
178                 if (bytes == null || bytes.length == 0)
179                         throw new IllegalArgumentException("Array of bytes is mandatory. Can't be null or empty.");
180
181                 if (bytes.length != SIZE)
182                         throw new PCEPDeserializerException("Wrong length of array of bytes. Passed: " + bytes.length + "; Expected: " + SIZE + ".");
183
184                 final byte[] flagBytes = { bytes[FLAGS_F_OFFSET] };
185                 final BitSet flags = ByteArray.bytesToBitSet(flagBytes);
186                 try {
187                         return new PCEPMetricObject(flags.get(B_FLAG_OFFSET), flags.get(C_FLAG_OFFSET), PCEPMetricsMapping.getInstance().getFromMetricTypeIdentifier(
188                                         (short) (bytes[TYPE_F_OFFSET] & 0xFF),
189                                         (long) ByteArray.bytesToFloat(ByteArray.subByte(bytes, METRIC_VALUE_F_OFFSET, METRIC_VALUE_F_LENGTH))), processed, ignored);
190                 } catch (final NoSuchElementException e) {
191                         throw new PCEPDeserializerException(e, "Metric object has unknown identifier.");
192                 }
193         }
194
195         @Override
196         public byte[] put(PCEPObject obj) {
197                 if (!(obj instanceof PCEPMetricObject))
198                         throw new IllegalArgumentException("Wrong instance of PCEPObject. Passed " + obj.getClass() + ". Needed PCEPMetricObject.");
199
200                 final PCEPMetricObject mObj = (PCEPMetricObject) obj;
201
202                 final byte[] retBytes = new byte[SIZE];
203                 final BitSet flags = new BitSet(FLAGS_F_LENGTH * Byte.SIZE);
204                 flags.set(C_FLAG_OFFSET, mObj.isComputedMetric());
205                 flags.set(B_FLAG_OFFSET, mObj.isBound());
206
207                 ByteArray.copyWhole(ByteArray.bitSetToBytes(flags, FLAGS_F_LENGTH), retBytes, FLAGS_F_OFFSET);
208
209                 final AbstractMetric<?> metric = mObj.getMetric();
210                 @SuppressWarnings("unchecked")
211                 final Class<? extends AbstractMetric<?>> metricClazz = (Class<? extends AbstractMetric<?>>) metric.getClass();
212                 retBytes[TYPE_F_OFFSET] = (byte) PCEPMetricsMapping.getInstance().getFromMetricClass(metricClazz);
213
214                 System.arraycopy(ByteArray.floatToBytes(mObj.getMetric().getValue()), 0, retBytes, METRIC_VALUE_F_OFFSET, METRIC_VALUE_F_LENGTH);
215
216                 return retBytes;
217         }
218
219 }