2 * Copyright © 2018 Orange, Inc. and others. All rights reserved.
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
9 package org.opendaylight.transportpce.pce.gnpy;
11 import com.google.common.base.Preconditions;
12 import com.google.gson.stream.JsonReader;
14 import java.io.BufferedReader;
15 import java.io.ByteArrayInputStream;
16 import java.io.FileReader;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.math.BigDecimal;
21 import java.nio.charset.StandardCharsets;
22 import java.util.Collections;
23 import java.util.List;
25 import java.util.Optional;
27 import javassist.ClassPool;
29 import javax.annotation.Nonnull;
31 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
32 import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
33 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
34 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
35 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
36 import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
37 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
38 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.Result;
39 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type.num.unnum.hop.NumUnnumHop;
40 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.properties.path.properties.PathMetric;
41 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.properties.path.properties.PathRouteObjects;
42 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.Response;
43 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.response.response.type.NoPathCase;
44 import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.response.response.type.PathCase;
45 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.General;
46 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.GeneralBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.Include;
48 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.IncludeBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.include_.OrderedHops;
50 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.include_.OrderedHopsBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.HopType;
52 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.HopTypeBuilder;
53 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.hop.type.hop.type.NodeBuilder;
54 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraints;
55 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraintsBuilder;
56 import org.opendaylight.yangtools.yang.binding.DataObject;
57 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
58 import org.opendaylight.yangtools.yang.common.QName;
59 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
60 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
61 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
63 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
64 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
65 import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
66 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
67 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
68 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
74 * Class for analyzing the result sent by GNPy.
76 * @author Ahmed Triki ( ahmed.triki@orange.com )
80 public class GnpyResult {
82 private static final Logger LOG = LoggerFactory.getLogger(GnpyResult.class);
83 private Response response = null;
85 public GnpyResult(String gnpyResponseString) throws Exception {
88 // Optional<DataObject> dataObject;
89 // Create the schema context
90 final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
91 Iterable<? extends YangModuleInfo> moduleInfos;
92 moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(Result.class));
93 moduleContext.addModuleInfos(moduleInfos);
94 SchemaContext schemaContext = moduleContext.tryToCreateSchemaContext().get();
96 // Create the binding binding normalized node codec registry
97 BindingRuntimeContext bindingRuntimeContext = BindingRuntimeContext.create(moduleContext, schemaContext);
98 final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(
99 StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())));
100 codecRegistry.onBindingRuntimeContextUpdated(bindingRuntimeContext);
102 // Create the data object
103 QName pathQname = QName.create("gnpy:path", "2019-05-02", "result");
104 LOG.debug("the Qname is {} / namesapce {} ; module {}; ", pathQname.toString(), pathQname.getNamespace(),
105 pathQname.getModule());
106 YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname);
107 DataObject dataObject = null;
108 //Create the object response
109 //Create JsonReader from String
110 InputStream streamGnpyRespnse = new ByteArrayInputStream(gnpyResponseString.getBytes(StandardCharsets.UTF_8));
111 InputStreamReader gnpyResultReader = new InputStreamReader(streamGnpyRespnse);
112 JsonReader jsonReader = new JsonReader(gnpyResultReader);
113 Optional<NormalizedNode<? extends PathArgument, ?>> transformIntoNormalizedNode = parseInputJSON(jsonReader,
115 NormalizedNode<? extends PathArgument, ?> normalizedNode = transformIntoNormalizedNode.get();
116 if (codecRegistry.fromNormalizedNode(yangId, normalizedNode) != null) {
117 LOG.debug("The key of the generated object",
118 codecRegistry.fromNormalizedNode(yangId, normalizedNode).getKey());
119 dataObject = codecRegistry.fromNormalizedNode(yangId, normalizedNode).getValue();
121 LOG.warn("The codec registry from the normalized node is null!");
123 List<Response> responses = null;
124 responses = ((Result) dataObject).getResponse();
125 if (responses != null) {
126 LOG.info("The response id is {}; ", responses.get(0).getResponseId());
128 LOG.warn("The response is null!");
130 this.response = responses.get(0);
134 public boolean getPathFeasibility() {
135 boolean isFeasible = false;
136 if (response != null) {
137 if (response.getResponseType() instanceof NoPathCase) {
139 LOG.info("The path is not feasible ");
140 } else if (response.getResponseType() instanceof PathCase) {
142 LOG.info("The path is feasible ");
148 public void analyzeResult() {
149 if (response != null) {
150 Long responseId = response.getResponseId();
151 LOG.info("Response-Id {}", responseId);
152 if (response.getResponseType() instanceof NoPathCase) {
153 NoPathCase noPathCase = (NoPathCase) response.getResponseType();
154 String noPathType = noPathCase.getNoPath().getNoPath();
155 LOG.info("GNPy: No path - {}",noPathType);
156 if (((noPathType == "NO_FEASIBLE_BAUDRATE_WITH_SPACING") && (noPathType == "NO_FEASIBLE_MODE"))
157 && ((noPathType == "MODE_NOT_FEASIBLE") && (noPathType == "NO_SPECTRUM"))) {
158 List<PathMetric> pathMetricList = noPathCase.getNoPath().getPathProperties().getPathMetric();
159 LOG.info("GNPy : path is not feasible : {}", noPathType);
160 for (PathMetric pathMetric : pathMetricList) {
161 String metricType = pathMetric.getMetricType().getSimpleName();
162 BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
163 LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
166 } else if (response.getResponseType() instanceof PathCase) {
167 LOG.info("GNPy : path is feasible");
168 PathCase pathCase = (PathCase) response.getResponseType();
169 List<PathMetric> pathMetricList = pathCase.getPathProperties().getPathMetric();
170 for (PathMetric pathMetric : pathMetricList) {
171 String metricType = pathMetric.getMetricType().getSimpleName();
172 BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
173 LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
179 public HardConstraints analyzeGnpyPath() {
180 HardConstraints hardConstraints = null;
181 if (response != null) {
182 Long responseId = response.getResponseId();
183 LOG.info("Response-Id {}", responseId);
184 if (response.getResponseType() instanceof NoPathCase) {
185 NoPathCase noPathCase = (NoPathCase) response.getResponseType();
186 LOG.info("No path feasible {}", noPathCase.toString());
187 } else if (response.getResponseType() instanceof PathCase) {
188 PathCase pathCase = (PathCase) response.getResponseType();
189 List<PathMetric> pathMetricList = pathCase.getPathProperties().getPathMetric();
190 for (PathMetric pathMetric : pathMetricList) {
191 String metricType = pathMetric.getMetricType().getSimpleName();
192 BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
193 LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
196 // Includes the list of nodes in the GNPy computed path as constraints for the PCE
197 List<OrderedHops> orderedHopsList = null;
198 List<PathRouteObjects> pathRouteObjectList = pathCase.getPathProperties().getPathRouteObjects();
200 for (PathRouteObjects pathRouteObjects : pathRouteObjectList) {
201 if (pathRouteObjects.getPathRouteObject().getType() instanceof NumUnnumHop) {
202 NumUnnumHop numUnnumHop = (NumUnnumHop) pathRouteObjects.getPathRouteObject().getType();
203 String nodeId = numUnnumHop.getNodeId();
204 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017
205 .ordered.constraints.sp.hop.type.hop.type.Node node = new NodeBuilder()
206 .setNodeId(nodeId).build();
207 HopType hopType = new HopTypeBuilder().setHopType(node).build();
208 OrderedHops orderedHops = new OrderedHopsBuilder().setHopNumber(counter).setHopType(hopType)
210 LOG.info("- gnpyResult class : Hard Constraint: {} // - Hop Node {}", counter, nodeId);
211 orderedHopsList.add(orderedHops);
215 Include include = new IncludeBuilder().setOrderedHops(orderedHopsList).build();
216 General general = new GeneralBuilder().setInclude(include).build();
217 hardConstraints = new HardConstraintsBuilder().setCoRoutingOrGeneral(general).build();
220 return hardConstraints;
224 * Parses the input json with concrete implementation of
225 * {@link JsonParserStream}.
232 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputJSON(JsonReader reader,
233 Class<? extends DataObject> objectClass) throws Exception {
234 NormalizedNodeResult result = new NormalizedNodeResult();
235 SchemaContext schemaContext = getSchemaContext(objectClass);
236 try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
237 JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext, 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();
247 return Optional.ofNullable(result.getResult());
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;
260 private String readResultFromFile(String fileName) {
261 BufferedReader br = null;
262 FileReader fr = null;
263 StringBuilder sb = new StringBuilder();
267 fr = new FileReader(fileName);
268 br = new BufferedReader(fr);
270 while ((currentLine = br.readLine()) != null) {
271 LOG.info(currentLine);
272 sb.append(currentLine);
275 } catch (IOException e) {
276 LOG.warn("GNPy: exception {} occured during the reading of results", e.getMessage());
278 gnpyResponse = sb.toString();
283 * Transforms the given input {@link NormalizedNode} into the given
284 * {@link DataObject}.
286 * @param normalizedNode
287 * normalized node you want to convert
289 * {@link QName} of converted normalized node root
292 * The input object should be {@link ContainerNode}
295 public <T extends DataObject> Optional<T> getDataObject(@Nonnull NormalizedNode<?, ?> normalizedNode,
296 @Nonnull QName rootNode, BindingNormalizedNodeSerializer codecRegistry) {
297 if (normalizedNode != null) {
298 LOG.debug("GNPy: The codecRegistry is ", codecRegistry.toString());
300 LOG.warn("GNPy: The codecRegistry is null");
302 Preconditions.checkNotNull(normalizedNode);
303 if (normalizedNode instanceof ContainerNode) {
304 YangInstanceIdentifier.PathArgument directChildIdentifier = YangInstanceIdentifier.of(rootNode)
305 .getLastPathArgument();
306 Optional<NormalizedNode<?, ?>> directChild = NormalizedNodes.getDirectChild(normalizedNode,
307 directChildIdentifier);
308 if (!directChild.isPresent()) {
309 throw new IllegalStateException(String.format("Could not get the direct child of %s", rootNode));
311 normalizedNode = directChild.get();
312 LOG.debug("GNPy: the normalized node is ", normalizedNode.getNodeType());
314 YangInstanceIdentifier rootNodeYangInstanceIdentifier = YangInstanceIdentifier.of(rootNode);
315 LOG.debug("GNPy: the root Node Yang Instance Identifier is ", rootNodeYangInstanceIdentifier.toString());
316 Map.Entry<?, ?> bindingNodeEntry = codecRegistry.fromNormalizedNode(rootNodeYangInstanceIdentifier,
318 if (bindingNodeEntry == null) {
319 LOG.debug("The binding Node Entry is null");
320 return Optional.empty();
322 return Optional.ofNullable((T) bindingNodeEntry.getValue());