From 9d60b6eed33f1139c52a8542a48e7783f7964f2f Mon Sep 17 00:00:00 2001 From: chengfan Date: Thu, 1 Dec 2016 11:06:39 +0800 Subject: [PATCH] [ONOS-5465][TE Tunnel SB Provider] Interaction with ONOS core TE subsystems for TE tunnel updates Change-Id: I2cb7ed7731192228a5f6ef4c4b6c3a14a7175732 --- providers/ietfte/{topology => app}/app.xml | 13 +- .../ietfte/{topology => app}/features.xml | 16 +- providers/ietfte/app/pom.xml | 49 +++ providers/ietfte/pom.xml | 27 ++ providers/ietfte/topology/pom.xml | 17 + .../topology/TeTopologyRestconfProvider.java | 4 +- providers/ietfte/tunnel/pom.xml | 73 ++++ .../te/tunnel/TeTunnelRestconfProvider.java | 354 ++++++++++++++++++ .../provider/te/tunnel/package-info.java | 19 + providers/ietfte/utils/pom.xml | 46 +++ .../provider/te/utils/CodecTools.java | 95 +++++ .../provider/te/utils/DefaultJsonCodec.java} | 95 +++-- .../te/utils}/YangCompositeEncodingImpl.java | 44 ++- .../provider/te/utils/package-info.java | 20 + .../provider/te/utils/CodecToolsTest.java | 53 +++ .../utils/YangCompositeEncodingImplTest.java | 50 +++ 16 files changed, 895 insertions(+), 80 deletions(-) rename providers/ietfte/{topology => app}/app.xml (57%) rename providers/ietfte/{topology => app}/features.xml (76%) create mode 100644 providers/ietfte/app/pom.xml create mode 100755 providers/ietfte/tunnel/pom.xml create mode 100755 providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java create mode 100644 providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/package-info.java create mode 100755 providers/ietfte/utils/pom.xml create mode 100644 providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/CodecTools.java rename providers/ietfte/{topology/src/main/java/org/onosproject/provider/te/topology/JsonYdtCodec.java => utils/src/main/java/org/onosproject/provider/te/utils/DefaultJsonCodec.java} (53%) mode change 100644 => 100755 rename providers/ietfte/{topology/src/main/java/org/onosproject/provider/te/topology => utils/src/main/java/org/onosproject/provider/te/utils}/YangCompositeEncodingImpl.java (54%) mode change 100644 => 100755 create mode 100644 providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/package-info.java create mode 100644 providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/CodecToolsTest.java create mode 100644 providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/YangCompositeEncodingImplTest.java diff --git a/providers/ietfte/topology/app.xml b/providers/ietfte/app/app.xml similarity index 57% rename from providers/ietfte/topology/app.xml rename to providers/ietfte/app/app.xml index d38fac46f8..09d0850981 100644 --- a/providers/ietfte/topology/app.xml +++ b/providers/ietfte/app/app.xml @@ -14,11 +14,16 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - ${project.description} - mvn:${project.groupId}/${project.artifactId}/${project.version} - mvn:${project.groupId}/onos-app-tenbi-yangmodel/${project.version} + mvn:${project.groupId}/onos-restconf-client-api/${project.version} + mvn:${project.groupId}/onos-restconf-client-ctl/${project.version} + + mvn:${project.groupId}/onos-ietfte-provider-utils/${project.version} + + mvn:${project.groupId}/onos-ietfte-provider-tunnel/${project.version} + mvn:${project.groupId}/onos-app-tenbi-yangmodel/${project.version} diff --git a/providers/ietfte/topology/features.xml b/providers/ietfte/app/features.xml similarity index 76% rename from providers/ietfte/topology/features.xml rename to providers/ietfte/app/features.xml index 3207bacd07..81637797de 100644 --- a/providers/ietfte/topology/features.xml +++ b/providers/ietfte/app/features.xml @@ -20,16 +20,22 @@ description="${project.description}"> onos-api onos-app-tenbi-yangmodel - mvn:${project.groupId}/${project.artifactId}/${project.version} - mvn:${project.groupId}/onos-restconf-client-api/${project.version} - mvn:${project.groupId}/onos-restconf-client-ctl/${project.version} - mvn:org.glassfish.jersey.core/jersey-client/2.22.2 - mvn:commons-io/commons-io/2.4 + mvn:${project.groupId}/onos-restsb-api/${project.version} mvn:org.apache.httpcomponents/httpclient-osgi/4.5.1 mvn:org.apache.httpcomponents/httpcore-osgi/4.4.4 + + mvn:${project.groupId}/onos-restconf-client-api/${project.version} + mvn:${project.groupId}/onos-restconf-client-ctl/${project.version} + + mvn:${project.groupId}/onos-app-tetunnel-api/${project.version} mvn:${project.groupId}/onos-app-tetopology/${project.version} mvn:${project.groupId}/onos-app-yms-api/${project.version} mvn:${project.groupId}/onos-app-tenbi-utils/${project.version} + mvn:${project.groupId}/onos-restconf-server-utils/${project.version} + + mvn:${project.groupId}/onos-ietfte-provider-utils/${project.version} + + mvn:${project.groupId}/onos-ietfte-provider-tunnel/${project.version} diff --git a/providers/ietfte/app/pom.xml b/providers/ietfte/app/pom.xml new file mode 100644 index 0000000000..6251d9fc2f --- /dev/null +++ b/providers/ietfte/app/pom.xml @@ -0,0 +1,49 @@ + + + + + + onos-ietfte-providers + org.onosproject + 1.8.0-SNAPSHOT + + 4.0.0 + + onos-ietfte + bundle + IETF TE provider + + + + org.onosproject + onos-ietfte-provider-utils + ${project.version} + + + org.onosproject + onos-ietfte-provider-topology + ${project.version} + + + org.onosproject + onos-ietfte-provider-tunnel + ${project.version} + + + diff --git a/providers/ietfte/pom.xml b/providers/ietfte/pom.xml index 7297e8f7b8..1d2acd70ed 100644 --- a/providers/ietfte/pom.xml +++ b/providers/ietfte/pom.xml @@ -28,7 +28,34 @@ onos-ietfte-providers pom + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + topology + tunnel + utils + app + + + org.onosproject + onos-app-yms-api + 1.8.0-SNAPSHOT + + + org.onosproject + onos-restconf-server-utils + 1.8.0-SNAPSHOT + + diff --git a/providers/ietfte/topology/pom.xml b/providers/ietfte/topology/pom.xml index 04243e4fb3..ddee4af6b3 100644 --- a/providers/ietfte/topology/pom.xml +++ b/providers/ietfte/topology/pom.xml @@ -30,6 +30,18 @@ bundle IETF TE topology southbound provider + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + @@ -67,6 +79,11 @@ onos-restconf-server-utils ${project.version} + + org.onosproject + onos-ietfte-provider-utils + ${project.version} + diff --git a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java b/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java index 2fd6aec331..8fdf49ce5c 100644 --- a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java +++ b/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/TeTopologyRestconfProvider.java @@ -36,6 +36,8 @@ import org.onosproject.net.provider.ProviderId; import org.onosproject.protocol.rest.RestSBDevice; import org.onosproject.protocol.restconf.RestConfNotificationEventListener; import org.onosproject.protocol.restconf.RestConfSBController; +import org.onosproject.provider.te.utils.DefaultJsonCodec; +import org.onosproject.provider.te.utils.YangCompositeEncodingImpl; import org.onosproject.tetopology.management.api.TeTopologyProvider; import org.onosproject.tetopology.management.api.TeTopologyProviderRegistry; import org.onosproject.tetopology.management.api.TeTopologyProviderService; @@ -155,7 +157,7 @@ public class TeTopologyRestconfProvider extends AbstractProvider codecHandler.addDeviceSchema(IetfNetworkTopology.class); codecHandler.addDeviceSchema(IetfTeTopology.class); // Register JSON CODEC functions - codecHandler.registerOverriddenCodec(new JsonYdtCodec(ymsService), + codecHandler.registerOverriddenCodec(new DefaultJsonCodec(ymsService), YangProtocolEncodingFormat.JSON); appId = coreService.registerApplication(APP_NAME); diff --git a/providers/ietfte/tunnel/pom.xml b/providers/ietfte/tunnel/pom.xml new file mode 100755 index 0000000000..6e07388572 --- /dev/null +++ b/providers/ietfte/tunnel/pom.xml @@ -0,0 +1,73 @@ + + + + + + onos-ietfte-providers + org.onosproject + 1.8.0-SNAPSHOT + + 4.0.0 + bundle + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + onos-ietfte-provider-tunnel + + + org.onosproject + onos-restconf-client-api + ${project.version} + + + org.onosproject + onos-app-yms-api + ${project.version} + + + org.onosproject + onos-app-tetunnel-api + ${project.version} + + + org.onosproject + onos-ietfte-provider-utils + ${project.version} + + + org.onosproject + onos-app-tenbi-yangmodel + ${project.version} + + + org.onosproject + onos-app-tenbi-utils + ${project.version} + + + \ No newline at end of file diff --git a/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java b/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java new file mode 100755 index 0000000000..ff6f2295b6 --- /dev/null +++ b/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/TeTunnelRestconfProvider.java @@ -0,0 +1,354 @@ +/* + * Copyright 2016-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.provider.te.tunnel; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.incubator.net.tunnel.Tunnel; +import org.onosproject.incubator.net.tunnel.TunnelDescription; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelProvider; +import org.onosproject.incubator.net.tunnel.TunnelProviderRegistry; +import org.onosproject.net.DeviceId; +import org.onosproject.net.ElementId; +import org.onosproject.net.Path; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.protocol.restconf.RestConfNotificationEventListener; +import org.onosproject.protocol.restconf.RestConfSBController; +import org.onosproject.provider.te.utils.YangCompositeEncodingImpl; +import org.onosproject.tetopology.management.api.TeTopology; +import org.onosproject.tetopology.management.api.TeTopologyKey; +import org.onosproject.tetopology.management.api.TeTopologyService; +import org.onosproject.tetunnel.api.TeTunnelProviderService; +import org.onosproject.tetunnel.api.TeTunnelService; +import org.onosproject.tetunnel.api.tunnel.DefaultTeTunnel; +import org.onosproject.tetunnel.api.tunnel.TeTunnel; +import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.te.rev20160705.IetfTe; +import org.onosproject.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.te.rev20160705.ietfte.tunnelsgrouping.Tunnels; +import org.onosproject.yms.ych.YangCodecHandler; +import org.onosproject.yms.ych.YangCompositeEncoding; +import org.onosproject.yms.ymsm.YmsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.core.MediaType; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.onosproject.provider.te.utils.CodecTools.jsonToString; +import static org.onosproject.provider.te.utils.CodecTools.toJson; +import static org.onosproject.tetopology.management.api.TeTopology.BIT_MERGED; +import static org.onosproject.teyang.utils.tunnel.TunnelConverter.buildIetfTe; +import static org.onosproject.teyang.utils.tunnel.TunnelConverter.yang2TeTunnel; +import static org.onosproject.yms.ych.YangProtocolEncodingFormat.JSON; +import static org.onosproject.yms.ych.YangResourceIdentifierType.URI; +import static org.onosproject.yms.ydt.YmsOperationType.EDIT_CONFIG_REQUEST; +import static org.onosproject.yms.ydt.YmsOperationType.QUERY_REPLY; + + +/** + * Provider which uses RESTCONF to do cross-domain tunnel creation/deletion/ + * update/deletion and so on operations on the domain networks. + */ + +@Component(immediate = true) +public class TeTunnelRestconfProvider extends AbstractProvider + implements TunnelProvider { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String SCHEMA = "ietf"; + private static final String IETF = "ietf"; + private static final String TE = "te"; + private static final int DEFAULT_INDEX = 1; + private static final String TUNNELS = "tunnels"; + private static final String TUNNELS_URL = IETF + ":" + TE + "/" + TUNNELS; + private static final String MEDIA_TYPE_JSON = "json"; + + private static final String SHOULD_IN_ONE = "Tunnel should be setup in one topo"; + private static final String PROVIDER_ID = "org.onosproject.provider.ietf"; + private static final String RESTCONF_ROOT = "/onos/restconf"; + + private final RestConfNotificationEventListener listener = + new InternalTunnelNotificationListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected RestConfSBController controller; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected YmsService ymsService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TeTunnelService tunnelService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TeTunnelProviderService providerService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TeTopologyService topologyService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TunnelProviderRegistry tunnelProviderRegistry; + + private YangCodecHandler codecHandler; + + @Activate + public void activate() { + tunnelProviderRegistry.register(this); + codecHandler = ymsService.getYangCodecHandler(); + codecHandler.addDeviceSchema(IetfTe.class); + collectInitialTunnels(); + subscribe(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + tunnelProviderRegistry.unregister(this); + unsubscribe(); + log.info("Stopped"); + + } + + public TeTunnelRestconfProvider() { + super(new ProviderId(SCHEMA, PROVIDER_ID)); + } + + private void collectInitialTunnels() { + for (DeviceId deviceId : controller.getDevices().keySet()) { + ObjectNode jsonNodes = executeGetRequest(deviceId); + if (jsonNodes == null) { + continue; + } + ObjectNode tunnelsNode = (ObjectNode) jsonNodes.get(TUNNELS); + if (tunnelsNode == null) { + continue; + } + Tunnels teTunnels = getYangTunnelsObject(tunnelsNode); + if (teTunnels == null) { + continue; + } + updateTeTunnels(teTunnels); + } + } + + private void subscribe() { + for (DeviceId deviceId : controller.getDevices().keySet()) { + try { + controller.enableNotifications(deviceId, TUNNELS_URL, + MEDIA_TYPE_JSON, + listener); + } catch (Exception e) { + log.error("Failed to subscribe for {} : {}", deviceId, + e.getMessage()); + } + } + } + + private void unsubscribe() { + controller.getDevices() + .keySet() + .forEach(deviceId -> controller + .removeNotificationListener(deviceId)); + } + + @Override + public void setupTunnel(Tunnel tunnel, Path path) { + TeTunnel teTunnel = tunnelService.getTeTunnel(tunnel.tunnelId()); + long tid = teTunnel.srcNode().topologyId(); + checkState(tid == teTunnel.dstNode().topologyId(), SHOULD_IN_ONE); + setupTunnel(getOwnDevice(tid), tunnel, path); + } + + @Override + public void setupTunnel(ElementId srcElement, Tunnel tunnel, Path path) { + TeTunnel teTunnel = tunnelService.getTeTunnel(tunnel.tunnelId()); + + IetfTe ietfTe = buildIetfTe(teTunnel); + + YangCompositeEncoding encoding = codecHandler. + encodeCompositeOperation(RESTCONF_ROOT, null, ietfTe, + JSON, EDIT_CONFIG_REQUEST); + String identifier = encoding.getResourceIdentifier(); + String resourceInformation = encoding.getResourceInformation(); + + if (srcElement == null) { + log.error("Can't find remote device for tunnel : {}", tunnel); + return; + } + log.info("Create tunnel get here"); + + controller.post((DeviceId) srcElement, identifier, + new ByteArrayInputStream(resourceInformation.getBytes()), + MediaType.APPLICATION_JSON, ObjectNode.class); + } + + @Override + public void releaseTunnel(Tunnel tunnel) { + //TODO implement release tunnel method + } + + @Override + public void releaseTunnel(ElementId srcElement, Tunnel tunnel) { + //TODO implement release tunnel with src method + } + + @Override + public void updateTunnel(Tunnel tunnel, Path path) { + //TODO implement update tunnel method + + } + + @Override + public void updateTunnel(ElementId srcElement, Tunnel tunnel, Path path) { + //TODO implement update tunnel with src method + } + + @Override + public TunnelId tunnelAdded(TunnelDescription tunnel) { + //TODO implement tunnel add method when te tunnel app merged to core + return null; + } + + @Override + public void tunnelRemoved(TunnelDescription tunnel) { + //TODO implement tunnel remove method when te tunnel app merged to core + + } + + @Override + public void tunnelUpdated(TunnelDescription tunnel) { + //TODO implement tunnel update method when te tunnel app merged to core + } + + @Override + public Tunnel tunnelQueryById(TunnelId tunnelId) { + return null; + } + + private ObjectNode executeGetRequest(DeviceId deviceId) { + //the request url is ietf-te:te/tunnels + //the response node will begin with tunnels + //be careful here to when get the tunnels data + InputStream resultStream = + controller.get(deviceId, TUNNELS_URL, MEDIA_TYPE_JSON); + return toJson(resultStream); + } + + private Tunnels getYangTunnelsObject(ObjectNode tunnelsNode) { + checkNotNull(tunnelsNode, "Input object node should not be null"); + + YangCompositeEncoding yce = + new YangCompositeEncodingImpl(URI, + TUNNELS_URL, + jsonToString(tunnelsNode)); + + Object yo = codecHandler.decode(yce, JSON, QUERY_REPLY); + + if (yo == null) { + log.error("YMS decoder returns null"); + return null; + } + IetfTe ietfTe = null; + Tunnels tunnels = null; + if (yo instanceof List) { + List list = (List) yo; + ietfTe = (IetfTe) list.get(DEFAULT_INDEX); + } + if (ietfTe != null && ietfTe.te() != null) { + tunnels = ietfTe.te().tunnels(); + } + return tunnels; + } + + private void updateTeTunnels(Tunnels tunnels) { + TeTopologyKey key = getTopologyKey(); + + tunnels.tunnel().forEach(tunnel -> { + DefaultTeTunnel teTunnel = yang2TeTunnel(tunnel, key); + providerService.updateTeTunnel(teTunnel); + }); + } + + private TeTopologyKey getTopologyKey() { + TeTopologyKey key = null; + Optional teTopology = topologyService.teTopologies() + .teTopologies() + .values() + .stream() + .filter(topology -> topology.flags().get(BIT_MERGED)) + .findFirst(); + if (teTopology.isPresent()) { + TeTopology topology = teTopology.get(); + key = topology.teTopologyId(); + } + return key; + } + + private DeviceId getOwnDevice(long topologyId) { + DeviceId deviceId = null; + Optional topoOpt = topologyService.teTopologies() + .teTopologies() + .values() + .stream() + .filter(tp -> tp.teTopologyId().topologyId() == topologyId) + .findFirst(); + + if (topoOpt.isPresent()) { + deviceId = topoOpt.get().ownerId(); + } + return deviceId; + } + + private class InternalTunnelNotificationListener implements + RestConfNotificationEventListener { + + @Override + public void handleNotificationEvent(DeviceId deviceId, Object eventJsonString) { + ObjectNode response = toJson((String) eventJsonString); + if (response == null) { + return; + } + JsonNode teNode = response.get(TE); + if (teNode == null) { + log.error("Illegal te json object from {}", deviceId); + return; + } + JsonNode tunnelsNode = teNode.get(TUNNELS); + if (tunnelsNode == null) { + log.error("Illegal tunnel json object from {}", deviceId); + return; + } + + Tunnels tunnels = getYangTunnelsObject((ObjectNode) tunnelsNode); + if (tunnels == null) { + return; + } + updateTeTunnels(tunnels); + } + } +} diff --git a/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/package-info.java b/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/package-info.java new file mode 100644 index 0000000000..5ea68ac08c --- /dev/null +++ b/providers/ietfte/tunnel/src/main/java/org/onosproject/provider/te/tunnel/package-info.java @@ -0,0 +1,19 @@ +/** + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * IETF TE Tunnel provider implementation using RESTCONF protocol. + */ +package org.onosproject.provider.te.tunnel; \ No newline at end of file diff --git a/providers/ietfte/utils/pom.xml b/providers/ietfte/utils/pom.xml new file mode 100755 index 0000000000..3dec655524 --- /dev/null +++ b/providers/ietfte/utils/pom.xml @@ -0,0 +1,46 @@ + + + + + + onos-ietfte-providers + org.onosproject + 1.8.0-SNAPSHOT + + 4.0.0 + onos-ietfte-provider-utils + bundle + + + org.onosproject + onos-app-yms-api + ${project.version} + + + org.onosproject + onos-restconf-server-utils + ${project.version} + + + + + \ No newline at end of file diff --git a/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/CodecTools.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/CodecTools.java new file mode 100644 index 0000000000..d5213ae934 --- /dev/null +++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/CodecTools.java @@ -0,0 +1,95 @@ +/* + * Copyright 2016-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.provider.te.utils; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; + +import java.io.IOException; +import java.io.InputStream; + +import static org.slf4j.LoggerFactory.getLogger; + + +/** + * Convert utility methods for IETF SB. + */ +public final class CodecTools { + private static final Logger log = getLogger(CodecTools.class); + private static final ObjectMapper MAPPER = new ObjectMapper(); + + //no instantiation + private CodecTools() { + } + + /** + * Returns an object node from a InputStream type input which usually comes + * from the HTTP response. + * + * @param stream stream data comes from a HTTP response + * @return object node + */ + public static ObjectNode toJson(InputStream stream) { + ObjectNode response = null; + try { + response = (ObjectNode) MAPPER.readTree(stream); + } catch (IOException e) { + log.error("Parse json string failed {}", e.getMessage()); + } + + return response; + } + + /** + * Returns an object node from a string. + * + * @param jsonString string with JSON format + * @return object node + */ + public static ObjectNode toJson(String jsonString) { + ObjectNode response = null; + try { + response = (ObjectNode) MAPPER.readTree(jsonString); + } catch (IOException e) { + log.error("Parse json string failed {}", e.getMessage()); + } + + return response; + } + + /** + * Returns a JSON format string from a Jackson object node. + * + * @param node JSON object node + * @return string with JSON format + */ + public static String jsonToString(ObjectNode node) { + ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter(); + String jsonString = null; + try { + jsonString = ow.writeValueAsString(node); + } catch (JsonProcessingException e) { + log.error("Parse json to string failed {}", e.getMessage()); + } + + return jsonString; + } +} diff --git a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/JsonYdtCodec.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/DefaultJsonCodec.java old mode 100644 new mode 100755 similarity index 53% rename from providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/JsonYdtCodec.java rename to providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/DefaultJsonCodec.java index f53bac8444..c8b5baec3d --- a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/JsonYdtCodec.java +++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/DefaultJsonCodec.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Open Networking Laboratory + * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,109 +13,98 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onosproject.provider.te.topology; -import com.fasterxml.jackson.databind.ObjectMapper; +package org.onosproject.provider.te.utils; + import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.commons.io.IOUtils; -import org.onosproject.protocol.restconf.server.utils.parser.json.ParserUtils; import org.onosproject.yms.ych.YangCompositeEncoding; import org.onosproject.yms.ych.YangDataTreeCodec; import org.onosproject.yms.ydt.YdtBuilder; +import org.onosproject.yms.ydt.YdtContext; import org.onosproject.yms.ydt.YmsOperationType; import org.onosproject.yms.ymsm.YmsService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.InputStream; - +import static org.onosproject.protocol.restconf.server.utils.parser.json.ParserUtils.convertJsonToYdt; +import static org.onosproject.protocol.restconf.server.utils.parser.json.ParserUtils.convertUriToYdt; +import static org.onosproject.protocol.restconf.server.utils.parser.json.ParserUtils.convertYdtToJson; +import static org.onosproject.provider.te.utils.CodecTools.jsonToString; +import static org.onosproject.provider.te.utils.CodecTools.toJson; +import static org.onosproject.yms.ych.YangResourceIdentifierType.URI; import static org.onosproject.yms.ydt.YdtContextOperationType.NONE; /** * JSON/YDT Codec implementation. */ -public class JsonYdtCodec implements YangDataTreeCodec { - private static final String RESTCONF_ROOT = "restconf/data"; +public class DefaultJsonCodec implements YangDataTreeCodec { + private static final String RESTCONF_ROOT = "/onos/restconf"; + private static final String DATA = "data"; + private static final String SLASH = "/"; - protected final YmsService ymsService; + private final YmsService ymsService; private final Logger log = LoggerFactory.getLogger(getClass()); - public JsonYdtCodec(YmsService service) { + public DefaultJsonCodec(YmsService service) { ymsService = service; } @Override - public String encodeYdtToProtocolFormat(YdtBuilder ydtBuilder) { - String json = ParserUtils.convertYdtToJson(ydtBuilder.getRootNode().getName(), - ydtBuilder.getRootNode(), - ymsService.getYdtWalker()) - .textValue(); - return json; + public String encodeYdtToProtocolFormat(YdtBuilder builder) { + ObjectNode jsonNode = convertYdtToJson(builder.getRootNode().getName(), + builder.getRootNode(), + ymsService.getYdtWalker()); + return jsonToString(jsonNode); } @Override - public YangCompositeEncoding encodeYdtToCompositeProtocolFormat(YdtBuilder ydtBuilder) { - // Mainly for POST/PUT operation. - // YdtBuilder/YdtContext has YdtContextType NONE for URI, - // YdtContextType CREATE/MERGE/REPLACE for Resource data. - - // TODO: Implement this method in Release Ibis for TE Tunnel. - - return null; + public YangCompositeEncoding encodeYdtToCompositeProtocolFormat( + YdtBuilder builder) { + YdtContext rootNode = builder.getRootNode(); + String rootName = rootNode.getName(); + YdtContext child = rootNode.getFirstChild(); + String name = child.getName(); + String url = rootName + SLASH + DATA + SLASH + name; + ObjectNode objectNode = convertYdtToJson(name, child, + ymsService.getYdtWalker()); + String payload = jsonToString((ObjectNode) objectNode.get(name)); + return new YangCompositeEncodingImpl(URI, url, payload); } @Override public YdtBuilder decodeProtocolDataToYdt(String protocolData, - Object schemaRegistryForYdt, + Object schemaRegistry, YmsOperationType opType) { // Get a new builder YdtBuilder builder = ymsService.getYdtBuilder(RESTCONF_ROOT, null, opType, - schemaRegistryForYdt); - ParserUtils.convertJsonToYdt(getObjectNode(protocolData), builder); + schemaRegistry); + + convertJsonToYdt(toJson(protocolData), builder); return builder; } @Override public YdtBuilder decodeCompositeProtocolDataToYdt(YangCompositeEncoding protocolData, - Object schemaRegistryForYdt, + Object schemaRegistry, YmsOperationType opType) { - // opType should be QUERY_REPLY - // Get a new builder + YdtBuilder builder = ymsService.getYdtBuilder(RESTCONF_ROOT, null, opType, - schemaRegistryForYdt); - // Convert the URI to ydtBuilder + schemaRegistry); // YdtContextOperationType should be NONE for URI in QUERY_RESPONSE. - ParserUtils.convertUriToYdt(protocolData.getResourceIdentifier(), builder, NONE); - // Set default operation type for the payload node, is this for resource data? + convertUriToYdt(protocolData.getResourceIdentifier(), builder, NONE); + // NULL/EMPTY for Resource data builder.setDefaultEditOperationType(null); // Convert the payload json body to ydt - ParserUtils.convertJsonToYdt(getObjectNode(protocolData.getResourceInformation()), builder); + convertJsonToYdt(toJson(protocolData.getResourceInformation()), builder); return builder; } - - // Returns an ObjectNode from s JSON string. - private ObjectNode getObjectNode(String json) { - InputStream stream = IOUtils.toInputStream(json); - - ObjectNode rootNode; - ObjectMapper mapper = new ObjectMapper(); - try { - rootNode = (ObjectNode) mapper.readTree(stream); - } catch (IOException e) { - log.error("Can't read stream as a JSON ObjectNode: {}", e); - return null; - } - return rootNode; - } - } diff --git a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/YangCompositeEncodingImpl.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/YangCompositeEncodingImpl.java old mode 100644 new mode 100755 similarity index 54% rename from providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/YangCompositeEncodingImpl.java rename to providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/YangCompositeEncodingImpl.java index 2f025e8918..177c803efd --- a/providers/ietfte/topology/src/main/java/org/onosproject/provider/te/topology/YangCompositeEncodingImpl.java +++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/YangCompositeEncodingImpl.java @@ -1,4 +1,20 @@ -package org.onosproject.provider.te.topology; +/* + * Copyright 2016-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.provider.te.utils; import org.onosproject.yms.ych.YangCompositeEncoding; import org.onosproject.yms.ych.YangResourceIdentifierType; @@ -21,49 +37,43 @@ public class YangCompositeEncodingImpl implements YangCompositeEncoding { /** * Resource identifier type. */ - public YangResourceIdentifierType resourceIdentifierType; + private YangResourceIdentifierType resourceIdentifierType; /** * Creates an instance of YangCompositeEncodingImpl. * - * @param resourceIdentifierType is URI - * @param resourceIdentifier is the URI string - * @param resourceInformation is the JSON body string + * @param resIdType is URI + * @param resId is the URI string + * @param resInfo is the JSON body string */ - public YangCompositeEncodingImpl(YangResourceIdentifierType resourceIdentifierType, - String resourceIdentifier, - String resourceInformation) { - this.resourceIdentifierType = resourceIdentifierType; - this.resourceIdentifier = resourceIdentifier; - this.resourceInformation = resourceInformation; + public YangCompositeEncodingImpl(YangResourceIdentifierType resIdType, + String resId, + String resInfo) { + this.resourceIdentifierType = resIdType; + this.resourceIdentifier = resId; + this.resourceInformation = resInfo; } - @Override public String getResourceIdentifier() { return resourceIdentifier; } - @Override public YangResourceIdentifierType getResourceIdentifierType() { return resourceIdentifierType; } - @Override public String getResourceInformation() { return resourceInformation; } - @Override public void setResourceIdentifier(String resourceId) { resourceIdentifier = resourceId; } - @Override public void setResourceInformation(String resourceInfo) { resourceInformation = resourceInfo; } - @Override public void setResourceIdentifierType(YangResourceIdentifierType idType) { resourceIdentifierType = idType; } diff --git a/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/package-info.java b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/package-info.java new file mode 100644 index 0000000000..74a914e18e --- /dev/null +++ b/providers/ietfte/utils/src/main/java/org/onosproject/provider/te/utils/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2016-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Public codec classes for ietf provider. + */ +package org.onosproject.provider.te.utils; \ No newline at end of file diff --git a/providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/CodecToolsTest.java b/providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/CodecToolsTest.java new file mode 100644 index 0000000000..fefa69ba78 --- /dev/null +++ b/providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/CodecToolsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.provider.te.utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Unit test for codec tools. + */ +public class CodecToolsTest { + private static final ObjectMapper MAP = new ObjectMapper(); + private final ObjectNode simpleObject = MAP.createObjectNode(); + private String simpleString; + + + @Before + public void setup() throws Exception { + simpleObject.put("field1", 1); + simpleString = "{\n" + + " \"field1\" : 1\n" + + "}"; + } + + @Test + public void toJson() throws Exception { + Assert.assertEquals(simpleObject, CodecTools.toJson(simpleString)); + } + + @Test + public void jsonToString() throws Exception { + assertEquals(simpleString, CodecTools.jsonToString(simpleObject)); + } +} \ No newline at end of file diff --git a/providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/YangCompositeEncodingImplTest.java b/providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/YangCompositeEncodingImplTest.java new file mode 100644 index 0000000000..a4906c99f9 --- /dev/null +++ b/providers/ietfte/utils/src/test/java/org/onosproject/provider/te/utils/YangCompositeEncodingImplTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.provider.te.utils; + +import org.junit.Before; +import org.junit.Test; +import org.onosproject.yms.ych.YangCompositeEncoding; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.yms.ych.YangResourceIdentifierType.URI; + +/** + * Unit test for YangCompositeEncodingImpl. + */ +public class YangCompositeEncodingImplTest { + + private YangCompositeEncoding encode; + private static final String RES_ID = "/restconf/data/ietf"; + private static final String RES_INFO = "tunnel"; + private static final String C_FAILED = "Construct failed: "; + + @Before + public void setup() { + encode = new YangCompositeEncodingImpl(URI, + RES_ID, + RES_INFO); + + } + + @Test + public void testConstruction() { + assertEquals(C_FAILED + "type", URI, encode.getResourceIdentifierType()); + assertEquals(C_FAILED + "id", RES_ID, encode.getResourceIdentifier()); + assertEquals(C_FAILED + "info", RES_INFO, encode.getResourceInformation()); + } +} \ No newline at end of file