fix some deprecated warnings
[transportpce.git] / pce / src / main / java / org / opendaylight / transportpce / pce / gnpy / GnpyResult.java
1 /*
2  * Copyright © 2018 Orange, 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
9 package org.opendaylight.transportpce.pce.gnpy;
10
11 import com.google.common.base.Preconditions;
12 import com.google.gson.stream.JsonReader;
13
14 import java.io.ByteArrayInputStream;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.InputStreamReader;
18 import java.math.BigDecimal;
19 import java.nio.charset.StandardCharsets;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Optional;
24
25 import javassist.ClassPool;
26
27 import javax.annotation.Nonnull;
28
29 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
30 import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
31 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
32 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
33 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
34 import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
35 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
36 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.Result;
37 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type.num.unnum.hop.NumUnnumHop;
38 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.properties.path.properties.PathMetric;
39 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.properties.path.properties.PathRouteObjects;
40 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.Response;
41 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.response.response.type.NoPathCase;
42 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.response.response.type.PathCase;
43 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.General;
44 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.GeneralBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.Include;
46 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.IncludeBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.include_.OrderedHops;
48 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.include_.OrderedHopsBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.HopType;
50 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.HopTypeBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.hop.type.hop.type.NodeBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraints;
53 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraintsBuilder;
54 import org.opendaylight.yangtools.yang.binding.DataObject;
55 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
56 import org.opendaylight.yangtools.yang.common.QName;
57 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
58 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
59 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
62 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
63 import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
64 import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
65 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
66 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
67 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 /**
73  * Class for analyzing the result sent by GNPy.
74  *
75  * @author Ahmed Triki ( ahmed.triki@orange.com )
76  *
77  */
78
79 public class GnpyResult {
80
81     private static final Logger LOG = LoggerFactory.getLogger(GnpyResult.class);
82     private Response response = null;
83
84     public GnpyResult(String gnpyResponseString) throws Exception {
85
86         // Create the schema context
87         final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
88         Iterable<? extends YangModuleInfo> moduleInfos;
89         moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(Result.class));
90         moduleContext.addModuleInfos(moduleInfos);
91         SchemaContext schemaContext = moduleContext.tryToCreateSchemaContext().get();
92
93         // Create the binding binding normalized node codec registry
94         BindingRuntimeContext bindingRuntimeContext = BindingRuntimeContext.create(moduleContext, schemaContext);
95         final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(
96                 StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())));
97         codecRegistry.onBindingRuntimeContextUpdated(bindingRuntimeContext);
98
99         // Create the data object
100         QName pathQname = QName.create("gnpy:path", "2019-05-02", "result");
101         LOG.debug("the Qname is {} / namesapce {} ; module {}; ", pathQname.toString(), pathQname.getNamespace(),
102                 pathQname.getModule());
103         YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname);
104         DataObject dataObject = null;
105         //Create the object response
106         //Create JsonReader from String
107         InputStream streamGnpyRespnse = new ByteArrayInputStream(gnpyResponseString.getBytes(StandardCharsets.UTF_8));
108         InputStreamReader gnpyResultReader = new InputStreamReader(streamGnpyRespnse);
109         JsonReader jsonReader = new JsonReader(gnpyResultReader);
110         Optional<NormalizedNode<? extends PathArgument, ?>> transformIntoNormalizedNode = parseInputJSON(jsonReader,
111                 Result.class);
112         NormalizedNode<? extends PathArgument, ?> normalizedNode = transformIntoNormalizedNode.get();
113         if (codecRegistry.fromNormalizedNode(yangId, normalizedNode) != null) {
114             LOG.debug("The key of the generated object",
115                     codecRegistry.fromNormalizedNode(yangId, normalizedNode).getKey());
116             dataObject = codecRegistry.fromNormalizedNode(yangId, normalizedNode).getValue();
117         } else {
118             LOG.warn("The codec registry from the normalized node is null!");
119         }
120         List<Response> responses = null;
121         responses = ((Result) dataObject).getResponse();
122         if (responses != null) {
123             LOG.info("The response id is {}; ", responses.get(0).getResponseId());
124         } else {
125             LOG.warn("The response is null!");
126         }
127         this.response = responses.get(0);
128         analyzeResult();
129     }
130
131     public boolean getPathFeasibility() {
132         boolean isFeasible = false;
133         if (response != null) {
134             if (response.getResponseType() instanceof NoPathCase) {
135                 isFeasible = false;
136                 LOG.info("The path is not feasible ");
137             } else if (response.getResponseType() instanceof PathCase) {
138                 isFeasible = true;
139                 LOG.info("The path is feasible ");
140             }
141         }
142         return isFeasible;
143     }
144
145     public void analyzeResult() {
146         if (response != null) {
147             Long responseId = response.getResponseId();
148             LOG.info("Response-Id {}", responseId);
149             if (response.getResponseType() instanceof NoPathCase) {
150                 NoPathCase noPathCase = (NoPathCase) response.getResponseType();
151                 String noPathType = noPathCase.getNoPath().getNoPath();
152                 LOG.info("GNPy: No path - {}",noPathType);
153                 if (((noPathType.equals("NO_FEASIBLE_BAUDRATE_WITH_SPACING"))
154                         && (noPathType.equals("NO_FEASIBLE_MODE"))) && ((noPathType.equals("MODE_NOT_FEASIBLE"))
155                         && (noPathType.equals("NO_SPECTRUM")))) {
156                     List<PathMetric> pathMetricList = noPathCase.getNoPath().getPathProperties().getPathMetric();
157                     LOG.info("GNPy : path is not feasible : {}", noPathType);
158                     for (PathMetric pathMetric : pathMetricList) {
159                         String metricType = pathMetric.getMetricType().getSimpleName();
160                         BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
161                         LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
162                     }
163                 }
164             } else if (response.getResponseType() instanceof PathCase) {
165                 LOG.info("GNPy : path is feasible");
166                 PathCase pathCase = (PathCase) response.getResponseType();
167                 List<PathMetric> pathMetricList = pathCase.getPathProperties().getPathMetric();
168                 for (PathMetric pathMetric : pathMetricList) {
169                     String metricType = pathMetric.getMetricType().getSimpleName();
170                     BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
171                     LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
172                 }
173             }
174         }
175     }
176
177     public HardConstraints analyzeGnpyPath() {
178         HardConstraints hardConstraints = null;
179         if (response != null) {
180             Long responseId = response.getResponseId();
181             LOG.info("Response-Id {}", responseId);
182             if (response.getResponseType() instanceof NoPathCase) {
183                 NoPathCase noPathCase = (NoPathCase) response.getResponseType();
184                 LOG.info("No path feasible {}", noPathCase.toString());
185             } else if (response.getResponseType() instanceof PathCase) {
186                 PathCase pathCase = (PathCase) response.getResponseType();
187                 List<PathMetric> pathMetricList = pathCase.getPathProperties().getPathMetric();
188                 for (PathMetric pathMetric : pathMetricList) {
189                     String metricType = pathMetric.getMetricType().getSimpleName();
190                     BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
191                     LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
192                 }
193
194                 // Includes the list of nodes in the GNPy computed path as constraints for the PCE
195                 List<OrderedHops> orderedHopsList = null;
196                 List<PathRouteObjects> pathRouteObjectList = pathCase.getPathProperties().getPathRouteObjects();
197                 int counter = 0;
198                 for (PathRouteObjects pathRouteObjects : pathRouteObjectList) {
199                     if (pathRouteObjects.getPathRouteObject().getType() instanceof NumUnnumHop) {
200                         NumUnnumHop numUnnumHop = (NumUnnumHop) pathRouteObjects.getPathRouteObject().getType();
201                         String nodeId = numUnnumHop.getNodeId();
202                         org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017
203                                 .ordered.constraints.sp.hop.type.hop.type.Node node = new NodeBuilder()
204                                 .setNodeId(nodeId).build();
205                         HopType hopType = new HopTypeBuilder().setHopType(node).build();
206                         OrderedHops orderedHops = new OrderedHopsBuilder().setHopNumber(counter).setHopType(hopType)
207                                 .build();
208                         LOG.info("- gnpyResult class : Hard Constraint: {} // - Hop Node {}", counter, nodeId);
209                         orderedHopsList.add(orderedHops);
210                         counter++;
211                     }
212                 }
213                 Include include = new IncludeBuilder().setOrderedHops(orderedHopsList).build();
214                 General general = new GeneralBuilder().setInclude(include).build();
215                 hardConstraints = new HardConstraintsBuilder().setCoRoutingOrGeneral(general).build();
216             }
217         }
218         return hardConstraints;
219     }
220
221     /**
222      * Parses the input json with concrete implementation of
223      * {@link JsonParserStream}.
224      *
225      * @param reader
226      *            of the given JSON
227      * @throws Exception
228      *
229      */
230     private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputJSON(JsonReader reader,
231             Class<? extends DataObject> objectClass) throws Exception {
232         NormalizedNodeResult result = new NormalizedNodeResult();
233         SchemaContext schemaContext = getSchemaContext(objectClass);
234         try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
235                 JsonParserStream jsonParser = JsonParserStream.create(streamWriter,
236                     JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(schemaContext),
237                     schemaContext);) {
238             LOG.debug("GNPy: the path to the reader {}", reader.getPath());
239             LOG.debug("GNPy: the reader {}", reader.toString());
240             LOG.debug("GNPy: the jsonParser class {} // jsonParser to string {}", jsonParser.getClass(),
241                     jsonParser.toString());
242             jsonParser.parse(reader);
243         } catch (IOException e) {
244             LOG.warn("GNPy: exception {} occured during parsing Json input stream", e.getMessage());
245             return Optional.empty();
246         }
247         return Optional.ofNullable(result.getResult());
248     }
249
250     private SchemaContext getSchemaContext(Class<? extends DataObject> objectClass) throws Exception {
251         final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
252         Iterable<? extends YangModuleInfo> moduleInfos;
253         SchemaContext schemaContext = null;
254         moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(objectClass));
255         moduleContext.addModuleInfos(moduleInfos);
256         schemaContext = moduleContext.tryToCreateSchemaContext().get();
257         return schemaContext;
258     }
259
260     /**
261      * Transforms the given input {@link NormalizedNode} into the given
262      * {@link DataObject}.
263      *
264      * @param normalizedNode
265      *            normalized node you want to convert
266      * @param rootNode
267      *            {@link QName} of converted normalized node root
268      *
269      *            <p>
270      *            The input object should be {@link ContainerNode}
271      *            </p>
272      */
273     public <T extends DataObject> Optional<T> getDataObject(@Nonnull NormalizedNode<?, ?> normalizedNode,
274             @Nonnull QName rootNode, BindingNormalizedNodeSerializer codecRegistry) {
275         if (normalizedNode != null) {
276             LOG.debug("GNPy: The codecRegistry is ", codecRegistry.toString());
277         } else {
278             LOG.warn("GNPy: The codecRegistry is null");
279         }
280         Preconditions.checkNotNull(normalizedNode);
281         if (normalizedNode instanceof ContainerNode) {
282             YangInstanceIdentifier.PathArgument directChildIdentifier = YangInstanceIdentifier.of(rootNode)
283                     .getLastPathArgument();
284             Optional<NormalizedNode<?, ?>> directChild = NormalizedNodes.getDirectChild(normalizedNode,
285                     directChildIdentifier);
286             if (!directChild.isPresent()) {
287                 throw new IllegalStateException(String.format("Could not get the direct child of %s", rootNode));
288             }
289             normalizedNode = directChild.get();
290             LOG.debug("GNPy: the normalized node is ", normalizedNode.getNodeType());
291         }
292         YangInstanceIdentifier rootNodeYangInstanceIdentifier = YangInstanceIdentifier.of(rootNode);
293         LOG.debug("GNPy: the root Node Yang Instance Identifier is ", rootNodeYangInstanceIdentifier.toString());
294         Map.Entry<?, ?> bindingNodeEntry = codecRegistry.fromNormalizedNode(rootNodeYangInstanceIdentifier,
295                 normalizedNode);
296         if (bindingNodeEntry == null) {
297             LOG.debug("The binding Node Entry is null");
298             return Optional.empty();
299         }
300         return Optional.ofNullable((T) bindingNodeEntry.getValue());
301     }
302
303     public Response getResponse() {
304         return response;
305     }
306 }