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.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.ArrayList;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
26 import java.util.Optional;
29 import javax.annotation.Nonnull;
31 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
32 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
33 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
34 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
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.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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
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.JSONCodecFactorySupplier;
66 import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
67 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
68 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
69 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
75 * Class for analyzing the result sent by GNPy.
77 * @author Ahmed Triki ( ahmed.triki@orange.com )
81 public class GnpyResult {
83 private static final Logger LOG = LoggerFactory.getLogger(GnpyResult.class);
84 private Response response = null;
85 private Map<String, IpAddress> mapNodeRefIp = new HashMap<String, IpAddress>();
86 //private Map<String, IpAddress> mapFiberIp = new HashMap<String, IpAddress>();
88 public GnpyResult(String gnpyResponseString, GnpyTopoImpl gnpyTopo) throws Exception {
90 this.mapNodeRefIp = gnpyTopo.getMapNodeRefIp();
91 // Create the schema context
92 final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
93 Iterable<? extends YangModuleInfo> moduleInfos;
94 moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(Result.class));
95 moduleContext.addModuleInfos(moduleInfos);
96 SchemaContext schemaContext = moduleContext.tryToCreateSchemaContext().get();
98 // Create the binding binding normalized node codec registry
99 BindingRuntimeContext bindingRuntimeContext = BindingRuntimeContext.create(moduleContext, schemaContext);
100 final BindingNormalizedNodeCodecRegistry codecRegistry =
101 new BindingNormalizedNodeCodecRegistry(bindingRuntimeContext);
103 // Create the data object
104 QName pathQname = QName.create("gnpy:path", "2019-05-02", "result");
105 LOG.debug("the Qname is {} / namesapce {} ; module {}; ", pathQname.toString(), pathQname.getNamespace(),
106 pathQname.getModule());
107 YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname);
108 DataObject dataObject = null;
109 // Create the object response
110 // Create JsonReader from String
111 InputStream streamGnpyRespnse = new ByteArrayInputStream(gnpyResponseString.getBytes(StandardCharsets.UTF_8));
112 InputStreamReader gnpyResultReader = new InputStreamReader(streamGnpyRespnse);
113 JsonReader jsonReader = new JsonReader(gnpyResultReader);
114 Optional<NormalizedNode<? extends PathArgument, ?>> transformIntoNormalizedNode = parseInputJSON(jsonReader,
116 NormalizedNode<? extends PathArgument, ?> normalizedNode = transformIntoNormalizedNode.get();
117 if (codecRegistry.fromNormalizedNode(yangId, normalizedNode) != null) {
118 dataObject = codecRegistry.fromNormalizedNode(yangId, normalizedNode).getValue();
120 LOG.warn("The codec registry from the normalized node is null!");
122 List<Response> responses = null;
123 responses = ((Result) dataObject).getResponse();
124 if (responses != null) {
125 LOG.info("The response id is {}; ", responses.get(0).getResponseId());
127 LOG.warn("The response is null!");
129 this.response = responses.get(0);
133 public boolean getPathFeasibility() {
134 boolean isFeasible = false;
135 if (response != null) {
136 if (response.getResponseType() instanceof NoPathCase) {
138 LOG.info("The path is not feasible ");
139 } else if (response.getResponseType() instanceof PathCase) {
141 LOG.info("The path is feasible ");
147 public List<PathRouteObjects> analyzeResult() {
148 List<PathRouteObjects> pathRouteObjectList = null;
149 if (response != null) {
150 if (response.getResponseType() instanceof NoPathCase) {
151 NoPathCase noPathCase = (NoPathCase) response.getResponseType();
152 String noPathType = noPathCase.getNoPath().getNoPath();
153 LOG.info("GNPy: No path - {}", noPathType);
154 if (((noPathType.equals("NO_FEASIBLE_BAUDRATE_WITH_SPACING"))
155 && (noPathType.equals("NO_FEASIBLE_MODE"))) && ((noPathType.equals("MODE_NOT_FEASIBLE"))
156 && (noPathType.equals("NO_SPECTRUM")))) {
157 List<PathMetric> pathMetricList = noPathCase.getNoPath().getPathProperties().getPathMetric();
158 LOG.info("GNPy : path is not feasible : {}", noPathType);
159 for (PathMetric pathMetric : pathMetricList) {
160 String metricType = pathMetric.getMetricType().getSimpleName();
161 BigDecimal accumulativeValue = pathMetric.getAccumulativeValue();
162 LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue);
165 } else if (response.getResponseType() instanceof PathCase) {
166 LOG.info("GNPy : path is feasible");
167 PathCase pathCase = (PathCase) response.getResponseType();
168 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);
175 // Path route objects
176 pathRouteObjectList = pathCase.getPathProperties().getPathRouteObjects();
177 LOG.info("in GnpyResult: finishing the computation of pathRouteObjectList");
180 return pathRouteObjectList;
183 public HardConstraints computeHardConstraintsFromGnpyPath(List<PathRouteObjects> pathRouteObjectList) {
184 HardConstraints hardConstraints = null;
185 // Includes the list of nodes in the GNPy computed path as constraints
187 List<OrderedHops> orderedHopsList = new ArrayList<>();
189 for (PathRouteObjects pathRouteObjects : pathRouteObjectList) {
190 if (pathRouteObjects.getPathRouteObject().getType() instanceof NumUnnumHop) {
191 NumUnnumHop numUnnumHop = (org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type
192 .NumUnnumHop) pathRouteObjects.getPathRouteObject().getType();
193 String nodeIp = numUnnumHop.getNumUnnumHop().getNodeId();
195 IpAddress nodeIpAddress = new IpAddress(new Ipv4Address(nodeIp));
196 // find the corresponding node-id (in ord-ntw) corresponding to nodeId (in gnpy response)
197 String nodeId = findOrdNetworkNodeId(nodeIpAddress);
198 if (nodeId != null) {
199 org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017
200 .ordered.constraints.sp.hop.type.hop.type.Node node = new NodeBuilder().setNodeId(nodeId)
202 HopType hopType = new HopTypeBuilder().setHopType(node).build();
203 OrderedHops orderedHops = new OrderedHopsBuilder().setHopNumber(counter).setHopType(hopType)
205 orderedHopsList.add(orderedHops);
208 } catch (IllegalArgumentException e) {
209 LOG.debug(" in GnpyResult: the element {} is not a ipv4Address ", nodeIp);
213 Include include = new IncludeBuilder().setOrderedHops(orderedHopsList).build();
214 General general = new GeneralBuilder().setInclude(include).build();
215 hardConstraints = new HardConstraintsBuilder().setCoRoutingOrGeneral(general).build();
216 return hardConstraints;
219 private String findOrdNetworkNodeId(IpAddress nodeIpAddress) {
221 Set<String> keySet = this.mapNodeRefIp.keySet();
222 Iterator<String> it = keySet.iterator();
223 while (it.hasNext()) {
225 if (this.mapNodeRefIp.get(nodeId).equals(nodeIpAddress)) {
233 * Parses the input json with concrete implementation of {@link JsonParserStream}.
234 * @param reader of the given JSON
235 * @throws Exception exception
237 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputJSON(JsonReader reader,
238 Class<? extends DataObject> objectClass) throws Exception {
239 NormalizedNodeResult result = new NormalizedNodeResult();
240 SchemaContext schemaContext = getSchemaContext(objectClass);
241 try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
242 JsonParserStream jsonParser = JsonParserStream.create(streamWriter,
243 JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(schemaContext),
245 jsonParser.parse(reader);
246 } catch (IOException e) {
247 LOG.warn("GNPy: exception {} occured during parsing Json input stream", e.getMessage());
248 return Optional.empty();
250 return Optional.ofNullable(result.getResult());
253 private SchemaContext getSchemaContext(Class<? extends DataObject> objectClass) throws Exception {
254 final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
255 Iterable<? extends YangModuleInfo> moduleInfos;
256 SchemaContext schemaContext = null;
257 moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(objectClass));
258 moduleContext.addModuleInfos(moduleInfos);
259 schemaContext = moduleContext.tryToCreateSchemaContext().get();
260 return schemaContext;
264 * Transforms the given input {@link NormalizedNode} into the given {@link DataObject}.
266 @SuppressWarnings("unchecked")
267 public <T extends DataObject> Optional<T> getDataObject(@Nonnull NormalizedNode<?, ?> normalizedNode,
268 @Nonnull QName rootNode, BindingNormalizedNodeSerializer codecRegistry) {
269 if (normalizedNode != null) {
270 LOG.debug("GNPy: The codecRegistry is ", codecRegistry.toString());
272 LOG.warn("GNPy: The codecRegistry is null");
274 Preconditions.checkNotNull(normalizedNode);
275 if (normalizedNode instanceof ContainerNode) {
276 YangInstanceIdentifier.PathArgument directChildIdentifier = YangInstanceIdentifier.of(rootNode)
277 .getLastPathArgument();
278 Optional<NormalizedNode<?, ?>> directChild = NormalizedNodes.getDirectChild(normalizedNode,
279 directChildIdentifier);
280 if (!directChild.isPresent()) {
281 throw new IllegalStateException(String.format("Could not get the direct child of %s", rootNode));
283 normalizedNode = directChild.get();
284 LOG.debug("GNPy: the normalized node is ", normalizedNode.getNodeType());
286 YangInstanceIdentifier rootNodeYangInstanceIdentifier = YangInstanceIdentifier.of(rootNode);
287 LOG.debug("GNPy: the root Node Yang Instance Identifier is ", rootNodeYangInstanceIdentifier.toString());
288 Map.Entry<?, ?> bindingNodeEntry = codecRegistry.fromNormalizedNode(rootNodeYangInstanceIdentifier,
290 if (bindingNodeEntry == null) {
291 LOG.debug("The binding Node Entry is null");
292 return Optional.empty();
294 return Optional.ofNullable((T) bindingNodeEntry.getValue());
297 public Response getResponse() {