--- /dev/null
+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: <https://github.com/Telecominfraproject/oopt-gnpy>
+ contact: <mailto:ahmed.triki@orange.com>
+ contact: <mailto:esther.lerouzic@orange.com>
+ ";
+
+ 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";
+ }
+ }
+
+}
--- /dev/null
+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: <https://github.com/Telecominfraproject/oopt-gnpy>
+ contact: <mailto:ahmed.triki@orange.com>
+ contact: <mailto:esther.lerouzic@orange.com>
+ ";
+
+ 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 {
+
+ }
+}
+
--- /dev/null
+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: <https://github.com/Telecominfraproject/oopt-gnpy>
+ contact: <mailto:ahmed.triki@orange.com>
+ contact: <mailto:esther.lerouzic@orange.com>
+ ";
+
+ 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" ;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+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: <https://github.com/Telecominfraproject/oopt-gnpy>
+ contact: <mailto:ahmed.triki@orange.com>
+ contact: <mailto:esther.lerouzic@orange.com>
+ ";
+
+ 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";
+ }
+}
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>org.opendaylight.odlparent</groupId>
- <artifactId>bundle-parent</artifactId>
- <version>4.0.10</version>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>3.0.8</version>
<relativePath />
</parent>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-xml</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-codec-gson</artifactId>
+ </dependency>
+
<!-- Testing Dependencies -->
<dependency>
<groupId>junit</groupId>
* 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;
* 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;
* 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;
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;
* 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;
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;
* 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;
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;
* 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;
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>org.opendaylight.odlparent</groupId>
- <artifactId>bundle-parent</artifactId>
- <version>4.0.10</version>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>3.0.8</version>
<relativePath/>
</parent>
<artifactId>transportpce-networkmodel</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>transportpce-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>net.sf.jung2</artifactId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>test-common</artifactId>
<version>1.9.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
-
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-dom-codec</artifactId>
+ </dependency>
</dependencies>
</project>
private boolean populateGraph(Map<NodeId, PceNode> allNodes) {
cleanupGraph();
-
Iterator<Map.Entry<NodeId, PceNode>> nodes = allNodes.entrySet().iterator();
while (nodes.hasNext()) {
-
Map.Entry<NodeId, PceNode> node = nodes.next();
-
PceNode pcenode = node.getValue();
List<PceLink> 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;
}
for (PceNode node : allNodes) {
List<PceLink> 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);
-
}
}
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;
* <code>false</code> 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;
}
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<Elements> elementsList1 = xtrTopo.getElements();
+ List<Connections> connectionsList1 = xtrTopo.getConnections();
+ List<PathRequest> pathRequestList1 = xtrTopo.getPathRequest();
+ List<Synchronization> 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<Elements> elementsList2 = xtrTopo.getElements();
+ List<Connections> connectionsList2 = xtrTopo.getConnections();
+ List<PathRequest> pathRequestList2 = xtrTopo.getPathRequest();
+ List<Synchronization> 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<Elements> elementsList, List<Connections> connectionsList,
+ List<PathRequest> pathRequestList, List<Synchronization> synchronizationList) throws Exception {
+ GnpyApi gnpyApi = new GnpyApiBuilder()
+ .setTopologyFile(
+ new TopologyFileBuilder().setElements(elementsList).setConnections(connectionsList).build())
+ .setServiceFile(new ServiceFileBuilder().setPathRequest(pathRequestList).build()).build();
+ InstanceIdentifier<GnpyApi> 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) {
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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> elements = new ArrayList<>();
+ private List<Connections> connections = new ArrayList<>();
+ private List<PathRequest> pathRequest = new ArrayList<>();
+ private List<Synchronization> synchronization = new ArrayList<>();
+ private Map<String, String> mapDisgNodeRefNode = new HashMap<String, String>();
+ private Map<String, IpAddress> mapNodeRefIp = new HashMap<String, IpAddress>();
+ private Map<String, String> mapLinkFiber = new HashMap<String, String>();
+ private Map<String, IpAddress> mapFiberIp = new HashMap<String, IpAddress>();
+ 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<String, List<?>> map = extractTopo();
+ if (map.containsKey("Elements")) {
+ elements = (List<Elements>) map.get("Elements");
+ } else {
+ elements = null;
+ }
+ if (map.containsKey("Elements")) {
+ connections = (List<Connections>) 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<String, List<?>> map = extractTopo();
+ if (map.containsKey("Elements")) {
+ elements = (List<Elements>) map.get("Elements");
+ } else {
+ elements = null;
+ }
+ if (map.containsKey("Elements")) {
+ connections = (List<Connections>) 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<String, List<?>> extractTopo() {
+ Map<String, List<?>> map = new HashMap<String, List<?>>();
+ // Define the elements
+ List<Elements> topoElements = new ArrayList<>();
+ // Define the connections
+ List<Connections> topoConnections = new ArrayList<>();
+ // Define the instance identifier of the OpenRoadm topology
+ InstanceIdentifier<Network> 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<Network> 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<Network> openRoadmTopo = readOnlyTransaction
+ .read(LogicalDatastoreType.CONFIGURATION, insIdOpenRoadmTopo).get().toJavaUtil();
+ java.util.Optional<Network> openRoadmNet = readOnlyTransaction
+ .read(LogicalDatastoreType.CONFIGURATION, insIdrOpenRoadmNet).get().toJavaUtil();
+ if (openRoadmNet.isPresent()) {
+ List<Node> openRoadmNetNodeList = openRoadmNet.get().getNode();
+ if (openRoadmTopo.isPresent()) {
+ List<Node> openRoadmTopoNodeList = openRoadmTopo.get().getNode();
+ List<String> 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<SupportingNode> 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<Link> 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<AmplifiedLink> 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<LinkConcatenation> 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<PathRequest> extractPathRequest(PathComputationRequestInput input, AToZDirection atoz, Long requestId) {
+ // List of A to Z
+ List<AToZ> listAtoZ = atoz.getAToZ();
+ int atozSize = listAtoZ.size();
+ // String modulationFormat = atoz.getModulationFormat();
+ // Create the path request
+ List<PathRequest> pathRequestList = new ArrayList<>();
+ // Define the instance identifier
+ // InstanceIdentifier<Network> 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<Network> networkObject = readOnlyTransaction
+ // .read(LogicalDatastoreType.CONFIGURATION,
+ // nwInstanceIdentifier).get().toJavaUtil();
+ // 1.1 Create explicitRouteObjects
+ // 1.1.1. create RouteObjectIncludeExclude list
+ List<RouteObjectIncludeExclude> 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> 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<PathRequest> extractPathRequest(PathComputationRequestInput input, ZToADirection ztoa, Long requestId) {
+ // List of A to Z
+ List<ZToA> listZToA = ztoa.getZToA();
+ int ztoaSize = listZToA.size();
+ // String modulationFormat = ztoa.getModulationFormat();
+ // Create the path request
+ List<PathRequest> servicePathRequest = new ArrayList<>();
+ // Define the instance identifier
+ InstanceIdentifier<Network> 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<Network> networkObject = readOnlyTransaction
+ // .read(LogicalDatastoreType.CONFIGURATION,
+ // nwInstanceIdentifier).get().toJavaUtil();
+ // 1.1 Create explicitRouteObjects
+ // 1.1.1. create RouteObjectIncludeExclude list
+ List<RouteObjectIncludeExclude> 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> 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<Synchronization> extractSynchronization(Long requestId) {
+ // Create RequestIdNumber
+ List<Long> 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<Synchronization> 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<Elements> getElements() {
+ return elements;
+ }
+
+ public void setElements(List<Elements> elements) {
+ this.elements = elements;
+ }
+
+ public List<Connections> getConnections() {
+ return connections;
+ }
+
+ public void setConnections(List<Connections> connections) {
+ this.connections = connections;
+ }
+
+ public List<PathRequest> getPathRequest() {
+ return pathRequest;
+ }
+
+ public void setPathRequest(List<PathRequest> pathRequest) {
+ this.pathRequest = pathRequest;
+ }
+
+ public List<Synchronization> getSynchronization() {
+ return synchronization;
+ }
+
+ public void setSynchronization(List<Synchronization> synchronization) {
+ this.synchronization = synchronization;
+ }
+
+ public List<PathRequest> createEmptyPathRequest(PathComputationRequestInput input, AToZDirection atoz) {
+ // List of A to Z
+ // List<AToZ> listAtoZ = atoz.getAToZ();
+ // int atozSize = listAtoZ.size();
+
+ // Create the path request
+ List<PathRequest> 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> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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> dataObject;
+ // Create the schema context
+ final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
+ Iterable<? extends YangModuleInfo> 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<NormalizedNode<? extends PathArgument, ?>> transformIntoNormalizedNode = parseInputJSON(jsonReader,
+ Result.class);
+ NormalizedNode<? extends PathArgument, ?> 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<Response> 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<PathMetric> 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<PathMetric> 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<PathMetric> 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<OrderedHops> orderedHopsList = null;
+ List<PathRouteObjects> 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<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputJSON(JsonReader reader,
+ Class<? extends DataObject> 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<? extends DataObject> objectClass) throws Exception {
+ final ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
+ Iterable<? extends YangModuleInfo> 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
+ *
+ * <p>
+ * The input object should be {@link ContainerNode}
+ * </p>
+ */
+ public <T extends DataObject> Optional<T> 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<NormalizedNode<?, ?>> 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());
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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<NormalizedNode<?, ?>> 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<PathArgument, QName>() {
+ @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<? extends YangModuleInfo> 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 ");
+ }
+ }
+}
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;
<artifactId>yang-data-codec-gson</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>transportpce-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
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 {
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;