From 952583aa9f0de2de04f230291a5989413591a7b7 Mon Sep 17 00:00:00 2001 From: manuedelf Date: Mon, 8 Feb 2021 22:35:38 +0100 Subject: [PATCH] GNPy client refactor - 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 Change-Id: I28cba22c7df7ffa419d205c024e8e5e5bb909650 --- .../tpce/module/TransportPCEImpl.java | 7 +- pce/pom.xml | 21 +++- .../transportpce/pce/PceSendingPceRPCs.java | 17 ++- .../pce/gnpy/ConnectToGnpyServer.java | 106 ------------------ .../transportpce/pce/gnpy/GnpyResult.java | 17 +-- .../pce/gnpy/GnpyUtilitiesImpl.java | 48 ++------ .../pce/gnpy/consumer/GnpyApiModule.java | 28 +++++ .../pce/gnpy/consumer/GnpyApiSerializer.java | 46 ++++++++ .../pce/gnpy/consumer/GnpyConsumer.java | 28 +++++ .../pce/gnpy/consumer/GnpyConsumerImpl.java | 66 +++++++++++ .../pce/gnpy/consumer/GnpyResource.java | 30 +++++ .../pce/gnpy/consumer/JsonConfigurator.java | 38 +++++++ .../pce/gnpy/consumer/ResultDeserializer.java | 44 ++++++++ .../service/PathComputationServiceImpl.java | 12 +- .../OSGI-INF/blueprint/pce-blueprint.xml | 18 ++- .../pce/PceSendingPceRPCsTest.java | 13 ++- .../pce/gnpy/ConnectToGnpyServerTest.java | 61 ---------- .../pce/gnpy/GnpyUtilitiesImplTest.java | 23 +++- .../transportpce/pce/gnpy/JerseyServer.java | 6 +- .../pce/gnpy/consumer/GnpyConsumerTest.java | 66 +++++++++++ .../pce/gnpy/{ => consumer}/GnpyStub.java | 45 ++++---- .../PathComputationServiceImplTest.java | 15 --- 22 files changed, 462 insertions(+), 293 deletions(-) delete mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServer.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiModule.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiSerializer.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumer.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerImpl.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyResource.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/JsonConfigurator.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/ResultDeserializer.java delete mode 100644 pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServerTest.java create mode 100644 pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerTest.java rename pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/{ => consumer}/GnpyStub.java (55%) diff --git a/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java b/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java index fa3680503..fe1c59fa6 100644 --- a/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java +++ b/lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java @@ -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); diff --git a/pce/pom.xml b/pce/pom.xml index 44627ab37..93e56faa8 100644 --- a/pce/pom.xml +++ b/pce/pom.xml @@ -48,7 +48,26 @@ 3.0.2 true - + + org.glassfish.jersey.core + jersey-client + + + org.glassfish.jersey.ext + jersey-proxy-client + + + org.glassfish.jersey.inject + jersey-hk2 + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + org.opendaylight.transportpce test-common diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java index 594aa137f..d0610c8cf 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java @@ -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 index a26f19604..000000000 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServer.java +++ /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; - } -} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java index a31abefc5..b13bc0097 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java @@ -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 mapNodeRefIp = new HashMap<>(); - private JsonStringConverter 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 responses = new ArrayList<>(result.nonnullResponse().values()); if (responses.isEmpty()) { throw new GnpyException("In GnpyResult: the response from GNpy is null!"); diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyUtilitiesImpl.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyUtilitiesImpl.java index 092a13a51..a51f3495e 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyUtilitiesImpl.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyUtilitiesImpl.java @@ -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 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 elementsList = new ArrayList<>(gnpyTopo.getElements().values()); List 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 elementsList, List connectionsList, - List pathRequestList, List synchronizationList) - throws GnpyException { + public Result getGnpyResponse(List elementsList, List connectionsList, + List pathRequestList, List 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 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 index 000000000..549b95deb --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiModule.java @@ -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 gnpyApiConverter, JsonStringConverter 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 index 000000000..29cd17c4e --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyApiSerializer.java @@ -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 { + private static final long serialVersionUID = 1L; + private static final Logger LOG = LoggerFactory.getLogger(GnpyApiSerializer.class); + private JsonStringConverter converter; + private InstanceIdentifier idGnpyApi = InstanceIdentifier.builder(GnpyApi.class).build(); + + public GnpyApiSerializer(JsonStringConverter 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 index 000000000..5c69347a1 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumer.java @@ -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 index 000000000..4913624a5 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerImpl.java @@ -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 gnpyApiConverter; + private JsonStringConverter 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 index 000000000..5b7377490 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyResource.java @@ -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 index 000000000..9e051d15d --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/JsonConfigurator.java @@ -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 { + + private final ObjectMapper mapper; + + public JsonConfigurator(JsonStringConverter gnpyApiConverter, + JsonStringConverter 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 index 000000000..222be701d --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/consumer/ResultDeserializer.java @@ -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 { + + private static final long serialVersionUID = 1L; + private JsonStringConverter converter; + private YangInstanceIdentifier yangId; + + public ResultDeserializer(JsonStringConverter 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); + } + +} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImpl.java b/pce/src/main/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImpl.java index 4e4dfcf55..24ec30ff4 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImpl.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImpl.java @@ -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(); diff --git a/pce/src/main/resources/OSGI-INF/blueprint/pce-blueprint.xml b/pce/src/main/resources/OSGI-INF/blueprint/pce-blueprint.xml index 4f85558d7..2b7415a72 100755 --- a/pce/src/main/resources/OSGI-INF/blueprint/pce-blueprint.xml +++ b/pce/src/main/resources/OSGI-INF/blueprint/pce-blueprint.xml @@ -11,7 +11,15 @@ Author: Martial Coulibaly on behalf of Orange --> + + + + + + + @@ -32,7 +40,15 @@ Author: Martial Coulibaly on behalf of Orange init-method="init" destroy-method="close"> - + + + + + + + + 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(); diff --git a/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/JerseyServer.java b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/JerseyServer.java index 6678c94fc..aa0b6967e 100644 --- a/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/JerseyServer.java +++ b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/JerseyServer.java @@ -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 index 000000000..074f8d459 --- /dev/null +++ b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyConsumerTest.java @@ -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 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); + } +} diff --git a/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/GnpyStub.java b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyStub.java 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 ff6762ad0..43d6db88a 100644 --- a/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/GnpyStub.java +++ b/pce/src/test/java/org/opendaylight/transportpce/pce/gnpy/consumer/GnpyStub.java @@ -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 converter = new JsonStringConverter<>( + AbstractTest.getDataStoreContextUtil().getBindingDOMCodecServices()); try { String response = null; - List 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 = 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(); } } diff --git a/pce/src/test/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImplTest.java b/pce/src/test/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImplTest.java index 86a2f9e07..0ab6d1c1e 100644 --- a/pce/src/test/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImplTest.java +++ b/pce/src/test/java/org/opendaylight/transportpce/pce/service/PathComputationServiceImplTest.java @@ -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(); -- 2.36.6