GNPy client refactor 86/95086/5
authormanuedelf <emmanuelle.delfour@orange.com>
Mon, 8 Feb 2021 21:35:38 +0000 (22:35 +0100)
committermanuedelf <emmanuelle.delfour@orange.com>
Wed, 10 Feb 2021 18:16:45 +0000 (19:16 +0100)
- Put GNPy api consumer in a specific package
- Remove hard-coded base url, username and password by putting
paramteres in blueprint configuration file (but still hardcoded in
lighty)
- Use jersey client package for requesting GNPy
- Use customized jackson serializer/deserialize as a temporary
workaround while waiting jackson support in yang tools
https://git.opendaylight.org/gerrit/c/yangtools/+/94852
- Update unit tests

Signed-off-by: manuedelf <emmanuelle.delfour@orange.com>
Change-Id: I28cba22c7df7ffa419d205c024e8e5e5bb909650

22 files changed:
lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java
pce/pom.xml
pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServer.java [deleted file]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyUtilitiesImpl.java
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiModule.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiSerializer.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumer.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerImpl.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyResource.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/JsonConfigurator.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/ResultDeserializer.java [new file with mode: 0644]
pce/src/main/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImpl.java
pce/src/main/resources/OSGI-INF/blueprint/pce-blueprint.xml
pce/src/test/java/org/opendaylight/transportpce/pce/PceSendingPceRPCsTest.java
pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServerTest.java [deleted file]
pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/GnpyUtilitiesImplTest.java
pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/JerseyServer.java
pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerTest.java [new file with mode: 0644]
pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyStub.java [moved from pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/GnpyStub.java with 55% similarity]
pce/src/test/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImplTest.java

index fa368050309d9ba629b32025c5a614cd357ff197..fe1c59fa6c152f9bc100c09f1a632bedb9881c49 100644 (file)
@@ -43,6 +43,8 @@ import org.opendaylight.transportpce.olm.power.PowerMgmt;
 import org.opendaylight.transportpce.olm.power.PowerMgmtImpl;
 import org.opendaylight.transportpce.olm.service.OlmPowerService;
 import org.opendaylight.transportpce.olm.service.OlmPowerServiceImpl;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumerImpl;
 import org.opendaylight.transportpce.pce.impl.PceProvider;
 import org.opendaylight.transportpce.pce.service.PathComputationService;
 import org.opendaylight.transportpce.pce.service.PathComputationServiceImpl;
@@ -105,10 +107,13 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP
         networkTransaction = new NetworkTransactionImpl(requestProcessor);
 
         LOG.info("Creating PCE beans ...");
+        // TODO: pass those parameters through command line
+        GnpyConsumer gnpyConsumer = new GnpyConsumerImpl("http://127.0.0.1:8008",
+                "gnpy", "gnpy", lightyServices.getAdapterContext().currentSerializer());
         PathComputationService pathComputationService = new PathComputationServiceImpl(
                 networkTransaction,
                 lightyServices.getBindingNotificationPublishService(),
-                lightyServices.getAdapterContext().currentSerializer()
+                gnpyConsumer
                 );
         pceProvider = new PceProvider(lightyServices.getRpcProviderService(), pathComputationService);
 
index 44627ab371249e7a31da9461516740596279f0ed..93e56faa80edcdd4324e01267fb911bdec6c5c5c 100644 (file)
             <version>3.0.2</version>
             <optional>true</optional>
         </dependency>
-
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-proxy-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-hk2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-jackson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.transportpce</groupId>
             <artifactId>test-common</artifactId>
index 594aa137fa78b57d5ab70ef047d5302890fb7159..d0610c8cf1c9868d0cd9ab1ad6a744fe4ed2d7ce 100644 (file)
@@ -8,15 +8,14 @@
 
 package org.opendaylight.transportpce.pce;
 
-import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
 import org.opendaylight.transportpce.common.ResponseCodes;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
 import org.opendaylight.transportpce.pce.constraints.PceConstraintsCalc;
-import org.opendaylight.transportpce.pce.gnpy.ConnectToGnpyServer;
 import org.opendaylight.transportpce.pce.gnpy.GnpyException;
 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
 import org.opendaylight.transportpce.pce.gnpy.GnpyUtilitiesImpl;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
 import org.opendaylight.transportpce.pce.graph.PceGraph;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceCalculation;
 import org.opendaylight.transportpce.pce.networkanalyzer.PceResult;
@@ -59,22 +58,23 @@ public class PceSendingPceRPCs {
     private Boolean success;
     private String message;
     private String responseCode;
-    private BindingDOMCodecServices bindingDOMCodecServices;
+    private final GnpyConsumer gnpyConsumer;
 
-    public PceSendingPceRPCs() {
+    public PceSendingPceRPCs(GnpyConsumer gnpyConsumer) {
         setPathDescription(null);
         this.input = null;
         this.networkTransaction = null;
+        this.gnpyConsumer = gnpyConsumer;
     }
 
     public PceSendingPceRPCs(PathComputationRequestInput input,
-        NetworkTransactionService networkTransaction, BindingDOMCodecServices bindingDOMCodecServices) {
+        NetworkTransactionService networkTransaction, GnpyConsumer gnpyConsumer) {
+        this.gnpyConsumer = gnpyConsumer;
         setPathDescription(null);
 
         // TODO compliance check to check that input is not empty
         this.input = input;
         this.networkTransaction = networkTransaction;
-        this.bindingDOMCodecServices = bindingDOMCodecServices;
     }
 
     public void cancelResourceReserve() {
@@ -155,10 +155,9 @@ public class PceSendingPceRPCs {
 
         //Connect to Gnpy to check path feasibility and recompute another path in case of path non-feasibility
         try {
-            ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer();
-            if (connectToGnpy.isGnpyURLExist()) {
+            if (gnpyConsumer.isAvailable()) {
                 GnpyUtilitiesImpl gnpy = new GnpyUtilitiesImpl(networkTransaction, input,
-                        bindingDOMCodecServices);
+                        gnpyConsumer);
                 if (rc.getStatus() && gnpyToCheckFeasiblity(atoz,ztoa,gnpy)) {
                     setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa));
                     return;
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServer.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServer.java
deleted file mode 100644 (file)
index a26f196..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright © 2019 Orange, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.transportpce.pce.gnpy;
-
-import com.google.common.io.CharStreams;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class to connect to GNPy tool.
- *
- * @author Ahmed Triki ( ahmed.triki@orange.com )
- *
- */
-
-public class ConnectToGnpyServer {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ConnectToGnpyServer.class);
-    static final String URL_GNPY = "http://127.0.0.1:8008/gnpy/api/v1.0/files";
-    static final String USER_CRED = "gnpy:gnpy";
-
-    public String returnGnpyResponse(String jsonTxt) throws GnpyException  {
-        String jsonRespTxt = null;
-        LOG.debug("Sending request {}",jsonTxt);
-        try {
-            // Send the request to the GNPy
-            HttpURLConnection conn = connectToGNPy("POST");
-            OutputStream os = conn.getOutputStream();
-            os.write(jsonTxt.getBytes(StandardCharsets.UTF_8));
-            os.flush();
-            if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
-                throw new GnpyException(String.format(
-                    "In connectToGnpyServer: could not connect to GNPy - response code: %s",conn.getResponseCode()));
-            }
-            InputStreamReader response = new InputStreamReader((conn.getInputStream()),StandardCharsets.UTF_8);
-            if (response.ready()) {
-                jsonRespTxt = CharStreams.toString(response);
-            }
-            conn.disconnect();
-        } catch (IOException e) {
-            throw new GnpyException("In connectToGnpyServer: excpetion",e);
-        }
-        LOG.debug("Receiving response {}",jsonRespTxt);
-        return jsonRespTxt;
-    }
-
-    public boolean isGnpyURLExist() {
-        boolean exist = false;
-        try {
-            HttpURLConnection conn = connectToGNPy("HEAD");
-            conn.connect();
-            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
-                LOG.info("In connectToGnpyServer: Gnpy instance is connected to T-PCE");
-                exist = true;
-            }
-            conn.disconnect();
-        }
-        catch (IOException e) {
-            LOG.warn("In connectToGnpyserver: could not connect to GNPy server {}",e.getMessage());
-            return exist;
-        }
-        return exist;
-    }
-
-    private HttpURLConnection connectToGNPy(String action) throws IOException {
-        URL url = new URL(URL_GNPY);
-        String basicAuth = "Basic " + new String(java.util.Base64.getEncoder()
-            .encode(USER_CRED.getBytes(StandardCharsets.UTF_8)),StandardCharsets.UTF_8);
-        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-        conn.setDoOutput(true);
-        conn.setRequestMethod(action);
-        conn.setRequestProperty("Authorization", basicAuth);
-        conn.setRequestProperty("Content-Type", "application/json");
-        conn.connect();
-        return conn;
-    }
-
-    public String readResponse(InputStreamReader response) throws GnpyException {
-        String output = null;
-        BufferedReader br = new BufferedReader(response);
-        String line;
-        StringBuilder sb = new StringBuilder();
-        try {
-            while ((line = br.readLine()) != null) {
-                sb.append(line);
-            }
-            output = sb.toString();
-        } catch (IOException e) {
-            throw new GnpyException("In connectToGnpyserver: could not read response",e);
-        }
-        return output;
-    }
-}
index a31abefc5dd23e39fec852c1f66a67233c4aa9d6..b13bc009730ce7b1e88d87c84a2bffbf5600a945 100644 (file)
@@ -17,8 +17,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.stream.Collectors;
-import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
-import org.opendaylight.transportpce.common.converter.JsonStringConverter;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.explicit.route.hop.type.NumUnnumHop;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.generic.path.properties.path.properties.PathMetric;
@@ -39,10 +37,7 @@ import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraintsBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.Uint16;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,19 +53,9 @@ public class GnpyResult {
     private static final Logger LOG = LoggerFactory.getLogger(GnpyResult.class);
     private Response response = null;
     private Map<String, IpAddress> mapNodeRefIp = new HashMap<>();
-    private JsonStringConverter<Result> converter;
 
-    public GnpyResult(String gnpyResponseString, GnpyTopoImpl gnpyTopo,
-            BindingDOMCodecServices bindingDOMCodecServices) throws GnpyException {
+    public GnpyResult(Result result, GnpyTopoImpl gnpyTopo) throws GnpyException {
         this.mapNodeRefIp = gnpyTopo.getMapNodeRefIp();
-        this.converter = new JsonStringConverter<>(bindingDOMCodecServices);
-        // Create the data object
-        QName pathQname = QName.create("gnpy:path", "2020-09-09", "result");
-        LOG.debug("the Qname is {} / namesapce {} ; module {}; ", pathQname, pathQname.getNamespace(),
-            pathQname.getModule());
-        YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname);
-        Result result = converter.createDataObjectFromJsonString(yangId, gnpyResponseString,
-                JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02);
         List<Response> responses = new ArrayList<>(result.nonnullResponse().values());
         if (responses.isEmpty()) {
             throw new GnpyException("In GnpyResult: the response from GNpy is null!");
index 092a13a51ff645e5d31b453d692c50254aea6261..a51f3495eb007da233e2fdb788e61fdd5e5ed2c0 100644 (file)
@@ -8,20 +8,19 @@
 
 package org.opendaylight.transportpce.pce.gnpy;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
-import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
-import org.opendaylight.transportpce.common.converter.JsonStringConverter;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApiBuilder;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.gnpy.api.ServiceFileBuilder;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.gnpy.api.TopologyFileBuilder;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Connections;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Elements;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.generic.path.properties.path.properties.PathRouteObjects;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.service.PathRequest;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.synchronization.info.Synchronization;
@@ -30,11 +29,7 @@ import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdes
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev201210.path.description.AToZDirectionBuilder;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev201210.path.description.ZToADirection;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraints;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.Uint32;
-import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Class that implements the functions asked to gnpy.
@@ -45,26 +40,22 @@ import org.slf4j.LoggerFactory;
 
 public class GnpyUtilitiesImpl {
 
-    private static final Logger LOG = LoggerFactory.getLogger(GnpyUtilitiesImpl.class);
     private PathComputationRequestInput input;
     private GnpyTopoImpl gnpyTopo = null;
     private GnpyResult gnpyAtoZ;
     private GnpyResult gnpyZtoA;
     private Uint32 requestId;
-    private BindingDOMCodecServices bindingDOMCodecServices;
-    private JsonStringConverter<GnpyApi> converter;
-
+    private final GnpyConsumer gnpyConsumer;
 
     public GnpyUtilitiesImpl(NetworkTransactionService networkTransaction, PathComputationRequestInput input,
-            BindingDOMCodecServices bindingDOMCodecServices)
+            GnpyConsumer gnpyConsumer)
         throws GnpyException {
         this.gnpyTopo = new GnpyTopoImpl(networkTransaction);
         this.input = input;
         this.gnpyAtoZ = null;
         this.gnpyZtoA = null;
         this.requestId = Uint32.valueOf(0);
-        this.bindingDOMCodecServices = bindingDOMCodecServices;
-        this.converter =  new JsonStringConverter<>(bindingDOMCodecServices);
+        this.gnpyConsumer = gnpyConsumer;
     }
 
     public boolean verifyComputationByGnpy(AToZDirection atoz, ZToADirection ztoa, PceConstraints pceHardConstraints)
@@ -92,18 +83,13 @@ public class GnpyUtilitiesImpl {
         // Send the computed path to GNPY tool
         List<Elements> elementsList = new ArrayList<>(gnpyTopo.getElements().values());
         List<Connections> connectionsList = gnpyTopo.getConnections();
-        String gnpyResponse;
-        try {
-            gnpyResponse = getGnpyResponse(elementsList, connectionsList, pathRequestList,
+        Result gnpyResponse = getGnpyResponse(elementsList, connectionsList, pathRequestList,
                 synchronizationList);
-        } catch (Exception e) {
-            throw new GnpyException("Something went wrong", e);
-        }
         // Analyze the response
         if (gnpyResponse == null) {
             throw new GnpyException("In GnpyUtilities: no response from GNPy server");
         }
-        GnpyResult result = new GnpyResult(gnpyResponse, gnpyTopo, bindingDOMCodecServices);
+        GnpyResult result = new GnpyResult(gnpyResponse, gnpyTopo);
         result.analyzeResult();
         return result;
     }
@@ -128,9 +114,8 @@ public class GnpyUtilitiesImpl {
         return result.computeHardConstraintsFromGnpyPath(pathRouteObjectList);
     }
 
-    public String getGnpyResponse(List<Elements> elementsList, List<Connections> connectionsList,
-        List<PathRequest> pathRequestList, List<Synchronization> synchronizationList)
-                throws GnpyException {
+    public Result getGnpyResponse(List<Elements> elementsList, List<Connections> connectionsList,
+        List<PathRequest> pathRequestList, List<Synchronization> synchronizationList) {
         GnpyApi gnpyApi = new GnpyApiBuilder()
             .setTopologyFile(
                 new TopologyFileBuilder()
@@ -142,20 +127,7 @@ public class GnpyUtilitiesImpl {
                         .collect(Collectors.toMap(PathRequest::key, pathRequest -> pathRequest)))
                 .build())
             .build();
-        try {
-            InstanceIdentifier<GnpyApi> idGnpyApi = InstanceIdentifier.builder(GnpyApi.class).build();
-            String gnpyJson = converter.createJsonStringFromDataObject(idGnpyApi, gnpyApi,
-                    JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02);
-            LOG.debug("GNPy Id: {} / json created : {}", idGnpyApi, gnpyJson);
-            ConnectToGnpyServer connect = new ConnectToGnpyServer();
-            String gnpyJsonModified = gnpyJson.replace("gnpy-eqpt-config:", "")
-                    .replace("gnpy-path-computation-simplified:", "").replace("gnpy-network-topology:", "");
-
-            return connect.returnGnpyResponse(gnpyJsonModified);
-        } catch (IOException e) {
-            LOG.error("Cannot convert data object to json string {}", gnpyApi);
-            throw new GnpyException("Cannot convert data object to json string", e);
-        }
+        return gnpyConsumer.computePaths(gnpyApi);
     }
 
     public GnpyResult getGnpyAtoZ() {
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiModule.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiModule.java
new file mode 100644 (file)
index 0000000..549b95d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+
+//This class is a temporary workaround while waiting jackson
+//support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class GnpyApiModule extends SimpleModule {
+
+    private static final long serialVersionUID = 1L;
+
+    public GnpyApiModule(JsonStringConverter<GnpyApi> gnpyApiConverter, JsonStringConverter<Result> resultConverter) {
+        super(PackageVersion.VERSION);
+        addSerializer(GnpyApi.class, new GnpyApiSerializer(gnpyApiConverter));
+        addDeserializer(Result.class, new ResultDeserializer(resultConverter));
+    }
+
+}
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiSerializer.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiSerializer.java
new file mode 100644 (file)
index 0000000..29cd17c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+//This class is a temporary workaround while waiting jackson
+//support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "temporary class")
+public class GnpyApiSerializer extends StdSerializer<GnpyApi> {
+    private static final long serialVersionUID = 1L;
+    private static final Logger LOG = LoggerFactory.getLogger(GnpyApiSerializer.class);
+    private JsonStringConverter<GnpyApi> converter;
+    private InstanceIdentifier<GnpyApi> idGnpyApi = InstanceIdentifier.builder(GnpyApi.class).build();
+
+    public GnpyApiSerializer(JsonStringConverter<GnpyApi> converter) {
+        super(GnpyApi.class);
+        this.converter = converter;
+    }
+
+    @Override
+    public void serialize(GnpyApi value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        String requestStr = converter
+                .createJsonStringFromDataObject(idGnpyApi, value,
+                        JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02);
+        requestStr =  requestStr.replace("gnpy-eqpt-config:", "")
+                .replace("gnpy-path-computation-simplified:", "").replace("gnpy-network-topology:", "");
+        LOG.info("Serialized request {}", requestStr);
+        gen.writeRaw(requestStr);
+    }
+
+}
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumer.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumer.java
new file mode 100644 (file)
index 0000000..5c69347
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+
+public interface GnpyConsumer {
+
+    /**
+     * Check if api is available or not.
+     * @return true os available, false otherwise.
+     */
+    boolean isAvailable();
+
+    /**
+     * Path computation request.
+     * @param request GnpyApi.
+     * @return Result the result of pat computation.
+     */
+    Result computePaths(GnpyApi request);
+
+}
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerImpl.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerImpl.java
new file mode 100644 (file)
index 0000000..4913624
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.glassfish.jersey.client.proxy.WebResourceFactory;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GnpyConsumerImpl implements GnpyConsumer {
+    private static final Logger LOG = LoggerFactory.getLogger(GnpyConsumerImpl.class);
+
+    private GnpyResource api;
+    private JsonStringConverter<GnpyApi> gnpyApiConverter;
+    private JsonStringConverter<Result> resultConverter;
+
+    public GnpyConsumerImpl(String baseUrl, String username, String password,
+            BindingDOMCodecServices bindingDOMCodecServices) {
+        gnpyApiConverter = new JsonStringConverter<>(bindingDOMCodecServices);
+        resultConverter = new JsonStringConverter<>(bindingDOMCodecServices);
+        JsonConfigurator jsonConfigurator = new JsonConfigurator(gnpyApiConverter, resultConverter);
+        Client client = ClientBuilder.newClient();
+        HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basic(username, password);
+        client.register(authFeature);
+        client.register(new LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getName())))
+            .register(JacksonFeature.class).register(jsonConfigurator);
+        api = WebResourceFactory.newResource(GnpyResource.class, client.target(baseUrl));
+    }
+
+    @Override
+    public boolean isAvailable() {
+        try {
+            api.checkStatus();
+            LOG.info("GNPy is available");
+            return true;
+        } catch (WebApplicationException | ProcessingException e) {
+            LOG.info("GNPy is not available ", e);
+            return false;
+        }
+    }
+
+    @Override
+    public Result computePaths(GnpyApi request) {
+        try {
+            return api.computePathRequest(request);
+        } catch (WebApplicationException | ProcessingException e) {
+            LOG.info("Something went wrong while requesting GNPy ", e);
+            return null;
+        }
+    }
+}
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyResource.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyResource.java
new file mode 100644 (file)
index 0000000..5b73774
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+
+@Path("/gnpy/api/v1.0/files")
+public interface GnpyResource {
+
+    @HEAD
+    String checkStatus();
+
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    Result computePathRequest(GnpyApi request);
+
+}
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/JsonConfigurator.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/JsonConfigurator.java
new file mode 100644 (file)
index 0000000..9e051d1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import javax.ws.rs.ext.ContextResolver;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+
+public class JsonConfigurator implements ContextResolver<ObjectMapper> {
+
+    private final ObjectMapper mapper;
+
+    public JsonConfigurator(JsonStringConverter<GnpyApi> gnpyApiConverter,
+            JsonStringConverter<Result> resultConverter) {
+        mapper = new ObjectMapper();
+        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+        mapper.enable(SerializationFeature.INDENT_OUTPUT);
+        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        mapper.registerModule(new GnpyApiModule(gnpyApiConverter, resultConverter));
+    }
+
+    @Override
+    public ObjectMapper getContext(Class<?> type) {
+        return mapper;
+    }
+
+}
diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/ResultDeserializer.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/ResultDeserializer.java
new file mode 100644 (file)
index 0000000..222be70
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import java.io.IOException;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+
+//This class is a temporary workaround while waiting jackson
+//support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "temporary class")
+public class ResultDeserializer extends StdDeserializer<Result> {
+
+    private static final long serialVersionUID = 1L;
+    private  JsonStringConverter<Result> converter;
+    private  YangInstanceIdentifier yangId;
+
+    public ResultDeserializer(JsonStringConverter<Result> converter) {
+        super(Result.class);
+        this.converter = converter;
+        QName pathQname = QName.create("gnpy:path", "2020-09-09", "result");
+        yangId = YangInstanceIdentifier.of(pathQname);
+    }
+
+    @Override
+    public Result deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
+        return converter
+                .createDataObjectFromJsonString(yangId,
+                        parser.readValueAsTree().toString(),
+                        JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02);
+    }
+
+}
index 4e4dfcf55d1720c63477736d44d03db7a9019e02..24ec30ff404eeab453df8520f2fb82d41ee5c609 100644 (file)
@@ -17,12 +17,12 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
-import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.transportpce.pce.PceComplianceCheck;
 import org.opendaylight.transportpce.pce.PceComplianceCheckResult;
 import org.opendaylight.transportpce.pce.PceSendingPceRPCs;
 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.result.Response;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.CancelResourceReserveInput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.CancelResourceReserveOutput;
@@ -61,15 +61,15 @@ public class PathComputationServiceImpl implements PathComputationService {
     private NetworkTransactionService networkTransactionService;
     private final ListeningExecutorService executor;
     private ServicePathRpcResult notification = null;
-    private BindingDOMCodecServices bindingDOMCodecServices;
+    private final GnpyConsumer gnpyConsumer;
 
     public PathComputationServiceImpl(NetworkTransactionService networkTransactionService,
                                       NotificationPublishService notificationPublishService,
-                                      BindingDOMCodecServices bindingDOMCodecServices) {
+                                      GnpyConsumer gnpyConsumer) {
         this.notificationPublishService = notificationPublishService;
         this.networkTransactionService = networkTransactionService;
         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
-        this.bindingDOMCodecServices = bindingDOMCodecServices;
+        this.gnpyConsumer = gnpyConsumer;
     }
 
     public void init() {
@@ -109,7 +109,7 @@ public class PathComputationServiceImpl implements PathComputationService {
                 String message = "";
                 sendNotifications(ServicePathNotificationTypes.CancelResourceReserve, input.getServiceName(),
                         RpcStatusEx.Pending, "Service compliant, submitting cancelResourceReserve Request ...", null);
-                PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs();
+                PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(gnpyConsumer);
                 sendingPCE.cancelResourceReserve();
                 if (Boolean.TRUE.equals(sendingPCE.getSuccess())) {
                     message = "ResourceReserve cancelled !";
@@ -158,7 +158,7 @@ public class PathComputationServiceImpl implements PathComputationService {
                 String message = "";
                 String responseCode = "";
                 PceSendingPceRPCs sendingPCE = new PceSendingPceRPCs(input, networkTransactionService,
-                        bindingDOMCodecServices);
+                        gnpyConsumer);
                 sendingPCE.pathComputation();
                 message = sendingPCE.getMessage();
                 responseCode = sendingPCE.getResponseCode();
index 4f85558d7cf229e7184b78e6485890904779f453..2b7415a72870f9403aaf85bf373953fba1a6f61c 100755 (executable)
@@ -11,7 +11,15 @@ Author: Martial Coulibaly <martial.coulibaly@gfi.com> on behalf of Orange
 -->
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
   xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+  xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
   odl:use-default-for-reference-types="true">
+    <cm:property-placeholder persistent-id="org.opendaylight.transportpce.pce" update-strategy="reload">
+        <cm:default-properties>
+            <cm:property name="url" value="http://127.0.0.1:8008" />
+            <cm:property name="username" value="gnpy" />
+            <cm:property name="password" value="gnpy" />
+        </cm:default-properties>
+    </cm:property-placeholder>
 
   <reference id="networkTransactionImpl" interface="org.opendaylight.transportpce.common.network.NetworkTransactionService" />
 
@@ -32,7 +40,15 @@ Author: Martial Coulibaly <martial.coulibaly@gfi.com> on behalf of Orange
         init-method="init" destroy-method="close">
     <argument ref="networkTransactionImpl"/>
     <argument ref="notificationPublishService" />
-    <argument ref="bindingDOMCodecServices" />
+    <argument ref="gnpyConsumer" />
+  </bean>
+
+  <bean id="gnpyConsumer"
+        class="org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumerImpl">
+     <argument value="${url}"/>
+     <argument value="${username}"/>
+     <argument value="${password}"/>
+     <argument ref="bindingDOMCodecServices" />
   </bean>
 
   <bean id="provider"
index 5291e5ce081735cc2de0a6c670b49942a7cdccd4..299d9379ea61ffb2ef559f32cf0c2884cb1bb5a7 100644 (file)
@@ -18,8 +18,9 @@ import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
 import org.opendaylight.transportpce.common.network.NetworkTransactionImpl;
 import org.opendaylight.transportpce.common.network.RequestProcessor;
-import org.opendaylight.transportpce.pce.gnpy.ConnectToGnpyServer;
 import org.opendaylight.transportpce.pce.gnpy.JerseyServer;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumerImpl;
 import org.opendaylight.transportpce.pce.utils.PceTestData;
 import org.opendaylight.transportpce.pce.utils.PceTestUtils;
 import org.opendaylight.transportpce.test.AbstractTest;
@@ -36,6 +37,7 @@ public class PceSendingPceRPCsTest extends AbstractTest {
     private BindingDOMCodecServices bindingDOMCodecServices;
     private JerseyServer jerseyServer = new JerseyServer();
     private DataBroker dataBroker;
+    private GnpyConsumer gnpyConsumer;
 
 
     @Before
@@ -43,8 +45,10 @@ public class PceSendingPceRPCsTest extends AbstractTest {
         this.dataBroker = getNewDataBroker();
         networkTransaction = new NetworkTransactionImpl(new RequestProcessor(this.dataBroker));
         PceTestUtils.writeNetworkInDataStore(this.dataBroker);
+        gnpyConsumer = new GnpyConsumerImpl("http://localhost:9998",
+                "mylogin", "mypassword", getDataStoreContextUtil().getBindingDOMCodecServices());
         pceSendingPceRPCs = new PceSendingPceRPCs(PceTestData.getPCE_test1_request_54(),
-                        networkTransaction, bindingDOMCodecServices);
+                        networkTransaction, gnpyConsumer);
     }
 
     @Test
@@ -58,11 +62,10 @@ public class PceSendingPceRPCsTest extends AbstractTest {
         jerseyServer.setUp();
         pceSendingPceRPCs =
                 new PceSendingPceRPCs(PceTestData.getGnpyPCERequest("XPONDER-1", "XPONDER-2"),
-                        networkTransaction, null);
+                        networkTransaction, gnpyConsumer);
 
         pceSendingPceRPCs.pathComputation();
-        ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer();
-        Assert.assertTrue(connectToGnpy.isGnpyURLExist());
+        Assert.assertTrue(gnpyConsumer.isAvailable());
         jerseyServer.tearDown();
 
     }
diff --git a/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServerTest.java b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServerTest.java
deleted file mode 100644 (file)
index 1d0dc55..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright © 2020 Orange Labs, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.transportpce.pce.gnpy;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import javax.ws.rs.core.Application;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.test.JerseyTest;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ConnectToGnpyServerTest extends JerseyTest {
-    static {
-        //we must hardcode port because it's hardcoded in ConnectToGnpyServer
-        System.setProperty("jersey.config.test.container.port", "8008");
-    }
-
-    @Override
-    protected Application configure() {
-        return new ResourceConfig(GnpyStub.class);
-    }
-
-    @Test
-    public void isGnpyURLExistTest() throws GnpyException, IOException {
-        ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer();
-        assertTrue(connectToGnpy.isGnpyURLExist());
-    }
-
-    @Test
-    public void returnGnpyResponseTest() throws GnpyException, IOException {
-        ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer();
-        String result = connectToGnpy.returnGnpyResponse(Files.readString(
-                Paths.get("src", "test", "resources", "gnpy", "gnpy_request.json"), StandardCharsets.US_ASCII));
-        assertNotNull("result should not be null", result);
-        assertTrue("Result should not be empty", !result.isEmpty());
-    }
-
-    @Test
-    public void readResponseTest() throws GnpyException {
-        InputStream anyInputStream = new ByteArrayInputStream("test data".getBytes());
-        ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer();
-        String result = connectToGnpy.readResponse(new InputStreamReader(anyInputStream));
-        Assert.assertNotNull(result);
-
-    }
-
-}
index ed40dbe536d099fe07c2c1a6485ab9158f7115a8..b55cc763bf19c0e51afa1dc28e16ad7309ee0dca 100644 (file)
@@ -25,6 +25,7 @@ import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.junit.AfterClass;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.mdsal.binding.api.WriteTransaction;
@@ -34,6 +35,9 @@ import org.opendaylight.transportpce.common.network.NetworkTransactionImpl;
 import org.opendaylight.transportpce.common.network.RequestProcessor;
 import org.opendaylight.transportpce.pce.constraints.PceConstraints;
 import org.opendaylight.transportpce.pce.constraints.PceConstraintsCalc;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumer;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyConsumerImpl;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyStub;
 import org.opendaylight.transportpce.pce.utils.JsonUtil;
 import org.opendaylight.transportpce.pce.utils.PceTestData;
 import org.opendaylight.transportpce.test.AbstractTest;
@@ -65,9 +69,10 @@ public class GnpyUtilitiesImplTest extends AbstractTest {
     private GnpyUtilitiesImpl gnpyUtilitiesImpl;
     private NetworkTransactionImpl networkTransaction;
     private static HttpServer httpServer;
+    private GnpyConsumer gnpyConsumer;
 
     public GnpyUtilitiesImplTest() throws IOException {
-        networkTransaction = new NetworkTransactionImpl(new RequestProcessor(this.getDataBroker()));
+        networkTransaction = new NetworkTransactionImpl(new RequestProcessor(getDataBroker()));
         JsonReader networkReader = null;
         JsonReader topoReader = null;
 
@@ -106,11 +111,17 @@ public class GnpyUtilitiesImplTest extends AbstractTest {
 
     }
 
+    @Before
+    public void initConsumer() {
+        gnpyConsumer = new GnpyConsumerImpl("http://localhost:9998", "mylogin", "mypassword",
+                getDataStoreContextUtil().getBindingDOMCodecServices());
+    }
+
     @BeforeClass
     public static void init() {
         // here we cannot use JerseyTest as we already extends AbstractTest
         final ResourceConfig rc = new ResourceConfig(GnpyStub.class);
-        httpServer = GrizzlyHttpServerFactory.createHttpServer(URI.create("http://127.0.0.1:8008"), rc);
+        httpServer = GrizzlyHttpServerFactory.createHttpServer(URI.create("http://localhost:9998"), rc);
     }
 
     @AfterClass
@@ -122,7 +133,7 @@ public class GnpyUtilitiesImplTest extends AbstractTest {
             throws InterruptedException, ExecutionException {
         InstanceIdentifier<Network> nwInstanceIdentifier = InstanceIdentifier.builder(Networks.class)
                 .child(Network.class, new NetworkKey(new NetworkId(networkId))).build();
-        WriteTransaction dataWriteTransaction = this.getDataBroker().newWriteOnlyTransaction();
+        WriteTransaction dataWriteTransaction = getDataBroker().newWriteOnlyTransaction();
         dataWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, nwInstanceIdentifier, network);
         dataWriteTransaction.commit().get();
     }
@@ -131,7 +142,7 @@ public class GnpyUtilitiesImplTest extends AbstractTest {
     public void askNewPathFromGnpyNullResultTest() throws Exception {
         gnpyUtilitiesImpl = new GnpyUtilitiesImpl(networkTransaction,
                 PceTestData.getGnpyPCERequest("XPONDER-1", "XPONDER-2"),
-                JsonUtil.getInstance().getBindingDOMCodecServices());
+                gnpyConsumer);
         assertNull("No hard constraints should be available", gnpyUtilitiesImpl.askNewPathFromGnpy(null));
 
     }
@@ -140,7 +151,7 @@ public class GnpyUtilitiesImplTest extends AbstractTest {
     public void askNewPathFromGnpyTest() throws Exception {
         gnpyUtilitiesImpl = new GnpyUtilitiesImpl(networkTransaction,
                 PceTestData.getGnpyPCERequest("XPONDER-3", "XPONDER-4"),
-                JsonUtil.getInstance().getBindingDOMCodecServices());
+                gnpyConsumer);
         PceConstraintsCalc constraints = new PceConstraintsCalc(PceTestData.getPCE_simpletopology_test1_request(),
                 networkTransaction);
         PceConstraints pceHardConstraints = constraints.getPceHardConstraints();
@@ -158,7 +169,7 @@ public class GnpyUtilitiesImplTest extends AbstractTest {
 
         gnpyUtilitiesImpl = new GnpyUtilitiesImpl(networkTransaction,
                 PceTestData.getGnpyPCERequest("XPONDER-1", "XPONDER-2"),
-                JsonUtil.getInstance().getBindingDOMCodecServices());
+                gnpyConsumer);
         PceConstraintsCalc constraints = new PceConstraintsCalc(PceTestData.getPCE_simpletopology_test1_request(),
                 networkTransaction);
         PceConstraints pceHardConstraints = constraints.getPceHardConstraints();
index 6678c94fc191da5556c4abc4828038c349a8ea03..aa0b6967ed8cef6e7bbdaa64dc59902575f4cb12 100644 (file)
@@ -11,15 +11,11 @@ package org.opendaylight.transportpce.pce.gnpy;
 import javax.ws.rs.core.Application;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
+import org.opendaylight.transportpce.pce.gnpy.consumer.GnpyStub;
 
 
 public class JerseyServer extends JerseyTest {
 
-    static {
-        //we must hardcode port because it's hardcoded in ConnectToGnpyServer
-        System.setProperty("jersey.config.test.container.port", "8008");
-    }
-
     @Override
     protected Application configure() {
         return new ResourceConfig(GnpyStub.class);
diff --git a/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerTest.java b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerTest.java
new file mode 100644 (file)
index 0000000..074f8d4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2021 Orange, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.pce.gnpy.consumer;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import javax.ws.rs.core.Application;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
+import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.Result;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GnpyConsumerTest extends JerseyTest {
+    private static final Logger LOG = LoggerFactory.getLogger(GnpyConsumerTest.class);
+    private JsonStringConverter<GnpyApi> gnpyApiConverter;
+
+    @Override
+    protected Application configure() {
+        gnpyApiConverter = new JsonStringConverter<>(
+                AbstractTest.getDataStoreContextUtil().getBindingDOMCodecServices());
+        return new ResourceConfig(GnpyStub.class);
+    }
+
+    @Test
+    public void isAvailableTest() {
+        GnpyConsumer gnpyConsumer = new GnpyConsumerImpl("http://localhost:9998",
+                "mylogin",
+                "mypassword",
+                AbstractTest.getDataStoreContextUtil().getBindingDOMCodecServices());
+        assertTrue("Gnpy should be available", gnpyConsumer.isAvailable());
+    }
+
+    @Test
+    public void computePathsTest() throws IOException {
+        GnpyConsumer gnpyConsumer = new GnpyConsumerImpl("http://localhost:9998",
+                "mylogin",
+                "mypassword",
+                AbstractTest.getDataStoreContextUtil().getBindingDOMCodecServices());
+        QName pathQname = QName.create("gnpy:gnpy-api", "2019-01-03", "gnpy-api");
+        YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname);
+        GnpyApi request = gnpyApiConverter
+                .createDataObjectFromJsonString(yangId,
+                        Files.readString(Paths.get("src/test/resources/gnpy/gnpy_request.json")),
+                        JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02);
+        Result result = gnpyConsumer.computePaths(request);
+        LOG.info("Response received {}", result);
+        assertNotNull("Result should not be null", result);
+    }
+}
similarity index 55%
rename from pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/GnpyStub.java
rename to pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyStub.java
index ff6762ad0c6686ce209728ac2e289ecc61028313..43d6db88ac1cfceecb7b41eae88701f418b7da83 100644 (file)
@@ -5,11 +5,9 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.transportpce.pce.gnpy;
+package org.opendaylight.transportpce.pce.gnpy.consumer;
 
-import com.google.gson.stream.JsonReader;
 import java.io.IOException;
-import java.io.StringReader;
 import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -21,10 +19,13 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Response;
-import org.opendaylight.transportpce.pce.utils.JsonUtil;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
 import org.opendaylight.yang.gen.v1.gnpy.gnpy.api.rev190103.GnpyApi;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.service.PathRequest;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,28 +41,25 @@ public class GnpyStub {
     @POST
     @Produces({ "application/json" })
     @Consumes({ "application/json" })
-    public Response computePath(String body) {
-        LOG.info("Received path request {}", body);
-        // as type-element and explicit route usage are not in the same namespace than
-        // gnpy-api,
-        // we add to add prefix if they are not set (request generated by
-        // GnpyUtilitiesImpl does not
-        // contain prefix)
-        if (body != null && !body.contains("gnpy-network-topology")) {
-            body = body.replaceAll("\"type\":\\s*\"", "\"type\":\"gnpy-network-topology:")
-                    .replaceAll("\"length_units\":\\s*\"", "\"length_units\":\"gnpy-network-topology:");
-        }
-        if (body != null && !body.contains("gnpy-path-computation-simplified")) {
-            body = body.replaceAll("\"explicit-route-usage\":\\s*\"",
-                    "\"explicit-route-usage\":\"gnpy-path-computation-simplified:");
-        }
-        GnpyApi request = (GnpyApi) JsonUtil.getInstance().getDataObjectFromJson(new JsonReader(new StringReader(body)),
-                QName.create("gnpy:gnpy-api", "2019-01-03", "gnpy-api"));
-        URI location = URI.create("http://127.0.0.1:8008/gnpy/api/v1.0/files");
+    public Response computePath(String request) {
+        LOG.info("Received path request {}", request);
+        URI location = URI.create("http://127.0.0.1:9998/gnpy/api/v1.0/files");
         // TODO: return different response based on body data
+        QName pathQname = QName.create("gnpy:gnpy-api", "2019-01-03", "gnpy-api");
+        YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname);
+        JsonStringConverter<GnpyApi> converter = new JsonStringConverter<>(
+                AbstractTest.getDataStoreContextUtil().getBindingDOMCodecServices());
         try {
             String response = null;
-            List<PathRequest> pathRequest = new ArrayList<>(request.getServiceFile().nonnullPathRequest().values());
+            request = request.replace("Transceiver", "gnpy-network-topology:Transceiver")
+                    .replace("Roadm", "gnpy-network-topology:Roadm")
+                    .replace("Fiber", "gnpy-network-topology:Fiber")
+                    .replace("km", "gnpy-network-topology:km")
+                    .replace("route-include-ero", "gnpy-path-computation-simplified:route-include-ero");
+            GnpyApi data = converter.createDataObjectFromJsonString(yangId,
+                    request, JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02);
+            LOG.info("Converted request {}", data);
+            List<PathRequest> pathRequest = new ArrayList<>(data.getServiceFile().nonnullPathRequest().values());
             // this condition is totally arbitrary and could be modified
             if (!pathRequest.isEmpty() && "127.0.0.31".contentEquals(pathRequest.get(0).getSource().stringValue())) {
                 response = Files
@@ -72,6 +70,7 @@ public class GnpyStub {
 
             return Response.created(location).entity(response).build();
         } catch (IOException e) {
+            LOG.error("Cannot manage request", e);
             return Response.serverError().build();
         }
     }
index 86a2f9e075123269c73fb1aa05b6b6a5cb7c52f7..0ab6d1c1e1227526f53eeb798889bba2b26ee2d5 100644 (file)
@@ -15,14 +15,10 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.transportpce.common.network.NetworkTransactionImpl;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
-import org.opendaylight.transportpce.common.network.RequestProcessor;
 import org.opendaylight.transportpce.pce.gnpy.GnpyResult;
 import org.opendaylight.transportpce.pce.gnpy.GnpyTopoImpl;
 import org.opendaylight.transportpce.pce.utils.PceTestData;
-import org.opendaylight.transportpce.pce.utils.PceTestUtils;
-import org.opendaylight.transportpce.pce.utils.TransactionUtils;
 import org.opendaylight.transportpce.test.AbstractTest;
 import org.opendaylight.transportpce.test.DataStoreContext;
 import org.opendaylight.yang.gen.v1.gnpy.path.rev200909.PathBandwidth;
@@ -93,17 +89,6 @@ public class PathComputationServiceImplTest extends AbstractTest {
 
     }
 
-    @Test(expected = Exception.class)
-    public void generateGnpyResponse() throws Exception {
-        PceTestUtils.writeNetworkIntoDataStore(dataBroker, dataStoreContext, TransactionUtils.getNetworkForSpanLoss());
-        GnpyResult gnpyResult2 =
-                new GnpyResult("A-to-Z",
-                        new GnpyTopoImpl(new NetworkTransactionImpl(
-                                new RequestProcessor(dataBroker))), null);
-        pathComputationServiceImpl.generateGnpyResponse(gnpyResult2.getResponse(), "A-to-Z");
-    }
-
-
     @After
     public void destroy() {
         pathComputationServiceImpl.close();