From e4a554e661804d03c14c9e65d8332e576af801b4 Mon Sep 17 00:00:00 2001 From: Ahmed Triki Date: Thu, 25 Apr 2019 15:38:59 +0200 Subject: [PATCH] exchange with GNPy to check path feasibility - add gnpy data model in api module - add package in pce to connect to gnpy - modify PCESendingPceRPC to support gnpy - move test-common DataStoreContext and binding converter classes to transportpce-common, adapt pom files dependencies JIRA: TRNSPRTPCE-87 Change-Id: Ia93fbe0665427530afe33b623ee9aeb3d9f121bb Signed-off-by: Ahmed Triki Co-authored-by: Esther Le Rouzic --- api/src/main/yang/gnpy-api@2019-01-03.yang | 44 + .../yang/gnpy-eqpt-config@2018-11-19.yang | 88 ++ .../gnpy-network-topology@2018-12-14.yang | 278 ++++++ ...ath-computation-simplified@2019-05-02.yang | 595 ++++++++++++ common/pom.xml | 21 +- .../common/DataStoreContext.java | 2 +- .../common/DataStoreContextImpl.java | 2 +- .../AbstractDataObjectConverter.java | 4 +- .../converter/JSONDataObjectConverter.java | 6 +- .../converter/XMLDataObjectConverter.java | 4 +- .../converter/api/DataObjectConverter.java | 2 +- pce/pom.xml | 17 +- .../transportpce/pce/PceGraph.java | 11 - .../transportpce/pce/PceSendingPceRPCs.java | 148 ++- .../pce/gnpy/ConnectToGnpyServer.java | 111 +++ .../pce/gnpy/ExtractTopoDataStoreImpl.java | 854 ++++++++++++++++++ .../transportpce/pce/gnpy/GnpyResult.java | 324 +++++++ .../pce/gnpy/ServiceDataStoreOperations.java | 23 + .../gnpy/ServiceDataStoreOperationsImpl.java | 147 +++ .../transportpce/pce/utils/PceTestUtils.java | 6 +- test-common/pom.xml | 5 + .../transportpce/test/AbstractTest.java | 4 +- .../transportpce/test/DeviceWrapper.java | 8 +- 23 files changed, 2627 insertions(+), 77 deletions(-) create mode 100644 api/src/main/yang/gnpy-api@2019-01-03.yang create mode 100644 api/src/main/yang/gnpy-eqpt-config@2018-11-19.yang create mode 100644 api/src/main/yang/gnpy-network-topology@2018-12-14.yang create mode 100644 api/src/main/yang/gnpy-path-computation-simplified@2019-05-02.yang rename {test-common/src/main/java/org/opendaylight/transportpce/test => common/src/main/java/org/opendaylight/transportpce}/common/DataStoreContext.java (95%) rename {test-common/src/main/java/org/opendaylight/transportpce/test => common/src/main/java/org/opendaylight/transportpce}/common/DataStoreContextImpl.java (99%) rename {test-common/src/main/java/org/opendaylight/transportpce/binding => common/src/main/java/org/opendaylight/transportpce/common}/converter/AbstractDataObjectConverter.java (97%) rename {test-common/src/main/java/org/opendaylight/transportpce/binding => common/src/main/java/org/opendaylight/transportpce/common}/converter/JSONDataObjectConverter.java (96%) rename {test-common/src/main/java/org/opendaylight/transportpce/binding => common/src/main/java/org/opendaylight/transportpce/common}/converter/XMLDataObjectConverter.java (98%) rename {test-common/src/main/java/org/opendaylight/transportpce/binding => common/src/main/java/org/opendaylight/transportpce/common}/converter/api/DataObjectConverter.java (98%) create 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/ExtractTopoDataStoreImpl.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperations.java create mode 100644 pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperationsImpl.java diff --git a/api/src/main/yang/gnpy-api@2019-01-03.yang b/api/src/main/yang/gnpy-api@2019-01-03.yang new file mode 100644 index 000000000..b837c277a --- /dev/null +++ b/api/src/main/yang/gnpy-api@2019-01-03.yang @@ -0,0 +1,44 @@ +module gnpy-api { + yang-version 1; + namespace "gnpy:gnpy-api"; + + prefix "gnpyapi"; + + import gnpy-network-topology { + prefix "gnpynt"; + } + import gnpy-path-computation-simplified { + prefix "gnpypc"; + } + + organization + "Telecom Infra Project OOPT PSE Working Group"; + + contact + "WG Web: + contact: + contact: + "; + + description "YANG model for gnpy api input for path computation - TransportPCE preversion"; + + revision "2019-01-03" { + description "first draft"; + reference "YANG model for api input for path computation with gnpy"; + } + + container gnpy-api{ + description "This is the structure of the body of the request to gnpy"; + container topology-file{ + uses gnpynt:topo; + description + "Describe the topology file to connect to gnpy"; + } + container service-file{ + uses gnpypc:service; + description + "Describe the service file to connect to gnpy"; + } + } + +} diff --git a/api/src/main/yang/gnpy-eqpt-config@2018-11-19.yang b/api/src/main/yang/gnpy-eqpt-config@2018-11-19.yang new file mode 100644 index 000000000..93f13b08c --- /dev/null +++ b/api/src/main/yang/gnpy-eqpt-config@2018-11-19.yang @@ -0,0 +1,88 @@ +module gnpy-eqpt-config { + yang-version 1; + namespace "gnpy:gnpy-eqpt-config"; + + prefix "gnpyeqpt"; + + organization + "Telecom Infra Project OOPT PSE + Working Group"; + + contact + "WG Web: + contact: + contact: + "; + + description "Base YANG model for gnpy equipment library input for path computation - transportPCE preversion"; + + revision "2018-11-19" { + description "first draft"; + reference "Base YANG model for equipment library input for path computation with gnpy"; + } + + /* + * Identities + + + identity edfa-variety { + description "edfa variety" ; + } + + identity fiber-variety { + description "base identity for fiber variety" ; + } + + identity transceiver-variety { + description "base identity for transceiver variety" ; + } + + */ + + list Edfa { + key type_variety; + leaf type_variety { + type string; + description "a unique name to ID the amplifier in the JSON/Excel template topology input file" ; + } + } + + + list Fiber { + key type_variety ; + leaf type_variety { + type string ; + } + description "a unique name to ID the fiber in the JSON or Excel template topology input file" ; + } + } + + list Transceiver{ + key type_variety ; + leaf type_variety { + type string ; + } + description "a unique name to ID the transceiver in the JSON or Excel template topology input file" ; + } + list mode { + key format ; + leaf format { + type string ; + description "unique name of the mode" ; + } + } + } + + container Spans { + + } + + container Roadms { + + } + + container SI { + + } +} + diff --git a/api/src/main/yang/gnpy-network-topology@2018-12-14.yang b/api/src/main/yang/gnpy-network-topology@2018-12-14.yang new file mode 100644 index 000000000..c49d4f142 --- /dev/null +++ b/api/src/main/yang/gnpy-network-topology@2018-12-14.yang @@ -0,0 +1,278 @@ +module gnpy-network-topology { + yang-version 1; + namespace "gnpy:gnpy-network-topology"; + + prefix "gnpynt"; + + + import gnpy-eqpt-config { + prefix "geqpt"; + } + + import ietf-inet-types { + prefix inet; + } + + organization + "Telecom Infra Project OOPT PSE Working Group"; + + contact + "WG Web: + contact: + contact: + "; + + description "YANG model for gnpy network input for path computation - transportPCE preversion"; + + revision "2018-12-14" { + description "first draft"; + reference "YANG model for network input for path computation with gnpy"; + } + + identity type-element { + description + "Base identity for element type"; + } + + identity Transceiver { + base type-element; + description + " Transceiver element"; + } + + identity Fiber { + base type-element; + description + "Fiber element"; + } + + identity Roadm { + base type-element; + description + "Roadm element"; + } + + identity Edfa { + base type-element; + description + "Edfa element"; + } + + identity Fused { + base type-element; + description + "Fused element"; + } + + identity length-unit { + description "length unit" ; + } + + identity km { + base length-unit ; + description "kilometers" ; + } + + identity m{ + base length-unit ; + description "meter" ; + } + typedef Coordinate { + type decimal64 { + fraction-digits 6; + } + } + + typedef te-node-id { + type inet:ip-address; + description + "An identifier for a node in a topology. + The identifier is represented as 32-bit unsigned integer in + the dotted-quad notation. + This attribute is mapped to Router ID in + RFC3630, RFC5329, RFC5305, and RFC6119."; + } + + typedef Coef { + type decimal64 { + fraction-digits 2; + } + } + + + grouping location-attributes { + container location { + leaf city { + type string; + mandatory true ; + } + leaf region { + type string; + mandatory true ; + } + leaf latitude { + type Coordinate; + mandatory true ; + } + leaf longitude { + type Coordinate; + mandatory true ; + } + } + } + + grouping fiber-params { + description "....." ; + leaf length { + mandatory true ; + type decimal64 { + fraction-digits 2; + } + } + leaf loss_coef{ + mandatory true ; + type decimal64 { + fraction-digits 2; + } + } + leaf length_units{ + type identityref { + base length-unit ; + } + mandatory true ; + } + leaf att_in{ + type decimal64 { + fraction-digits 2; + } + mandatory true ; + } + leaf con_in{ + type decimal64 { + fraction-digits 2; + } + mandatory true ; + } + leaf con_out{ + type decimal64 { + fraction-digits 2; + } + mandatory true ; + } + } + + grouping edfa-params { + container operational { + leaf gain-target { + type decimal64 { + fraction-digits 2; + } + mandatory true ; + units dB ; + description ".." ; + } + leaf tilt-target { + type decimal64 { + fraction-digits 2; + } + mandatory true ; + description ".." ; + } + leaf out-voa { + type decimal64 { + fraction-digits 2; + } + mandatory true ; + units dB ; + description ".." ; + } + description "Operational values for the Edfa " ; + } + } + + grouping roadm-params{ + leaf target_pch_out_db{ + type decimal64 { + fraction-digits 2; + } + units dB ; + description ".." ; + } + } + + grouping transceiver-params{ + + } + + grouping fused-params{ + + } + + grouping element-type-choice{ + choice element-type{ + case Edfa{ + when "type = 'Edfa'" ; + uses edfa-params ; + } + case FiberRoadm{ + container params { + choice fiberroadm{ + case Fiber{ + when "type = 'Fiber'" ; + uses fiber-params ; + } + case Roadm{ + when "type = 'Roadm'" ; + uses roadm-params ; + } + } + } + } + case Transceiver{ + when "type = 'Transceiver'" ; + } + + case Fused{ + when "type = 'Fused'" ; + } + } + } + + grouping topo { + list elements { + key uid; + leaf uid { + type string; + } + leaf type { + type identityref { + base type-element ; + } + mandatory true ; + } + leaf type_variety { + type string ; + mandatory false ; + } + container metadata { + uses location-attributes ; + } + + uses element-type-choice ; + } + + list connections { + config false ; + leaf from_node { + type leafref{ + path "/topo/elements/uid" ; + } + } + leaf to_node { + type leafref{ + path "/topo/elements/uid" ; + } + } + } + } +} diff --git a/api/src/main/yang/gnpy-path-computation-simplified@2019-05-02.yang b/api/src/main/yang/gnpy-path-computation-simplified@2019-05-02.yang new file mode 100644 index 000000000..64979b5f7 --- /dev/null +++ b/api/src/main/yang/gnpy-path-computation-simplified@2019-05-02.yang @@ -0,0 +1,595 @@ +module gnpy-path-computation-simplified { + yang-version 1; + namespace "gnpy:path"; + + prefix "gnpypc"; + + import ietf-yang-types { + prefix "yang-types"; + } + + import ietf-inet-types { + prefix inet; + } + organization + "Telecom Infra Project OOPT PSE Working Group"; + + contact + "WG Web: + contact: + contact: + "; + + description "YANG model for gnpy path computation simplified for transportPCE"; + + revision "2019-05-02" { + description "second draft with detailed blocking reasons"; + reference "YANG model for path computation with gnpy inputs"; + } + + grouping effective-freq-slot{ + /* content copied from ietf-flexi-grid-media-channel, because only M and N are needed + from the initial grouping. + */ + description "The effective frequency slot is an attribute + of a media channel and, being a frequency slot, it is + described by its nominal central frequency and slot + width"; + reference "rfc7698"; + leaf N { + type int32; + description + "Is used to determine the Nominal Central + Frequency. The set of nominal central frequencies + can be built using the following expression: + f = 193.1 THz + n x 0.00625 THz, + where 193.1 THz is ITU-T ''anchor frequency'' for + transmission over the C band, n is a positive or + negative integer including 0."; + reference "rfc7698"; + } + leaf M { + type int32; + description + "Is used to determine the slot width. A slot width + is constrained to be M x SWG (that is, M x 12.5 GHz), + where M is an integer greater than or equal to 1."; + reference "rfc7698"; + } + } + + grouping gnpy-specific-parameters{ + description + "This grouping defines the gnpy specific parameters for requests."; + leaf technology { + type string; + default "flexi-grid"; + description + "Data plane technology type."; + } + leaf trx_type { + type string ; + mandatory true; + description "name of the transponder type (to be read from equipment library"; + + } + leaf trx_mode { + type string ; + description "name of the transponder mode (to be read from equipment library"; + + } + list effective-freq-slot { + key "N"; + uses effective-freq-slot ; + } + leaf spacing { + mandatory true; + type decimal64 { + fraction-digits 1; + } + units Hz; + description + "It is the spacing between channels assuming full load with + same channels as the requested one. multiple of 12.5 GHz"; + + } + leaf max-nb-of-channel{ + type uint32 ; + description "Nb of channel to take into account for the full load case. + "; + + } + leaf output-power{ + type decimal64 { + fraction-digits 5; + } + units W; + description "optical power setting to be used for the propagation"; + + } + leaf path_bandwidth{ + type decimal64 { + fraction-digits 5; + } + mandatory true; + units bit/s; + description "Capacity required"; + } + } + + identity SNR-bandwidth { + base path-metric-type; + description + "A metric that records SNR in signal bandwidth"; + } + + identity OSNR-bandwidth { + base path-metric-type; + description + "A metric that records OSNR in signal bandwidth"; + } + + identity SNR-0.1nm { + base path-metric-type; + description + "A metric that records SNR in 0.1nm"; + } + + identity OSNR-0.1nm { + base path-metric-type; + description + "A metric that records OSNR in 0.1nm"; + } + + identity reference_power { + base path-metric-type; + description + "to be revised"; + } + + identity path_bandwidth { + base path-metric-type; + description + "to be revised"; + } + + grouping transponder{ + leaf transponder-type { + type string ; + description + "transponder type."; + } + leaf transponder-mode { + type string ; + description + "transponder mode."; + } + } + + grouping hop-attribute{ + description + "This grouping defines the hop attribute parameters for request or response"; + choice hop-type{ + case tsp { + container transponder{ + uses transponder ; + } + } + case regen { + container regenerator{ + leaf regenerator-id{ + type string ; + } + uses transponder ; + } + } + case pow { + container optical-power{ + leaf optical-power{ + type decimal64 { + fraction-digits 5; + } + units W; + description "hop output (input??) power"; + } + } + } + } + + } + + identity path-metric-type { + description + "Base identity for path metric type"; + } + + identity route-usage-type { + description + "Base identity for route usage"; + } + + identity route-include-ero { + base route-usage-type; + description + "Include ERO from route"; + } + + identity route-exclude-ero { + base route-usage-type; + description + "Exclude ERO from route"; + } + + identity route-exclude-srlg { + base route-usage-type; + description + "Exclude SRLG from route"; + } + + typedef te-hop-type { + type enumeration { + enum LOOSE { + description + "loose hop in an explicit path"; + } + enum STRICT { + description + "strict hop in an explicit path"; + } + } + description + "enumerated type for specifying loose or strict + paths"; + reference "RFC3209: section-4.3.2"; + } + + typedef te-path-disjointness { + type bits { + bit node { + position 0; + description "Node disjoint."; + } + bit link { + position 1; + description "Link disjoint."; + } + bit srlg { + position 2; + description "SRLG (Shared Risk Link Group) disjoint."; + } + } + description + "Type of the resource disjointness for a TE tunnel path."; + reference + "RFC4872: RSVP-TE Extensions in Support of End-to-End + Generalized Multi-Protocol Label Switching (GMPLS) + Recovery"; + } // te-path-disjointness + + typedef te-node-id { + type inet:ip-address; + description + "An identifier for a node in a topology. + The identifier is represented as 32-bit unsigned integer in + the dotted-quad notation. + This attribute is mapped to Router ID in + RFC3630, RFC5329, RFC5305, and RFC6119."; + } + + typedef te-tp-id { + type union { + type uint32; // Unnumbered + type inet:ip-address; // IPv4 or IPv6 address + } + description + "An identifier for a TE link endpoint on a node. + This attribute is mapped to local or remote link identifier in + RFC3630 and RFC5305."; + } + + typedef accumulated-metric-type { + type union { + type uint64; + type decimal64 { + fraction-digits 2; + } + } + description + "type useable for accumulative-value"; + } + + grouping path-route-objects { + description + "List of EROs to be included or excluded when performing + the path computation."; + container explicit-route-objects { + description + "Container for the route object list"; + list route-object-include-exclude { + key index; + description + "List of explicit route objects to include or + exclude in path computation"; + leaf explicit-route-usage { + type identityref { + base route-usage-type; + } + description "Explicit-route usage."; + } + uses explicit-route-hop ; + } + } + } + + grouping generic-path-disjointness { + description "Path disjointness grouping"; + leaf disjointness { + type te-path-disjointness; + description + "The type of resource disjointness. + Under primary path, disjointness level applies to + all secondary LSPs. Under secondary, disjointness + level overrides the one under primary"; + } + } + + grouping common-path-constraints-attributes { + description + "Common path constraints configuration grouping"; + uses common-constraints_config; + } + + grouping generic-path-constraints { + description + "Global named path constraints configuration + grouping"; + container path-constraints { + description "TE named path constraints container"; + uses common-path-constraints-attributes; + } + } + + + grouping explicit-route-hop { + description + "The explicit route subobject grouping"; + leaf index { + type uint32; + description "ERO subobject index"; + } + choice type { + description + "The explicit route subobject type"; + case num-unnum-hop { + container num-unnum-hop { + leaf node-id { + //type te-node-id; + type string; + description + "The identifier of a node in the TE topology."; + } + leaf link-tp-id { + //type te-tp-id; + type string; + description + "TE link termination point identifier. The combination + of TE link ID and the TE node ID is used to identify an + unnumbered TE link."; + } + leaf hop-type { + type te-hop-type; + description "strict or loose hop"; + } + description + "Numbered and Unnumbered link/node explicit route + subobject"; + } + } + case label { + container label-hop { + description "Label hop type"; + uses effective-freq-slot; + } + description + "The Label ERO subobject"; + } + case hop-attribute{ + uses gnpypc:hop-attribute ; + } + } + } + + grouping common-constraints_config { + description + "Common constraints grouping that can be set on + a constraint set or directly on the tunnel"; + + container te-bandwidth { + uses gnpy-specific-parameters ; + description + "A requested bandwidth to use for path computation"; + } + } + + grouping end-points { + description + "Common grouping to define the TE tunnel end-points"; + + leaf source { + type inet:ip-address; + description "TE tunnel source address."; + } + leaf destination { + type inet:ip-address; + description "P2P tunnel destination address"; + } + leaf src-tp-id { + type binary; + description "TE tunnel source termination point identifier."; + } + leaf dst-tp-id { + type binary; + + description "TE tunnel destination termination point +identifier."; + } + } + + grouping synchronization-info { + description "Information for sync"; + list synchronization { + key "synchronization-id"; + description "sync list"; + leaf synchronization-id { + type uint32; + description "index"; + } + container svec { + description + "Synchronization VECtor"; + leaf relaxable { + type boolean; + default true; + description + "If this leaf is true, path computation process is free +to ignore svec content. + otherwise it must take into account this svec."; + } + uses generic-path-disjointness; + leaf-list request-id-number { + type uint32; + description "This list reports the set of M path computation requests that must be synchronized."; + } + } + } + } + + grouping generic-path-properties { + description "TE generic path properties grouping"; + container path-properties { + config false; + description "The TE path properties"; + list path-metric { + key metric-type; + description "TE path metric type"; + leaf metric-type { + type identityref { + base path-metric-type; + } + description "TE path metric type"; + } + leaf accumulative-value { + type decimal64 { + fraction-digits 2; + } + description "TE path metric accumulative value"; + } + } +// container path-route-objects { +// description +// "Container for the list of route objects either returned by +// the computation engine or actually used by an LSP"; +// list path-route-object { +// key index; +// description +// "List of route objects either returned by the computation +// engine or actually used by an LSP"; +// uses explicit-route-hop; +// } +// } + list path-route-objects { + description + "Container for the list of route objects either returned by + the computation engine or actually used by an LSP"; + container path-route-object { + description + "List of route objects either returned by the computation + engine or actually used by an LSP"; + uses explicit-route-hop; + } + } + } + } + + grouping path-info { + uses generic-path-properties; + description "Path computation output information"; + } + +// adding some blocking reasons and info on path in case of blocking + + grouping no-path-info { + description "no-path-info"; + container no-path { + presence "Response without path information, due to failure + performing the path computation"; + leaf no-path { + type string; + mandatory true ; + description + "returned blocking reasons: + NO_PATH + NO_COMPUTED_SNR + NO_FEASIBLE_BAUDRATE_WITH_SPACING + NO_PATH_WITH_CONSTRAINT + NO_FEASIBLE_MODE + MODE_NOT_FEASIBLE + NO_SPECTRUM + "; + } + uses generic-path-properties ; + description "if path computation cannot identify a path, + rpc returns no path."; + } + } + + /* TODO : correct the following with good trees: + * te:tunnels-rpc/te:input/te:tunnel-info + * te:tunnels-rpc/te:output/te:result + */ + grouping service { + list path-request { + key "request-id"; + description "request-list"; + leaf request-id { + type uint32; + mandatory true; + description "Each path computation request is uniquely identified by the request-id-number."; + } + + uses end-points; + uses path-route-objects; + uses generic-path-constraints; + } + uses synchronization-info; + } + + grouping result { + list response { + key response-id; + config false; + description "response"; + leaf response-id { + type uint32; + description + "The list key that has to reuse request-id-number."; + } + choice response-type { + config false; + description "response-type"; + case no-path-case { + uses no-path-info; + } + case path-case { + uses path-info; + description "Path computation service."; + } + } + } + } + container result { + uses result; + description + "Describe the service file to connect to gnpy"; + } +} diff --git a/common/pom.xml b/common/pom.xml index 17f0ecd22..38dbb864b 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -8,9 +8,9 @@ 4.0.0 - org.opendaylight.odlparent - bundle-parent - 4.0.10 + org.opendaylight.mdsal + binding-parent + 3.0.8 @@ -75,6 +75,21 @@ ${project.version} + + org.opendaylight.controller + sal-binding-broker-impl + + + + org.opendaylight.yangtools + yang-data-codec-xml + + + + org.opendaylight.yangtools + yang-data-codec-gson + + junit diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java b/common/src/main/java/org/opendaylight/transportpce/common/DataStoreContext.java similarity index 95% rename from test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java rename to common/src/main/java/org/opendaylight/transportpce/common/DataStoreContext.java index 112351240..b6eaf86c1 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContext.java +++ b/common/src/main/java/org/opendaylight/transportpce/common/DataStoreContext.java @@ -5,7 +5,7 @@ * 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.test.common; +package org.opendaylight.transportpce.common; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java b/common/src/main/java/org/opendaylight/transportpce/common/DataStoreContextImpl.java similarity index 99% rename from test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java rename to common/src/main/java/org/opendaylight/transportpce/common/DataStoreContextImpl.java index 2b7a4d27b..2b470112f 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/test/common/DataStoreContextImpl.java +++ b/common/src/main/java/org/opendaylight/transportpce/common/DataStoreContextImpl.java @@ -5,7 +5,7 @@ * 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.test.common; +package org.opendaylight.transportpce.common; import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.ImmutableMap; diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java b/common/src/main/java/org/opendaylight/transportpce/common/converter/AbstractDataObjectConverter.java similarity index 97% rename from test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java rename to common/src/main/java/org/opendaylight/transportpce/common/converter/AbstractDataObjectConverter.java index 6a44ebfe8..924dad513 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/AbstractDataObjectConverter.java +++ b/common/src/main/java/org/opendaylight/transportpce/common/converter/AbstractDataObjectConverter.java @@ -5,7 +5,7 @@ * 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.binding.converter; +package org.opendaylight.transportpce.common.converter; import com.google.common.base.Preconditions; import java.util.Map; @@ -13,7 +13,7 @@ import java.util.Map.Entry; import java.util.Optional; import javax.annotation.Nonnull; import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter; +import org.opendaylight.transportpce.common.converter.api.DataObjectConverter; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java b/common/src/main/java/org/opendaylight/transportpce/common/converter/JSONDataObjectConverter.java similarity index 96% rename from test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java rename to common/src/main/java/org/opendaylight/transportpce/common/converter/JSONDataObjectConverter.java index c0fc3256f..8e992b707 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/JSONDataObjectConverter.java +++ b/common/src/main/java/org/opendaylight/transportpce/common/converter/JSONDataObjectConverter.java @@ -5,7 +5,7 @@ * 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.binding.converter; +package org.opendaylight.transportpce.common.converter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; @@ -18,8 +18,8 @@ import java.io.Writer; import java.util.Optional; import javax.annotation.Nonnull; import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry; -import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter; -import org.opendaylight.transportpce.test.common.DataStoreContext; +import org.opendaylight.transportpce.common.DataStoreContext; +import org.opendaylight.transportpce.common.converter.api.DataObjectConverter; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java b/common/src/main/java/org/opendaylight/transportpce/common/converter/XMLDataObjectConverter.java similarity index 98% rename from test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java rename to common/src/main/java/org/opendaylight/transportpce/common/converter/XMLDataObjectConverter.java index 40c8420ed..5afbb4075 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/XMLDataObjectConverter.java +++ b/common/src/main/java/org/opendaylight/transportpce/common/converter/XMLDataObjectConverter.java @@ -5,7 +5,7 @@ * 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.binding.converter; +package org.opendaylight.transportpce.common.converter; import java.io.IOException; import java.io.InputStream; @@ -24,7 +24,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.transportpce.test.common.DataStoreContext; +import org.opendaylight.transportpce.common.DataStoreContext; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java b/common/src/main/java/org/opendaylight/transportpce/common/converter/api/DataObjectConverter.java similarity index 98% rename from test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java rename to common/src/main/java/org/opendaylight/transportpce/common/converter/api/DataObjectConverter.java index d70606f1d..fcd2bda63 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/binding/converter/api/DataObjectConverter.java +++ b/common/src/main/java/org/opendaylight/transportpce/common/converter/api/DataObjectConverter.java @@ -5,7 +5,7 @@ * 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.binding.converter.api; +package org.opendaylight.transportpce.common.converter.api; import java.io.InputStream; import java.io.Reader; diff --git a/pce/pom.xml b/pce/pom.xml index 8dd6f3abe..b0f5c056c 100644 --- a/pce/pom.xml +++ b/pce/pom.xml @@ -15,9 +15,9 @@ Author: Martial Coulibaly on behalf of Orange 4.0.0 - org.opendaylight.odlparent - bundle-parent - 4.0.10 + org.opendaylight.mdsal + binding-parent + 3.0.8 @@ -55,6 +55,11 @@ Author: Martial Coulibaly on behalf of Orange transportpce-networkmodel ${project.version} + + ${project.groupId} + transportpce-common + ${project.version} + org.opendaylight.controller.thirdparty net.sf.jung2 @@ -72,6 +77,7 @@ Author: Martial Coulibaly on behalf of Orange mockito-core test + ${project.groupId} test-common @@ -84,7 +90,10 @@ Author: Martial Coulibaly on behalf of Orange 1.9.2-SNAPSHOT test - + + org.opendaylight.mdsal + mdsal-binding-dom-codec + diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/PceGraph.java b/pce/src/main/java/org/opendaylight/transportpce/pce/PceGraph.java index 390a7ddb7..89013ca26 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/PceGraph.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/PceGraph.java @@ -158,25 +158,17 @@ public class PceGraph { private boolean populateGraph(Map allNodes) { cleanupGraph(); - Iterator> nodes = allNodes.entrySet().iterator(); while (nodes.hasNext()) { - Map.Entry node = nodes.next(); - PceNode pcenode = node.getValue(); List links = pcenode.getOutgoingLinks(); - LOG.info("In populateGraph: use node for graph {}", pcenode.toString()); - for (PceLink link : links) { LOG.info("In populateGraph: add edge to graph {}", link.toString()); addLinkToGraph(link); - } - } - return true; } @@ -186,13 +178,10 @@ public class PceGraph { for (PceNode node : allNodes) { List links = node.getOutgoingLinks(); - LOG.debug("In populateGraph: use node for graph {}", node.toString()); - for (PceLink link : links) { LOG.debug("In populateGraph: add edge to graph {}", link.toString()); addLinkToGraph(link); - } } 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 324b02260..bada4cb4b 100644 --- a/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/PceSendingPceRPCs.java @@ -8,13 +8,28 @@ package org.opendaylight.transportpce.pce; +import java.util.List; + import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.transportpce.pce.PceResult.LocalCause; +import org.opendaylight.transportpce.pce.gnpy.ConnectToGnpyServer; +import org.opendaylight.transportpce.pce.gnpy.ExtractTopoDataStoreImpl; +import org.opendaylight.transportpce.pce.gnpy.GnpyResult; +import org.opendaylight.transportpce.pce.gnpy.ServiceDataStoreOperationsImpl; +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.rev190502.service.PathRequest; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.synchronization.info.Synchronization; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.PathComputationRequestInput; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.service.path.rpc.result.PathDescriptionBuilder; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.AToZDirection; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ZToADirection; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.RoutingConstraintsSp.PceMetric; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,16 +53,14 @@ public class PceSendingPceRPCs { * false cancelresourcereserve . */ private PathDescriptionBuilder pathDescription; - private PathComputationRequestInput input; private DataBroker dataBroker; - private PceConstraints pceHardConstraints = new PceConstraints(); private PceConstraints pceSoftConstraints = new PceConstraints(); + private Long gnpyRequestId = new Long(0); public PceSendingPceRPCs() { setPathDescription(null); - this.input = null; this.dataBroker = null; } @@ -70,80 +83,135 @@ public class PceSendingPceRPCs { LOG.info("cancelResourceReserve ..."); } - public void pathComputation() { + public void pathComputation() throws Exception { + // Comput the path according to the constraints of PCE + rc = pathComputationPCE(); + + LOG.info("setPathDescription ..."); + AToZDirection atoz = rc.getAtoZDirection(); + ZToADirection ztoa = rc.getZtoADirection(); + ConnectToGnpyServer connectToGnpy = new ConnectToGnpyServer(); + if ((atoz == null) || (atoz.getAToZ() == null)) { + rc.setRC("400"); + LOG.warn("In PCE pathComputation: empty atoz path after description: result = {}", rc.toString()); + return; + } else { + // Send the computed path A-to-Z to GNPY tool + if (connectToGnpy.isGnpyURLExist()) { + ExtractTopoDataStoreImpl xtrTopo = new ExtractTopoDataStoreImpl(dataBroker, input, atoz, gnpyRequestId); + gnpyRequestId++; + List elementsList1 = xtrTopo.getElements(); + List connectionsList1 = xtrTopo.getConnections(); + List pathRequestList1 = xtrTopo.getPathRequest(); + List synchronizationList1 = xtrTopo.getSynchronization(); + String gnpyResponse1 = getGnpyResponse(elementsList1, connectionsList1, pathRequestList1, + synchronizationList1); + // Analyze the response + if (gnpyResponse1 != null) { + GnpyResult gnpyResult = new GnpyResult(gnpyResponse1); + LOG.debug("GNPy result created"); + gnpyResult.analyzeResult(); + } else { + LOG.error("No response from the GNPy server"); + } + } + } + + if ((ztoa == null) || (ztoa.getZToA() == null)) { + rc.setRC("400"); + LOG.error("In pathComputation empty ztoa path after description: result = {}", rc.toString()); + return; + } else { + // Send the computed path Z-to-A to GNPY tool + if (connectToGnpy.isGnpyURLExist()) { + ExtractTopoDataStoreImpl xtrTopo = new ExtractTopoDataStoreImpl(dataBroker, input, ztoa, gnpyRequestId); + gnpyRequestId++; + List elementsList2 = xtrTopo.getElements(); + List connectionsList2 = xtrTopo.getConnections(); + List pathRequestList2 = xtrTopo.getPathRequest(); + List synchronizationList2 = xtrTopo.getSynchronization(); + String gnpyResponse2 = getGnpyResponse(elementsList2, connectionsList2, pathRequestList2, + synchronizationList2); + // Analyze the response + if (gnpyResponse2 != null) { + GnpyResult gnpyResult = new GnpyResult(gnpyResponse2); + LOG.debug("GNPy result created"); + gnpyResult.analyzeResult(); + } else { + LOG.info("No response from the GNPy server"); + } + } + } + // Set the description of the path + setPathDescription(new PathDescriptionBuilder().setAToZDirection(atoz).setZToADirection(ztoa)); + LOG.info("In pathComputation Graph is Found"); + } + + public PceResult pathComputationPCE() { LOG.info("PathComputation ..."); PceConstraintsCalc constraints = new PceConstraintsCalc(input, dataBroker); pceHardConstraints = constraints.getPceHardConstraints(); pceSoftConstraints = constraints.getPceSoftConstraints(); - LOG.info("nwAnalizer ..."); - PceCalculation nwAnalizer = new PceCalculation(input, dataBroker, - pceHardConstraints, pceSoftConstraints, rc); + PceCalculation nwAnalizer = new PceCalculation(input, dataBroker, pceHardConstraints, pceSoftConstraints, rc); nwAnalizer.calcPath(); rc = nwAnalizer.getReturnStructure(); if (!rc.getStatus()) { LOG.error("In pathComputation nwAnalizer: result = {}", rc.toString()); - return; + return null; } LOG.info("PceGraph ..."); LOG.warn("PathComputation: aPceNode '{}' - zPceNode '{}'", nwAnalizer.getaPceNode(), nwAnalizer.getzPceNode()); - PceGraph graph = new PceGraph( - nwAnalizer.getaPceNode(), - nwAnalizer.getzPceNode(), - nwAnalizer.getAllPceNodes(), + PceGraph graph = new PceGraph(nwAnalizer.getaPceNode(), nwAnalizer.getzPceNode(), nwAnalizer.getAllPceNodes(), pceHardConstraints, pceSoftConstraints, rc); graph.calcPath(); rc = graph.getReturnStructure(); if (!rc.getStatus()) { - LOG.warn("In pathComputation : Graph return without Path "); - // TODO fix. This is quick workaround for algorithm problem if ((rc.getLocalCause() == LocalCause.TOO_HIGH_LATENCY) - && (pceHardConstraints.getPceMetrics() == PceMetric.HopCount) - && (pceHardConstraints.getMaxLatency() != -1)) { - + && (pceHardConstraints.getPceMetrics() == PceMetric.HopCount) + && (pceHardConstraints.getMaxLatency() != -1)) { pceHardConstraints.setPceMetrics(PceMetric.PropagationDelay); graph = patchRerunGraph(graph); } - if (!rc.getStatus()) { LOG.error("In pathComputation graph.calcPath: result = {}", rc.toString()); - return; + return null; } } LOG.info("PcePathDescription ..."); - PcePathDescription description = new PcePathDescription( - graph.getPathAtoZ(), - nwAnalizer.getAllPceLinks(), rc); + PcePathDescription description = new PcePathDescription(graph.getPathAtoZ(), nwAnalizer.getAllPceLinks(), rc); description.buildDescriptions(); rc = description.getReturnStructure(); if (!rc.getStatus()) { LOG.error("In pathComputation description: result = {}", rc.toString()); - return; + return null; } + return rc; + } - LOG.info("setPathDescription ..."); - AToZDirection atoz = rc.getAtoZDirection(); - ZToADirection ztoa = rc.getZtoADirection(); - if ((atoz == null) || (atoz.getAToZ() == null)) { - rc.setRC("400"); - LOG.error("In pathComputation empty atoz path after description: result = {}", rc.toString()); - return; - } - if ((ztoa == null) || (ztoa.getZToA() == null)) { - rc.setRC("400"); - LOG.error("In pathComputation empty ztoa path after description: result = {}", rc.toString()); - return; - } - setPathDescription(new PathDescriptionBuilder() - .setAToZDirection(atoz) - .setZToADirection(ztoa)); - LOG.info("In pathComputation Graph is Found"); + private String getGnpyResponse(List elementsList, List connectionsList, + List pathRequestList, List synchronizationList) throws Exception { + GnpyApi gnpyApi = new GnpyApiBuilder() + .setTopologyFile( + new TopologyFileBuilder().setElements(elementsList).setConnections(connectionsList).build()) + .setServiceFile(new ServiceFileBuilder().setPathRequest(pathRequestList).build()).build(); + InstanceIdentifier idGnpyApi = InstanceIdentifier.builder(GnpyApi.class).build(); + String gnpyJson; + ServiceDataStoreOperationsImpl sd = new ServiceDataStoreOperationsImpl(dataBroker); + gnpyJson = sd.createJsonStringFromDataObject(idGnpyApi, gnpyApi); + 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:", ""); + //sd.writeStringFile(gnpyJsonModified); + String gnpyResponse = connect.gnpyCnx(gnpyJsonModified); + return gnpyResponse; } private PceGraph patchRerunGraph(PceGraph graph) { 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 new file mode 100644 index 000000000..6a6a0d886 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ConnectToGnpyServer.java @@ -0,0 +1,111 @@ +/* + * 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.MalformedURLException; +import java.net.URL; +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:5000/gnpy/api/v1.0/files"; + + public String gnpyCnx(String jsonTxt) { + String jsonRespTxt = null; + try { + URL url = new URL(URL_GNPY); + String userCredentials = "gnpy:gnpy"; + String basicAuth = "Basic " + new String(java.util.Base64.getEncoder().encode(userCredentials.getBytes())); + + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Authorization", basicAuth); + conn.setRequestProperty("Content-Type", "application/json"); + + // Send the request to the GNPy + OutputStream os = conn.getOutputStream(); + os.write(jsonTxt.getBytes()); + os.flush(); + if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) { + throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); + } + InputStreamReader response = new InputStreamReader((conn.getInputStream())); + if (response != null) { + jsonRespTxt = null; + try { + jsonRespTxt = CharStreams.toString(response); + } catch (IOException e1) { + LOG.warn("Could not read characters of GNPy response: {}", e1.getMessage()); + } + } + conn.disconnect(); + } catch (MalformedURLException e) { + LOG.warn("Exception : Malformed GNPy URL"); + } catch (IOException e) { + LOG.warn("IOException when connecting to GNPy server: {}", e.getMessage()); + } + return jsonRespTxt; + } + + public boolean isGnpyURLExist() { + boolean exist = false; + try { + URL url = new URL(URL_GNPY); + String userCredentials = "gnpy:gnpy"; + String basicAuth = "Basic " + new String(java.util.Base64.getEncoder().encode(userCredentials.getBytes())); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("HEAD"); + conn.setRequestProperty("Authorization", basicAuth); + conn.setRequestProperty("Content-Type", "application/json"); + conn.connect(); + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + exist = true; + } + conn.disconnect(); + } + catch (IOException e) { + LOG.warn("Could not connect to GNPy server"); + } + return exist; + } + + public String readResponse(InputStreamReader response) { + 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) { + LOG.warn("IOException when reading GNPy response: {}", e.getMessage()); + } + return output; + } +} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ExtractTopoDataStoreImpl.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ExtractTopoDataStoreImpl.java new file mode 100644 index 000000000..31417baf8 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ExtractTopoDataStoreImpl.java @@ -0,0 +1,854 @@ +/* + * Copyright © 2018 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 java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.stream.IntStream; + +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.transportpce.common.NetworkUtils; +//import org.opendaylight.yang.gen.v1.gnpy.gnpy.eqpt.config.rev181119.EdfaVariety; +//import org.opendaylight.yang.gen.v1.gnpy.gnpy.eqpt.config.rev181119.FiberVariety; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Coordinate; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Km; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.edfa.params.Operational; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.edfa.params.OperationalBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.Edfa; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.EdfaBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.FiberRoadmBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.Transceiver; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.TransceiverBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.Params; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.ParamsBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.Fiber; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.FiberBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.Roadm; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.element.type.choice.element.type.fiberroadm.params.fiberroadm.RoadmBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.location.attributes.Location; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.location.attributes.LocationBuilder; +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.ConnectionsBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.Elements; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.ElementsBuilder; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.elements.Metadata; +import org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.topo.elements.MetadataBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.RouteIncludeEro; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.TeHopType; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.TeNodeId; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.TePathDisjointness; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.TeTpId; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.common.constraints_config.TeBandwidth; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.common.constraints_config.TeBandwidthBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.Type; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type.NumUnnumHopBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type.num.unnum.hop.NumUnnumHop; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.constraints.PathConstraints; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.constraints.PathConstraintsBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.gnpy.specific.parameters.EffectiveFreqSlot; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.gnpy.specific.parameters.EffectiveFreqSlotBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.path.route.objects.ExplicitRouteObjects; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.path.route.objects.ExplicitRouteObjectsBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.path.route.objects.explicit.route.objects.RouteObjectIncludeExclude; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.path.route.objects.explicit.route.objects.RouteObjectIncludeExcludeBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.service.PathRequest; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.service.PathRequestBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.synchronization.info.Synchronization; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.synchronization.info.SynchronizationBuilder; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.synchronization.info.synchronization.Svec; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.synchronization.info.synchronization.SvecBuilder; +import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.PathComputationRequestInput; +import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.amplified.link.attributes.AmplifiedLink; +import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.amplified.link.attributes.amplified.link.section.element.section.element.Span; +import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.amplified.link.attributes.amplified.link.section.element.section.element.ila.Ila; +import org.opendaylight.yang.gen.v1.http.org.openroadm.link.rev181130.span.attributes.LinkConcatenation; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev181130.Node1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.Link1; +import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130.networks.network.link.OMSAttributes; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.AToZDirection; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ZToADirection; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.atoz.direction.AToZ; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.ztoa.direction.ZToA; +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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.Node; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.network.node.SupportingNode; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.Network1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.networks.network.Link; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to create the topology corresponding to GNPy requirements. + * + * @author Ahmed Triki ( ahmed.triki@orange.com ) + * + */ + +public class ExtractTopoDataStoreImpl { + private static final Logger LOG = LoggerFactory.getLogger(ExtractTopoDataStoreImpl.class); + private final DataBroker dataBroker; + // private final OpenRoadmTopology openRoadmTopology; + // private final OpenRoadmInterfaces openRoadmInterfaces; + private List elements = new ArrayList<>(); + private List connections = new ArrayList<>(); + private List pathRequest = new ArrayList<>(); + private List synchronization = new ArrayList<>(); + private Map mapDisgNodeRefNode = new HashMap(); + private Map mapNodeRefIp = new HashMap(); + private Map mapLinkFiber = new HashMap(); + private Map mapFiberIp = new HashMap(); + private static int convertKmM = 1000; + + /* + * Construct the ExtractTopoDataStoreImpl. + */ + @SuppressWarnings("unchecked") + public ExtractTopoDataStoreImpl(final DataBroker dataBroker, PathComputationRequestInput input, AToZDirection atoz, + Long requestId) { + this.dataBroker = dataBroker; + Map> map = extractTopo(); + if (map.containsKey("Elements")) { + elements = (List) map.get("Elements"); + } else { + elements = null; + } + if (map.containsKey("Elements")) { + connections = (List) map.get("Connections"); + } else { + connections = null; + } + pathRequest = extractPathRequest(input, atoz, requestId); + synchronization = extractSynchronization(requestId); + } + + public ExtractTopoDataStoreImpl(final DataBroker dataBroker, PathComputationRequestInput input, ZToADirection ztoa, + Long requestId) { + this.dataBroker = dataBroker; + Map> map = extractTopo(); + if (map.containsKey("Elements")) { + elements = (List) map.get("Elements"); + } else { + elements = null; + } + if (map.containsKey("Elements")) { + connections = (List) map.get("Connections"); + } else { + connections = null; + } + pathRequest = extractPathRequest(input, ztoa, requestId); + synchronization = extractSynchronization(requestId); + } + + /* + * extract the topology: all the elements have ipAddress as uid and maintain + * a mapping structure to map between the nodeId and the ipAddress (uid) + * + */ + public Map> extractTopo() { + Map> map = new HashMap>(); + // Define the elements + List topoElements = new ArrayList<>(); + // Define the connections + List topoConnections = new ArrayList<>(); + // Define the instance identifier of the OpenRoadm topology + InstanceIdentifier insIdOpenRoadmTopo = InstanceIdentifier + .builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build(); + // Define the instance identifier of the OpenRoadm network + InstanceIdentifier insIdrOpenRoadmNet = InstanceIdentifier + .builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID))).build(); + ReadOnlyTransaction readOnlyTransaction = this.dataBroker.newReadOnlyTransaction(); + // Read the data broker + try { + // Initialize the reading of the data broker + // read the configuration part of the data broker that concerns + // the openRoadm topology and get all the nodes + java.util.Optional openRoadmTopo = readOnlyTransaction + .read(LogicalDatastoreType.CONFIGURATION, insIdOpenRoadmTopo).get().toJavaUtil(); + java.util.Optional openRoadmNet = readOnlyTransaction + .read(LogicalDatastoreType.CONFIGURATION, insIdrOpenRoadmNet).get().toJavaUtil(); + if (openRoadmNet.isPresent()) { + List openRoadmNetNodeList = openRoadmNet.get().getNode(); + if (openRoadmTopo.isPresent()) { + List openRoadmTopoNodeList = openRoadmTopo.get().getNode(); + List nodesList = new ArrayList<>(); + // Create the list of nodes + if (!openRoadmTopoNodeList.isEmpty()) { + // Create elements + for (Node openRoadmTopoNode : openRoadmTopoNodeList) { + // Retrieve the supporting node and the type of the + // node in openRoadm network + List supportingNodeList = openRoadmTopoNode.getSupportingNode(); + for (SupportingNode supportingNode : supportingNodeList) { + String nodeRef = supportingNode.getNodeRef().getValue(); + IpAddress ipAddress = null; + // Retrieve the mapping between the openRoadm + // topology and openRoadm network + mapDisgNodeRefNode.put(openRoadmTopoNode.getNodeId().getValue(), nodeRef); + Node1 openRoadmNetNode1 = null; + for (Node openRoadmNetNode : openRoadmNetNodeList) { + if (openRoadmNetNode.getNodeId().getValue().equals(nodeRef)) { + openRoadmNetNode1 = openRoadmNetNode.augmentation(Node1.class); + ipAddress = openRoadmNetNode1.getIp(); + mapNodeRefIp.put(nodeRef, ipAddress); + break; + } + } + if (openRoadmNetNode1.getNodeType().getName().equals("ROADM")) { + if (!nodesList.contains(nodeRef)) { + Elements element = addElementsRoadm(2, 0, nodeRef, openRoadmNetNode1.getShelf(), + -20, ipAddress.getIpv4Address().getValue().toString()); + topoElements.add(element); + nodesList.add(nodeRef); + } + } else if (openRoadmNetNode1.getNodeType().getName().equals("XPONDER")) { + if (!nodesList.contains(nodeRef)) { + Elements element = addElementsTransceiver(2, 0, nodeRef, + openRoadmNetNode1.getShelf(), + ipAddress.getIpv4Address().getValue().toString()); + topoElements.add(element); + nodesList.add(nodeRef); + } + } else { + LOG.warn("the type is not implemented"); + } + } + } + } else { + LOG.warn("no nodes in the network"); + } + + // Create the list of connections + Network1 nw1 = openRoadmTopo.get().augmentation(Network1.class); + List linksList = nw1.getLink(); + // 1:EXPRESS-LINK ; 2:ADD-LINK ; 3:DROP-LINK ; + // 4:ROADM-To-ROADM ; 5:XPONDER-INPUT ; 6:XPONDER-OUTPUT + int[] externalLink = {4,5,6}; + int idFiber = 0; + int nbEDFA = 0; + if (!linksList.isEmpty()) { + LOG.warn("The link list is not empty"); + for (Link link : linksList) { + Link1 link1 = link.augmentation(Link1.class); + int linkType = link1.getLinkType().getIntValue(); + if (IntStream.of(externalLink).anyMatch(x -> x == linkType)) { + // Verify if the node is a ROADM + String srcId = mapDisgNodeRefNode.get(link.getSource().getSourceNode().getValue()); + IpAddress srcIp = mapNodeRefIp.get(srcId); + String destId = null; + IpAddress destIp = null; + // Add the links between amplifiers + OMSAttributes omsAttributes = link1.getOMSAttributes(); + if (omsAttributes != null) { + if (omsAttributes.getAmplifiedLink() != null) { + List amplifiedLinkList = omsAttributes.getAmplifiedLink() + .getAmplifiedLink(); + if (!amplifiedLinkList.isEmpty()) { + for (AmplifiedLink amplifiedLink : amplifiedLinkList) { + Elements element1 = null; + if (amplifiedLink.getSectionElement() + .getSectionElement() instanceof Ila) { + Ila ila = (Ila) amplifiedLink.getSectionElement() + .getSectionElement(); + String nodeId = ila.getNodeId().getValue(); + IpAddress ipEdfa = new IpAddress( + new Ipv4Address("1.1.1." + nbEDFA)); + nbEDFA++; + mapDisgNodeRefNode.put(nodeId, nodeId); + mapNodeRefIp.put(nodeId, ipEdfa); + // class std_medium_gain + // implements EdfaVariety {} + element1 = addElementsEdfa(2, 0, "RLD", "Lannion_CAS", + ila.getGain().getValue(), ila.getTilt().getValue(), + ila.getOutVoaAtt().getValue(), "std_medium_gain", + ipEdfa.getIpv4Address().getValue().toString()); + } else if (amplifiedLink.getSectionElement() + .getSectionElement() instanceof Span) { + // Create the location + Span span = (Span) amplifiedLink.getSectionElement() + .getSectionElement(); + String clfi = span.getSpan().getClfi(); + IpAddress ipFiber = new IpAddress( + new Ipv4Address("2.2.2." + idFiber)); + mapLinkFiber.put(link.getLinkId().getValue(), clfi); + mapFiberIp.put(clfi, ipFiber); + idFiber++; + // class SSMF implements + // FiberVariety {} + element1 = addElementsFiber(2, 0, "RLD", "Lannion_CAS", + ipFiber.getIpv4Address().getValue(), 20, 0, 0.2, 0, 0, + "SSMF"); + } + if (element1 != null) { + topoElements.add(element1); + destId = element1.getUid(); + destIp = null; + // Create a new link + if (srcId != destId) { + Connections connection = createNewConnection(srcId, srcIp, + destId, destIp); + topoConnections.add(connection); + srcId = destId; + srcIp = destIp; + } + } + } + } + } else if (omsAttributes.getSpan() != null) { + org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev181130 + .networks.network.link.oms.attributes.@Nullable Span span + = omsAttributes.getSpan(); + + String clfi = span.getClfi(); + IpAddress ipFiber = new IpAddress(new Ipv4Address("2.2.2." + idFiber)); + mapLinkFiber.put(link.getLinkId().getValue(), clfi); + mapFiberIp.put(clfi, ipFiber); + idFiber++; + + double attIn = span.getSpanlossCurrent().getValue().doubleValue(); + double lossCoef = 0.2; + double connIn = 0; + double connOut = 0; + String typeVariety = "SSMF"; + + double length = 0; //convert to kilometer + // Compute the length of the link + List linkConcatenationList = span.getLinkConcatenation(); + for (LinkConcatenation linkConcatenation : linkConcatenationList) { + double srlgLength = linkConcatenation.getSRLGLength(); + length += srlgLength / convertKmM; //convert to kilometer + } + + Elements element1 = addElementsFiber(2, 0, "RLD", "Lannion_CAS", + ipFiber.getIpv4Address().getValue(), length, attIn, lossCoef, connIn, + connOut, typeVariety); + + topoElements.add(element1); + // Create a new link + destId = element1.getUid(); + destIp = null; + if (srcId != destId) { + Connections connection = createNewConnection(srcId, srcIp, destId, destIp); + topoConnections.add(connection); + srcId = destId; + srcIp = destIp; + } + } else { + // Add a fiber + String clfi = "Fiber" + idFiber; + IpAddress ipFiber = new IpAddress(new Ipv4Address("2.2.2." + idFiber)); + mapLinkFiber.put(link.getLinkId().getValue(), clfi); + mapFiberIp.put(clfi, ipFiber); + idFiber++; + // Create a new element + // class SSMF implements FiberVariety {} + Elements element1 = addElementsFiber(2, 0, "RLD", "Lannion_CAS", + ipFiber.getIpv4Address().getValue(), 20, 0, 0.2, 0, 0, "SSMF"); + topoElements.add(element1); + // Create a new link + destId = element1.getUid(); + destIp = null; + if (srcId != destId) { + Connections connection = createNewConnection(srcId, srcIp, destId, destIp); + topoConnections.add(connection); + srcId = destId; + srcIp = destIp; + } + } + } else { + LOG.warn("The oms attributes is null!"); + } + // Create a new link + destId = mapDisgNodeRefNode.get(link.getDestination().getDestNode().getValue()); + destIp = mapNodeRefIp.get(destId); + Connections connection = createNewConnection(srcId, srcIp, destId, destIp); + topoConnections.add(connection); + } + } + } else { + LOG.warn("no links in the network"); + } + } else { + LOG.warn("No nodes in the selected network ..."); + } + } + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error reading the topology", e); + readOnlyTransaction.close(); + } + readOnlyTransaction.close(); + map.put("Elements", topoElements); + map.put("Connections", topoConnections); + return map; + } + + /* + * Create the pathRequest + */ + public List extractPathRequest(PathComputationRequestInput input, AToZDirection atoz, Long requestId) { + // List of A to Z + List listAtoZ = atoz.getAToZ(); + int atozSize = listAtoZ.size(); + // String modulationFormat = atoz.getModulationFormat(); + // Create the path request + List pathRequestList = new ArrayList<>(); + // Define the instance identifier + // InstanceIdentifier nwInstanceIdentifier = InstanceIdentifier + // .builder(Network.class, new NetworkKey(new + // NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build(); + + // read the configuration part of the data broker that concerns the + // nodes ID and get all the nodes + // java.util.Optional networkObject = readOnlyTransaction + // .read(LogicalDatastoreType.CONFIGURATION, + // nwInstanceIdentifier).get().toJavaUtil(); + // 1.1 Create explicitRouteObjects + // 1.1.1. create RouteObjectIncludeExclude list + List routeObjectIncludeExcludes = new ArrayList<>(); + IpAddress ipAddressCurrent = null; + Long index = (long) 0; + //ReadOnlyTransaction readOnlyTransaction = this.dataBroker.newReadOnlyTransaction(); + for (int i = 0; i < atozSize; i++) { + // String idAtoZ = listAtoZ.get(i).getId(); + String nodeId = null; + if (listAtoZ.get(i).getResource() + .getResource() instanceof org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface + .pathdescription.rev171017.pce.resource.resource.resource.Node) { + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce + .resource.resource.resource.Node node = (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c + ._interface.pathdescription.rev171017.pce.resource.resource.resource.Node) listAtoZ + .get(i).getResource().getResource(); + nodeId = node.getNodeId(); + if (nodeId != null) { + String nodeRef = mapDisgNodeRefNode.get(nodeId); + IpAddress ipAddress = mapNodeRefIp.get(nodeRef); + for (Elements element : elements) { + if (element.getUid().contains(ipAddress.getIpv4Address().getValue().toString())) { + String type = element.getType().getName(); + if ((ipAddressCurrent == null) || (ipAddressCurrent != ipAddress)) { + ipAddressCurrent = ipAddress; + // Fill in routeObjectIncludeExcludes + RouteObjectIncludeExclude routeObjectIncludeExclude1 = addRouteObjectIncludeExclude( + ipAddress, 1, index); + routeObjectIncludeExcludes.add(routeObjectIncludeExclude1); + index++; + } + break; + } + } + } else { + LOG.warn("node ID is null"); + } + } else if (listAtoZ.get(i).getResource() + .getResource() instanceof org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface + .pathdescription.rev171017.pce.resource.resource.resource.TerminationPoint) { + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce + .resource.resource.resource.TerminationPoint tp = (org.opendaylight.yang.gen.v1.http.org + .transportpce.b.c._interface.pathdescription.rev171017.pce.resource.resource.resource + .TerminationPoint) listAtoZ.get(i).getResource().getResource(); + // Not used in this version + } else if (listAtoZ.get(i).getResource() + .getResource() instanceof org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface + .pathdescription.rev171017.pce.resource.resource.resource.Link) { + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce + .resource.resource.resource.Link link = (org.opendaylight.yang.gen.v1.http.org.transportpce + .b.c._interface.pathdescription.rev171017.pce.resource.resource.resource.Link) listAtoZ + .get(i).getResource().getResource(); + String clfi = mapLinkFiber.get(link.getLinkId()); + IpAddress fiberIp = mapFiberIp.get(clfi); + if (clfi != null) { + RouteObjectIncludeExclude routeObjectIncludeExclude1 = addRouteObjectIncludeExclude(fiberIp, 1, + index); + routeObjectIncludeExcludes.add(routeObjectIncludeExclude1); + index++; + } + } + } + // Create ExplicitRouteObjects + ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder() + .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build(); + + // 1. Create the path request element 1 + // Find parameters + // String serviceName = input.getServiceName(); + String sourceNode = input.getServiceAEnd().getNodeId(); + String destNode = input.getServiceZEnd().getNodeId(); + + // 1.2 Create a path constraints + Long rate = atoz.getRate(); + // Long wavelengthNumber = atoz.getAToZWavelengthNumber(); + // Create EffectiveFreqSlot + List effectiveFreqSlot = new ArrayList<>(); + EffectiveFreqSlot effectiveFreqSlot1 = new EffectiveFreqSlotBuilder().setM(5).setN(8).build(); + effectiveFreqSlot.add(effectiveFreqSlot1); + // Create Te-Bandwidth + TeBandwidth teBandwidth = new TeBandwidthBuilder().setPathBandwidth(new BigDecimal(rate)) + .setTechnology("flexi-grid").setTrxType("openroadm-beta1").setTrxMode("W100G") + .setEffectiveFreqSlot(effectiveFreqSlot).setSpacing(new BigDecimal(50000000000.0)).build(); + // .setMaxNbOfChannel(new Long(80)).setOutputPower(new + // BigDecimal(0.0012589254117941673)) + PathConstraints pathConstraints = new PathConstraintsBuilder().setTeBandwidth(teBandwidth).build(); + // PathRequest pathRequest1 = new + // PathRequestBuilder().setRequestId(new + // Long(0)).setSource(mapNodeRefIp.get(sourceNode)) + // .setDestination(mapNodeRefIp.get(destNode)).setSrcTpId(input.getServiceAEnd().getTxDirection() + // .getPort().getPortName().getBytes()) + // .setDstTpId(input.getServiceAEnd().getRxDirection().getPort().getPortName().getBytes()) + // .setPathConstraints(pathConstraints) + // .setExplicitRouteObjects(explicitRouteObjects).build(); + PathRequest pathRequest1 = new PathRequestBuilder().setRequestId(requestId) + .setSource(mapNodeRefIp.get(sourceNode)).setDestination(mapNodeRefIp.get(destNode)) + .setSrcTpId("srcTpId".getBytes()).setDstTpId("dstTpId".getBytes()).setPathConstraints(pathConstraints) + .setExplicitRouteObjects(explicitRouteObjects).build(); + pathRequestList.add(pathRequest1); + //readOnlyTransaction.close(); + return pathRequestList; + } + + public List extractPathRequest(PathComputationRequestInput input, ZToADirection ztoa, Long requestId) { + // List of A to Z + List listZToA = ztoa.getZToA(); + int ztoaSize = listZToA.size(); + // String modulationFormat = ztoa.getModulationFormat(); + // Create the path request + List servicePathRequest = new ArrayList<>(); + // Define the instance identifier + InstanceIdentifier nwInstanceIdentifier = InstanceIdentifier + .builder(Networks.class) + .child(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID))).build(); + //ReadOnlyTransaction readOnlyTransaction = this.dataBroker.newReadOnlyTransaction(); + + // read the configuration part of the data broker that concerns the + // nodes ID and get all the nodes + // java.util.Optional networkObject = readOnlyTransaction + // .read(LogicalDatastoreType.CONFIGURATION, + // nwInstanceIdentifier).get().toJavaUtil(); + // 1.1 Create explicitRouteObjects + // 1.1.1. create RouteObjectIncludeExclude list + List routeObjectIncludeExcludes = new ArrayList<>(); + IpAddress ipAddressCurrent = null; + Long index = (long) 0; + for (int i = 0; i < ztoaSize; i++) { + // String idZtoA = listZToA.get(i).getId(); + String nodeId = null; + if (listZToA.get(i).getResource() + .getResource() instanceof org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface + .pathdescription.rev171017.pce.resource.resource.resource.Node) { + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce + .resource.resource.resource.Node node = (org.opendaylight.yang.gen.v1.http.org.transportpce.b.c + ._interface.pathdescription.rev171017.pce.resource.resource.resource.Node) listZToA.get(i) + .getResource().getResource(); + nodeId = node.getNodeId(); + if (nodeId != null) { + String nodeRef = mapDisgNodeRefNode.get(nodeId); + IpAddress ipAddress = mapNodeRefIp.get(nodeRef); + for (Elements element : elements) { + if (element.getUid().contains(ipAddress.getIpv4Address().getValue().toString())) { + // String type = element.getType().getName(); + if ((ipAddressCurrent == null) || (ipAddressCurrent != ipAddress)) { + ipAddressCurrent = ipAddress; + // Fill in routeObjectIncludeExcludes + RouteObjectIncludeExclude routeObjectIncludeExclude1 = addRouteObjectIncludeExclude( + ipAddress, 1, index); + routeObjectIncludeExcludes.add(routeObjectIncludeExclude1); + index++; + } + break; + } + } + } else { + LOG.warn("node ID is null"); + } + } else if (listZToA.get(i).getResource() + .getResource() instanceof org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface + .pathdescription.rev171017.pce.resource.resource.resource.TerminationPoint) { + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce + .resource.resource.resource.TerminationPoint tp = (org.opendaylight.yang.gen.v1.http.org + .transportpce.b.c._interface.pathdescription.rev171017.pce.resource.resource.resource + .TerminationPoint) listZToA.get(i).getResource().getResource(); + // Not used in this version + } else if (listZToA.get(i).getResource() + .getResource() instanceof org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface + .pathdescription.rev171017.pce.resource.resource.resource.Link) { + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce + .resource.resource.resource.Link link = (org.opendaylight.yang.gen.v1.http.org.transportpce + .b.c._interface.pathdescription.rev171017.pce.resource.resource.resource.Link) listZToA.get(i) + .getResource().getResource(); + String clfi = mapLinkFiber.get(link.getLinkId()); + IpAddress fiberIp = mapFiberIp.get(clfi); + if (clfi != null) { + RouteObjectIncludeExclude routeObjectIncludeExclude1 = addRouteObjectIncludeExclude(fiberIp, 1, + index); + routeObjectIncludeExcludes.add(routeObjectIncludeExclude1); + index++; + } + } + } + // Create ExplicitRouteObjects + ExplicitRouteObjects explicitRouteObjects = new ExplicitRouteObjectsBuilder() + .setRouteObjectIncludeExclude(routeObjectIncludeExcludes).build(); + + // 1. Create the path request element 1 + // Find parameters + // String serviceName = input.getServiceName(); + String sourceNode = input.getServiceZEnd().getNodeId(); + String destNode = input.getServiceAEnd().getNodeId(); + + // 1.2 Create a path constraints + Long rate = ztoa.getRate(); + // Long wavelengthNumber = ztoa.getZToAWavelengthNumber(); + // Create EffectiveFreqSlot + List effectiveFreqSlot = new ArrayList<>(); + EffectiveFreqSlot effectiveFreqSlot1 = new EffectiveFreqSlotBuilder().setM(5).setN(8).build(); + effectiveFreqSlot.add(effectiveFreqSlot1); + // Create Te-Bandwidth + TeBandwidth teBandwidth = new TeBandwidthBuilder().setPathBandwidth(new BigDecimal(rate)) + .setTechnology("flexi-grid").setTrxType("openroadm-beta1").setTrxMode("W100G") + .setEffectiveFreqSlot(effectiveFreqSlot).setSpacing(new BigDecimal(50000000000.0)).build(); + // .setMaxNbOfChannel(new Long(80)).setOutputPower(new + // BigDecimal(0.0012589254117941673)) + PathConstraints pathConstraints = new PathConstraintsBuilder().setTeBandwidth(teBandwidth).build(); + // PathRequest pathRequest1 = new + // PathRequestBuilder().setRequestId(new + // Long(0)).setSource(mapNodeRefIp.get(sourceNode)) + // .setDestination(mapNodeRefIp.get(destNode)).setSrcTpId(input.getServiceAEnd().getTxDirection() + // .getPort().getPortName().getBytes()) + // .setDstTpId(input.getServiceAEnd().getRxDirection().getPort().getPortName().getBytes()) + // .setPathConstraints(pathConstraints) + // .setExplicitRouteObjects(explicitRouteObjects).build(); + PathRequest pathRequest1 = new PathRequestBuilder().setRequestId(requestId) + .setSource(mapNodeRefIp.get(sourceNode)).setDestination(mapNodeRefIp.get(destNode)) + .setSrcTpId("srcTpId".getBytes()).setDstTpId("dstTpId".getBytes()).setPathConstraints(pathConstraints) + .setExplicitRouteObjects(explicitRouteObjects).build(); + servicePathRequest.add(pathRequest1); + //readOnlyTransaction.close(); + return servicePathRequest; + } + + /* + * Create the synchronization + */ + public List extractSynchronization(Long requestId) { + // Create RequestIdNumber + List requestIdNumber = new ArrayList<>(); + requestIdNumber.add(0, new Long(0)); + // Create a synchronization + Svec svec = new SvecBuilder().setRelaxable(true).setDisjointness(new TePathDisjointness(true, true, false)) + .setRequestIdNumber(requestIdNumber).build(); + List synchro = new ArrayList<>(); + Synchronization synchronization1 = new SynchronizationBuilder().setSynchronizationId(new Long(0)).setSvec(svec) + .build(); + synchro.add(synchronization1); + return (synchro); + } + + /* + * Method to add Fiber + */ + private Elements addElementsFiber(double latitude, double longitude, String region, String city, String clfi, + double length, double attIn, double lossCoef, double connIn, double connOut, String typeVariety) { + // Create an amplifier after the roadm + Coordinate c1 = new Coordinate(new BigDecimal(latitude)); + Coordinate c2 = new Coordinate(new BigDecimal(longitude)); + Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2) + .build(); + Metadata metadata1 = new MetadataBuilder().setLocation(location1).build(); + Fiber fiber = new FiberBuilder().setLength(new BigDecimal(length)).setLengthUnits(Km.class) + .setAttIn(new BigDecimal(attIn)).setLossCoef(new BigDecimal(lossCoef)).setConIn(new BigDecimal(connIn)) + .setConOut(new BigDecimal(connOut)).build(); + Params params1 = new ParamsBuilder().setFiberroadm(fiber).build(); + // TypeElement Fiber = ; //new TypeElement(Fiber); + Elements element1 = new ElementsBuilder().setUid(clfi) + .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Fiber.class) + .setTypeVariety(typeVariety).setMetadata(metadata1) + .setElementType(new FiberRoadmBuilder().setParams(params1).build()).build(); + return element1; + } + + /* + * Method to add Edfa + */ + private Elements addElementsEdfa(double latitude, double longitude, String region, String city, + BigDecimal gainTarget, BigDecimal tiltTarget, BigDecimal outVoa, String typeVariety, String uidEdfa) { + // Create an amplifier after the roadm + Coordinate c1 = new Coordinate(new BigDecimal(latitude)); + Coordinate c2 = new Coordinate(new BigDecimal(longitude)); + Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2) + .build(); + Metadata metadata1 = new MetadataBuilder().setLocation(location1).build(); + Operational operational = new OperationalBuilder().setGainTarget(gainTarget).setTiltTarget(tiltTarget) + .setOutVoa(outVoa).build(); + Edfa edfa = new EdfaBuilder() + // .setTypeVariety(typeVariety) + .setOperational(operational).build(); + Elements element1 = new ElementsBuilder().setUid(uidEdfa) // Choose an + // ip + // address + .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Edfa.class) + .setMetadata(metadata1).setElementType(edfa).setTypeVariety(typeVariety).build(); + return element1; + } + + /* + * Method to add ROADM + */ + private Elements addElementsRoadm(double latitude, double longitude, String region, String city, + double targetPchOutDb, String uidRoadm) { + + Coordinate c1 = new Coordinate(new BigDecimal(latitude)); + Coordinate c2 = new Coordinate(new BigDecimal(longitude)); + Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2) + .build(); + Metadata metadata1 = new MetadataBuilder().setLocation(location1).build(); + // Create the roadm + Roadm roadm = new RoadmBuilder().setTargetPchOutDb(new BigDecimal(targetPchOutDb)).build(); + Params params1 = new ParamsBuilder().setFiberroadm(roadm).build(); + Elements element1 = new ElementsBuilder().setUid(uidRoadm) + .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Roadm.class) + .setMetadata(metadata1).setElementType(new FiberRoadmBuilder().setParams(params1).build()).build(); + return element1; + } + + /* + * Method to add Transceiver + */ + private Elements addElementsTransceiver(double latitude, double longitude, String region, String city, + String uidTrans) { + Coordinate c1 = new Coordinate(new BigDecimal(latitude)); + Coordinate c2 = new Coordinate(new BigDecimal(longitude)); + Location location1 = new LocationBuilder().setRegion(region).setCity(city).setLatitude(c1).setLongitude(c2) + .build(); + Metadata metadata1 = new MetadataBuilder().setLocation(location1).build(); + Transceiver transceiver = new TransceiverBuilder().build(); + Elements element1 = new ElementsBuilder().setUid(uidTrans) + .setType(org.opendaylight.yang.gen.v1.gnpy.gnpy.network.topology.rev181214.Transceiver.class) + .setMetadata(metadata1).setElementType(transceiver).build(); + return element1; + } + + /* + * Add routeObjectIncludeExclude + */ + private RouteObjectIncludeExclude addRouteObjectIncludeExclude(IpAddress ipAddress, long teTpValue, long index) { + TeNodeId teNodeId = new TeNodeId(ipAddress); + TeTpId teTpId = new TeTpId(teTpValue); + NumUnnumHop numUnnumHop = new org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type.num + .unnum.hop.NumUnnumHopBuilder() + .setNodeId(teNodeId.getIpv4Address().getValue().toString()).setLinkTpId(teTpId.getUint32().toString()) + .setHopType(TeHopType.STRICT).build(); + Type type1 = new NumUnnumHopBuilder().setNumUnnumHop(numUnnumHop).build(); + // Create routeObjectIncludeExclude element 1 + RouteObjectIncludeExclude routeObjectIncludeExclude1 = new RouteObjectIncludeExcludeBuilder().setIndex(index) + .setExplicitRouteUsage(RouteIncludeEro.class).setType(type1).build(); + return routeObjectIncludeExclude1; + } + + private String fromToNodeForConnection(String id, IpAddress ip) { + String fromToNode = id; + if (ip != null) { + fromToNode = ip.getIpv4Address().getValue().toString(); + } + return (fromToNode); + } + + private Connections createNewConnection(String srcId, IpAddress srcIp, String destId, IpAddress destIp) { + String fromNode = srcId; + String toNode = destId; + if (srcIp != null) { + fromNode = srcIp.getIpv4Address().getValue().toString(); + } + if (destIp != null) { + toNode = destIp.getIpv4Address().getValue().toString(); + } + Connections connection1 = new ConnectionsBuilder().setFromNode(fromNode).setToNode(toNode).build(); + return (connection1); + } + + public List getElements() { + return elements; + } + + public void setElements(List elements) { + this.elements = elements; + } + + public List getConnections() { + return connections; + } + + public void setConnections(List connections) { + this.connections = connections; + } + + public List getPathRequest() { + return pathRequest; + } + + public void setPathRequest(List pathRequest) { + this.pathRequest = pathRequest; + } + + public List getSynchronization() { + return synchronization; + } + + public void setSynchronization(List synchronization) { + this.synchronization = synchronization; + } + + public List createEmptyPathRequest(PathComputationRequestInput input, AToZDirection atoz) { + // List of A to Z + // List listAtoZ = atoz.getAToZ(); + // int atozSize = listAtoZ.size(); + + // Create the path request + List pathRequestList = new ArrayList<>(); + + // 1. Create the path request element 1 + // Find parameters + // String serviceName = input.getServiceName(); + String sourceNode = input.getServiceAEnd().getNodeId(); + String destNode = input.getServiceZEnd().getNodeId(); + + // 1.2 Create a path constraints + Long rate = atoz.getRate(); + + // Create EffectiveFreqSlot + List effectiveFreqSlot = new ArrayList<>(); + EffectiveFreqSlot effectiveFreqSlot1 = new EffectiveFreqSlotBuilder().setM(5).setN(8).build(); + effectiveFreqSlot.add(effectiveFreqSlot1); + + // Create Te-Bandwidth + TeBandwidth teBandwidth = new TeBandwidthBuilder().setPathBandwidth(new BigDecimal(rate)) + .setTechnology("flexi-grid").setTrxType("openroadm-beta1").setTrxMode("W100G") + .setEffectiveFreqSlot(effectiveFreqSlot).setSpacing(new BigDecimal(50000000000.0)).build(); + PathConstraints pathConstraints = new PathConstraintsBuilder().setTeBandwidth(teBandwidth).build(); + PathRequest pathRequest1 = new PathRequestBuilder().setRequestId(new Long(0)) + .setSource(mapNodeRefIp.get(sourceNode)).setDestination(mapNodeRefIp.get(destNode)) + .setSrcTpId("srcTpId".getBytes()).setDstTpId("dstTpId".getBytes()).setPathConstraints(pathConstraints) + .build(); + pathRequestList.add(pathRequest1); + return pathRequestList; + } + +} 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 new file mode 100644 index 000000000..006710250 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/GnpyResult.java @@ -0,0 +1,324 @@ +/* + * Copyright © 2018 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.base.Preconditions; +import com.google.gson.stream.JsonReader; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javassist.ClassPool; + +import javax.annotation.Nonnull; + +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.mdsal.binding.generator.util.JavassistUtils; +import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.Result; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.explicit.route.hop.type.num.unnum.hop.NumUnnumHop; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.properties.path.properties.PathMetric; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.generic.path.properties.path.properties.PathRouteObjects; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.Response; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.response.response.type.NoPathCase; +import org.opendaylight.yang.gen.v1.gnpy.path.rev190502.result.response.response.type.PathCase; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.General; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.GeneralBuilder; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.Include; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.IncludeBuilder; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.include_.OrderedHops; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.constraints.sp.co.routing.or.general.general.include_.OrderedHopsBuilder; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.HopType; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.HopTypeBuilder; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.ordered.constraints.sp.hop.type.hop.type.NodeBuilder; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraints; +import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017.routing.constraints.sp.HardConstraintsBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.YangModuleInfo; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class for analyzing the result sent by GNPy. + * + * @author Ahmed Triki ( ahmed.triki@orange.com ) + * + */ + +public class GnpyResult { + + private static final Logger LOG = LoggerFactory.getLogger(GnpyResult.class); + private Response response = null; + + public GnpyResult(String gnpyResponseString) throws Exception { + + // try { + // Optional dataObject; + // Create the schema context + final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create(); + Iterable moduleInfos; + moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(Result.class)); + moduleContext.addModuleInfos(moduleInfos); + SchemaContext schemaContext = moduleContext.tryToCreateSchemaContext().get(); + + // Create the binding binding normalized node codec registry + BindingRuntimeContext bindingRuntimeContext = BindingRuntimeContext.create(moduleContext, schemaContext); + final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry( + StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault()))); + codecRegistry.onBindingRuntimeContextUpdated(bindingRuntimeContext); + + // Create the data object + QName pathQname = QName.create("gnpy:path", "2019-05-02", "result"); + LOG.debug("the Qname is {} / namesapce {} ; module {}; ", pathQname.toString(), pathQname.getNamespace(), + pathQname.getModule()); + YangInstanceIdentifier yangId = YangInstanceIdentifier.of(pathQname); + DataObject dataObject = null; + //Create the object response + //Create JsonReader from String + InputStream streamGnpyRespnse = new ByteArrayInputStream(gnpyResponseString.getBytes(StandardCharsets.UTF_8)); + InputStreamReader gnpyResultReader = new InputStreamReader(streamGnpyRespnse); + JsonReader jsonReader = new JsonReader(gnpyResultReader); + Optional> transformIntoNormalizedNode = parseInputJSON(jsonReader, + Result.class); + NormalizedNode normalizedNode = transformIntoNormalizedNode.get(); + if (codecRegistry.fromNormalizedNode(yangId, normalizedNode) != null) { + LOG.debug("The key of the generated object", + codecRegistry.fromNormalizedNode(yangId, normalizedNode).getKey()); + dataObject = codecRegistry.fromNormalizedNode(yangId, normalizedNode).getValue(); + } else { + LOG.warn("The codec registry from the normalized node is null!"); + } + List responses = null; + responses = ((Result) dataObject).getResponse(); + if (responses != null) { + LOG.info("The response id is {}; ", responses.get(0).getResponseId()); + } else { + LOG.warn("The response is null!"); + } + this.response = responses.get(0); + analyzeResult(); + } + + public boolean getPathFeasibility() { + boolean isFeasible = false; + if (response != null) { + if (response.getResponseType() instanceof NoPathCase) { + isFeasible = false; + LOG.info("The path is not feasible "); + } else if (response.getResponseType() instanceof PathCase) { + isFeasible = true; + LOG.info("The path is feasible "); + } + } + return isFeasible; + } + + public void analyzeResult() { + if (response != null) { + Long responseId = response.getResponseId(); + LOG.info("Response-Id {}", responseId); + if (response.getResponseType() instanceof NoPathCase) { + NoPathCase noPathCase = (NoPathCase) response.getResponseType(); + String noPathType = noPathCase.getNoPath().getNoPath(); + LOG.info("GNPy: No path - {}",noPathType); + if (((noPathType == "NO_FEASIBLE_BAUDRATE_WITH_SPACING") && (noPathType == "NO_FEASIBLE_MODE")) + && ((noPathType == "MODE_NOT_FEASIBLE") && (noPathType == "NO_SPECTRUM"))) { + List pathMetricList = noPathCase.getNoPath().getPathProperties().getPathMetric(); + LOG.info("GNPy : path is not feasible : {}", noPathType); + for (PathMetric pathMetric : pathMetricList) { + String metricType = pathMetric.getMetricType().getSimpleName(); + BigDecimal accumulativeValue = pathMetric.getAccumulativeValue(); + LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue); + } + } + } else if (response.getResponseType() instanceof PathCase) { + LOG.info("GNPy : path is feasible"); + PathCase pathCase = (PathCase) response.getResponseType(); + List pathMetricList = pathCase.getPathProperties().getPathMetric(); + for (PathMetric pathMetric : pathMetricList) { + String metricType = pathMetric.getMetricType().getSimpleName(); + BigDecimal accumulativeValue = pathMetric.getAccumulativeValue(); + LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue); + } + } + } + } + + public HardConstraints analyzeGnpyPath() { + HardConstraints hardConstraints = null; + if (response != null) { + Long responseId = response.getResponseId(); + LOG.info("Response-Id {}", responseId); + if (response.getResponseType() instanceof NoPathCase) { + NoPathCase noPathCase = (NoPathCase) response.getResponseType(); + LOG.info("No path feasible {}", noPathCase.toString()); + } else if (response.getResponseType() instanceof PathCase) { + PathCase pathCase = (PathCase) response.getResponseType(); + List pathMetricList = pathCase.getPathProperties().getPathMetric(); + for (PathMetric pathMetric : pathMetricList) { + String metricType = pathMetric.getMetricType().getSimpleName(); + BigDecimal accumulativeValue = pathMetric.getAccumulativeValue(); + LOG.info("Metric type {} // AccumulatriveValue {}", metricType, accumulativeValue); + } + + // Includes the list of nodes in the GNPy computed path as constraints for the PCE + List orderedHopsList = null; + List pathRouteObjectList = pathCase.getPathProperties().getPathRouteObjects(); + int counter = 0; + for (PathRouteObjects pathRouteObjects : pathRouteObjectList) { + if (pathRouteObjects.getPathRouteObject().getType() instanceof NumUnnumHop) { + NumUnnumHop numUnnumHop = (NumUnnumHop) pathRouteObjects.getPathRouteObject().getType(); + String nodeId = numUnnumHop.getNodeId(); + org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.routing.constraints.rev171017 + .ordered.constraints.sp.hop.type.hop.type.Node node = new NodeBuilder() + .setNodeId(nodeId).build(); + HopType hopType = new HopTypeBuilder().setHopType(node).build(); + OrderedHops orderedHops = new OrderedHopsBuilder().setHopNumber(counter).setHopType(hopType) + .build(); + LOG.info("- gnpyResult class : Hard Constraint: {} // - Hop Node {}", counter, nodeId); + orderedHopsList.add(orderedHops); + counter++; + } + } + Include include = new IncludeBuilder().setOrderedHops(orderedHopsList).build(); + General general = new GeneralBuilder().setInclude(include).build(); + hardConstraints = new HardConstraintsBuilder().setCoRoutingOrGeneral(general).build(); + } + } + return hardConstraints; + } + + /** + * Parses the input json with concrete implementation of + * {@link JsonParserStream}. + * + * @param reader + * of the given JSON + * @throws Exception + * + */ + private Optional> parseInputJSON(JsonReader reader, + Class objectClass) throws Exception { + NormalizedNodeResult result = new NormalizedNodeResult(); + SchemaContext schemaContext = getSchemaContext(objectClass); + try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result); + JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext, schemaContext);) { + LOG.debug("GNPy: the path to the reader {}", reader.getPath()); + LOG.debug("GNPy: the reader {}", reader.toString()); + LOG.debug("GNPy: the jsonParser class {} // jsonParser to string {}", jsonParser.getClass(), + jsonParser.toString()); + jsonParser.parse(reader); + } catch (IOException e) { + LOG.warn("GNPy: exception {} occured during parsing Json input stream", e.getMessage()); + return Optional.empty(); + } + return Optional.ofNullable(result.getResult()); + } + + private SchemaContext getSchemaContext(Class objectClass) throws Exception { + final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create(); + Iterable moduleInfos; + SchemaContext schemaContext = null; + moduleInfos = Collections.singleton(BindingReflections.getModuleInfo(objectClass)); + moduleContext.addModuleInfos(moduleInfos); + schemaContext = moduleContext.tryToCreateSchemaContext().get(); + return schemaContext; + } + + private String readResultFromFile(String fileName) { + BufferedReader br = null; + FileReader fr = null; + StringBuilder sb = new StringBuilder(); + String gnpyResponse; + + try { + fr = new FileReader(fileName); + br = new BufferedReader(fr); + String currentLine; + while ((currentLine = br.readLine()) != null) { + LOG.info(currentLine); + sb.append(currentLine); + } + fr.close(); + } catch (IOException e) { + LOG.warn("GNPy: exception {} occured during the reading of results", e.getMessage()); + } + gnpyResponse = sb.toString(); + return gnpyResponse; + } + + /** + * Transforms the given input {@link NormalizedNode} into the given + * {@link DataObject}. + * + * @param normalizedNode + * normalized node you want to convert + * @param rootNode + * {@link QName} of converted normalized node root + * + *

+ * The input object should be {@link ContainerNode} + *

+ */ + public Optional getDataObject(@Nonnull NormalizedNode normalizedNode, + @Nonnull QName rootNode, BindingNormalizedNodeSerializer codecRegistry) { + if (normalizedNode != null) { + LOG.debug("GNPy: The codecRegistry is ", codecRegistry.toString()); + } else { + LOG.warn("GNPy: The codecRegistry is null"); + } + Preconditions.checkNotNull(normalizedNode); + if (normalizedNode instanceof ContainerNode) { + YangInstanceIdentifier.PathArgument directChildIdentifier = YangInstanceIdentifier.of(rootNode) + .getLastPathArgument(); + Optional> directChild = NormalizedNodes.getDirectChild(normalizedNode, + directChildIdentifier); + if (!directChild.isPresent()) { + throw new IllegalStateException(String.format("Could not get the direct child of %s", rootNode)); + } + normalizedNode = directChild.get(); + LOG.debug("GNPy: the normalized node is ", normalizedNode.getNodeType()); + } + YangInstanceIdentifier rootNodeYangInstanceIdentifier = YangInstanceIdentifier.of(rootNode); + LOG.debug("GNPy: the root Node Yang Instance Identifier is ", rootNodeYangInstanceIdentifier.toString()); + Map.Entry bindingNodeEntry = codecRegistry.fromNormalizedNode(rootNodeYangInstanceIdentifier, + normalizedNode); + if (bindingNodeEntry == null) { + LOG.debug("The binding Node Entry is null"); + return Optional.empty(); + } + return Optional.ofNullable((T) bindingNodeEntry.getValue()); + } +} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperations.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperations.java new file mode 100644 index 000000000..11489dc90 --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperations.java @@ -0,0 +1,23 @@ +/* + * Copyright © 2018 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 org.opendaylight.transportpce.common.DataStoreContext; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface ServiceDataStoreOperations { + + void createXMLFromDevice(DataStoreContext dataStoreContextUtil, OrgOpenroadmDevice device, String output); + + String createJsonStringFromDataObject(InstanceIdentifier id, DataObject object) throws Exception; + + void writeStringFile(String jsonString, String fileName); +} diff --git a/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperationsImpl.java b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperationsImpl.java new file mode 100644 index 000000000..4771b5c2d --- /dev/null +++ b/pce/src/main/java/org/opendaylight/transportpce/pce/gnpy/ServiceDataStoreOperationsImpl.java @@ -0,0 +1,147 @@ +/* + * Copyright © 2018 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.base.Function; +import com.google.common.collect.FluentIterable; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Collections; +import java.util.Optional; + +import javassist.ClassPool; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.mdsal.binding.generator.util.JavassistUtils; +import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; +import org.opendaylight.transportpce.common.DataStoreContext; +import org.opendaylight.transportpce.common.converter.XMLDataObjectConverter; +import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice; +import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.binding.YangModuleInfo; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory; +import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ServiceDataStoreOperationsImpl implements ServiceDataStoreOperations { + + private static final Logger LOG = LoggerFactory.getLogger(ServiceDataStoreOperationsImpl.class); + private final DataBroker dataBroker; + + public ServiceDataStoreOperationsImpl(DataBroker dataBroker) { + this.dataBroker = dataBroker; + } + + public void createXMLFromDevice(DataStoreContext dataStoreContextUtil, OrgOpenroadmDevice device, String output) { + if (device != null) { + Optional> transformIntoNormalizedNode = null; + XMLDataObjectConverter cwDsU = XMLDataObjectConverter.createWithDataStoreUtil(dataStoreContextUtil); + transformIntoNormalizedNode = cwDsU.toNormalizedNodes(device, OrgOpenroadmDevice.class); + if (!transformIntoNormalizedNode.isPresent()) { + throw new IllegalStateException( + String.format("Could not transform the input %s into normalized nodes", device)); + } + Writer writerFromDataObject = + cwDsU.writerFromDataObject(device, OrgOpenroadmDevice.class,cwDsU.dataContainer()); + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(output)); + writer.write(writerFromDataObject.toString()); + writer.close(); + } catch (IOException e) { + LOG.error("Bufferwriter error "); + } + LOG.debug("GNPy: device xml : {}", writerFromDataObject.toString()); + } + } + + public String createJsonStringFromDataObject(final InstanceIdentifier id, DataObject object) throws Exception { + + // See this link for more info : + // https://github.com/opendaylight/fpc/blob/master/impl/src/main/java/org/opendaylight/fpc/utils/FpcCodecUtils.java + final SchemaPath scPath = SchemaPath + .create(FluentIterable.from(id.getPathArguments()).transform(new Function() { + @Override + public QName apply(final PathArgument input) { + return BindingReflections.findQName(input.getType()); + } + }), true); + final Writer writer = new StringWriter(); + NormalizedNodeStreamWriter domWriter; + + try { + // Prepare the variables + final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create(); + Iterable moduleInfos = Collections + .singleton(BindingReflections.getModuleInfo(object.getClass()));// TransportpceGnpyData.class)); + moduleContext.addModuleInfos(moduleInfos); + SchemaContext schemaContext = moduleContext.tryToCreateSchemaContext().get(); + BindingRuntimeContext bindingContext; + bindingContext = BindingRuntimeContext.create(moduleContext, schemaContext); + final BindingNormalizedNodeCodecRegistry bindingStreamCodecs = new BindingNormalizedNodeCodecRegistry( + StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault()))); + bindingStreamCodecs.onBindingRuntimeContextUpdated(bindingContext); + BindingNormalizedNodeCodecRegistry codecRegistry = bindingStreamCodecs; + + /* + * This function needs : - context - scPath.getParent() - + * scPath.getLastComponent().getNamespace(), - + * JsonWriterFactory.createJsonWriter(writer) + */ + domWriter = JSONNormalizedNodeStreamWriter.createExclusiveWriter( + JSONCodecFactory.createSimple(schemaContext), scPath.getParent(), + scPath.getLastComponent().getNamespace(), JsonWriterFactory.createJsonWriter(writer, 2)); + // The write part + final BindingStreamEventWriter bindingWriter = codecRegistry.newWriter(id, domWriter); + codecRegistry.getSerializer(id.getTargetType()).serialize(object, bindingWriter); + // file.write(writer.toString()); + // file.close(); + writer.close(); + } catch (IOException e) { + LOG.error("GNPy: writer error "); + } catch (YangSyntaxErrorException e) { + LOG.warn("GNPy: exception {} occured during json file creation", e.getMessage(), e); + } catch (ReactorException e) { + LOG.warn("GNPy: exception {} occured during json file creation", e.getMessage(), e); +// } catch (Exception e) { +// LOG.warn("An error {} occured during json file creation", e.getMessage(), e); + } + return writer.toString(); + } + + // Write the json as a string in a file + public void writeStringFile(String jsonString, String fileName) { + try { + FileWriter file = new FileWriter(fileName); + file.write(jsonString); + file.close(); + } catch (IOException e) { + LOG.error("GNPy: writer error "); + } + } +} diff --git a/pce/src/test/java/org/opendaylight/transportpce/pce/utils/PceTestUtils.java b/pce/src/test/java/org/opendaylight/transportpce/pce/utils/PceTestUtils.java index c53b96aa3..0d94866d2 100644 --- a/pce/src/test/java/org/opendaylight/transportpce/pce/utils/PceTestUtils.java +++ b/pce/src/test/java/org/opendaylight/transportpce/pce/utils/PceTestUtils.java @@ -16,10 +16,10 @@ import org.junit.Assert; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.transportpce.binding.converter.XMLDataObjectConverter; -import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter; +import org.opendaylight.transportpce.common.DataStoreContext; import org.opendaylight.transportpce.common.NetworkUtils; -import org.opendaylight.transportpce.test.common.DataStoreContext; +import org.opendaylight.transportpce.common.converter.XMLDataObjectConverter; +import org.opendaylight.transportpce.common.converter.api.DataObjectConverter; import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev171017.PathComputationRequestOutput; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.path.description.atoz.direction.AToZ; import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev171017.pce.resource.resource.resource.Node; diff --git a/test-common/pom.xml b/test-common/pom.xml index 3c598ee58..d33967f1d 100644 --- a/test-common/pom.xml +++ b/test-common/pom.xml @@ -70,5 +70,10 @@ yang-data-codec-gson + + ${project.groupId} + transportpce-common + ${project.version} + diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java b/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java index bfc2d8a97..76682adba 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/AbstractTest.java @@ -11,8 +11,8 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; import org.opendaylight.controller.md.sal.binding.api.NotificationService; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.transportpce.test.common.DataStoreContext; -import org.opendaylight.transportpce.test.common.DataStoreContextImpl; +import org.opendaylight.transportpce.common.DataStoreContext; +import org.opendaylight.transportpce.common.DataStoreContextImpl; public abstract class AbstractTest { diff --git a/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java b/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java index 833de2289..861cb948d 100644 --- a/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java +++ b/test-common/src/main/java/org/opendaylight/transportpce/test/DeviceWrapper.java @@ -21,10 +21,10 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.transportpce.binding.converter.XMLDataObjectConverter; -import org.opendaylight.transportpce.binding.converter.api.DataObjectConverter; -import org.opendaylight.transportpce.test.common.DataStoreContext; -import org.opendaylight.transportpce.test.common.DataStoreContextImpl; +import org.opendaylight.transportpce.common.DataStoreContext; +import org.opendaylight.transportpce.common.DataStoreContextImpl; +import org.opendaylight.transportpce.common.converter.XMLDataObjectConverter; +import org.opendaylight.transportpce.common.converter.api.DataObjectConverter; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -- 2.36.6