/* * 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.pcerest; import static com.google.common.base.Preconditions.checkNotNull; import static org.onosproject.net.Link.State.ACTIVE; import static org.onosproject.net.Link.Type.DIRECT; import com.fasterxml.jackson.databind.node.ArrayNode; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.onosproject.codec.CodecContext; import org.onosproject.codec.JsonCodec; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultLink; import org.onosproject.net.DeviceId; import org.onosproject.net.NetworkResource; import org.onosproject.net.PortNumber; import org.onosproject.net.provider.ProviderId; import org.onosproject.pce.pceservice.ExplicitPathInfo; import org.onosproject.pce.pceservice.PcePath; import org.onosproject.pce.pceservice.DefaultPcePath; import org.onosproject.pce.pceservice.constraint.CostConstraint; import org.onosproject.pce.pceservice.constraint.PceBandwidthConstraint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.JsonNode; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; /** * PCE path json codec. */ public final class PcePathCodec extends JsonCodec<PcePath> { private final Logger log = LoggerFactory.getLogger(PcePathCodec.class); private static final String SOURCE = "source"; private static final String DESTINATION = "destination"; private static final String LSP_TYPE = "pathType"; private static final String SYMBOLIC_PATH_NAME = "name"; private static final String CONSTRAINT = "constraint"; private static final String COST = "cost"; private static final String BANDWIDTH = "bandwidth"; private static final String PATH_ID = "pathId"; private static final String EXPLICIT_PATH_INFO = "explicitPathInfo"; private static final String MISSING_MEMBER_MESSAGE = " member is required in pce-path"; public static final String JSON_NOT_NULL = "JsonNode can not be null"; public static final byte SOURCE_DEVICEID_INDEX = 0; public static final byte SOURCE_PORTNO_INDEX = 1; public static final byte DESTINATION_DEVICEID_INDEX = 2; public static final byte DESTINATION_PORTNO_INDEX = 3; @Override public PcePath decode(ObjectNode json, CodecContext context) { if (json == null || !json.isObject()) { log.error("Empty json input"); return null; } // build pce-path PcePath.Builder resultBuilder = new DefaultPcePath.Builder(); // retrieve source JsonNode jNode = json.get(SOURCE); if (jNode != null) { String src = jNode.asText(); resultBuilder.source(src); } // retrieve destination jNode = json.get(DESTINATION); if (jNode != null) { String dst = jNode.asText(); resultBuilder.destination(dst); } // retrieve lsp-type jNode = json.get(LSP_TYPE); if (jNode != null) { String lspType = jNode.asText(); //Validating LSP type int type = Integer.parseInt(lspType); if ((type < 0) || (type > 2)) { return null; } resultBuilder.lspType(lspType); } // retrieve symbolic-path-name jNode = json.get(SYMBOLIC_PATH_NAME); if (jNode != null) { String name = jNode.asText(); resultBuilder.name(name); } // retrieve constraint JsonNode constraintJNode = (JsonNode) json.path(CONSTRAINT); if ((constraintJNode != null) && (!constraintJNode.isMissingNode())) { // retrieve cost jNode = constraintJNode.get(COST); if (jNode != null) { String cost = jNode.asText(); //Validating Cost type int costType = Integer.parseInt(cost); if ((costType < 1) || (costType > 2)) { return null; } resultBuilder.costConstraint(cost); } // retrieve bandwidth jNode = constraintJNode.get(BANDWIDTH); if (jNode != null) { String bandwidth = jNode.asText(); double bw = Double.parseDouble(bandwidth); if (bw < 0) { return null; } resultBuilder.bandwidthConstraint(bandwidth); } } // Retrieve explicit path info JsonNode explicitPathInfo = json.get(EXPLICIT_PATH_INFO); if (explicitPathInfo != null) { List<ExplicitPathInfo> explicitPathInfoList = ImmutableList.copyOf(jsonNodeToExplicitPathInfo(explicitPathInfo)); if (explicitPathInfoList != null) { resultBuilder.explicitPathInfo(explicitPathInfoList); } } return resultBuilder.build(); } private ExplicitPathInfo createListOfExplicitPathObj(JsonNode node) { int explicitPathType = Integer.parseInt(node.get("type").asText()); DeviceId deviceId; PortNumber portNo; NetworkResource res; LinkedList<ExplicitPathInfo> list = Lists.newLinkedList(); if ((explicitPathType < 0) || (explicitPathType > 1)) { return null; } ExplicitPathInfo.Type type = ExplicitPathInfo.Type.values()[explicitPathType]; String subType = node.get("subtype").asText(); if (Integer.parseInt(subType) == 0) { res = DeviceId.deviceId(node.get("value").asText()); } else if (Integer.parseInt(subType) == 1) { String[] splitted = node.get("value").asText().split("/"); if (splitted[SOURCE_DEVICEID_INDEX] != null && splitted[SOURCE_PORTNO_INDEX] != null && splitted[DESTINATION_DEVICEID_INDEX] != null && splitted[DESTINATION_PORTNO_INDEX] != null) { return null; } deviceId = DeviceId.deviceId(splitted[SOURCE_DEVICEID_INDEX]); portNo = PortNumber.portNumber(splitted[SOURCE_PORTNO_INDEX]); ConnectPoint cpSrc = new ConnectPoint(deviceId, portNo); deviceId = DeviceId.deviceId(splitted[DESTINATION_DEVICEID_INDEX]); portNo = PortNumber.portNumber(splitted[DESTINATION_PORTNO_INDEX]); ConnectPoint cpDst = new ConnectPoint(deviceId, portNo); res = DefaultLink.builder() .providerId(ProviderId.NONE) .src(cpSrc) .dst(cpDst) .type(DIRECT) .state(ACTIVE) .build(); } else { return null; } return new ExplicitPathInfo(type, res); } private Collection<ExplicitPathInfo> jsonNodeToExplicitPathInfo(JsonNode explicitPathInfo) { checkNotNull(explicitPathInfo, JSON_NOT_NULL); Integer i = 0; NetworkResource res; LinkedList<ExplicitPathInfo> list = Lists.newLinkedList(); if (explicitPathInfo.isArray()) { for (JsonNode node : explicitPathInfo) { ExplicitPathInfo obj = createListOfExplicitPathObj(node); if (obj == null) { return null; } list.add(obj); } } else { ExplicitPathInfo obj = createListOfExplicitPathObj(explicitPathInfo); if (obj == null) { return null; } list.add(obj); } return Collections.unmodifiableCollection(list); } @Override public ObjectNode encode(PcePath path, CodecContext context) { checkNotNull(path, "path output cannot be null"); ObjectNode result = context.mapper() .createObjectNode() .put(PATH_ID, path.id().id()) .put(SOURCE, path.source()) .put(DESTINATION, path.destination()) .put(LSP_TYPE, path.lspType().type()) .put(SYMBOLIC_PATH_NAME, path.name()); ObjectNode constraintNode = context.mapper() .createObjectNode() .put(COST, ((CostConstraint) path.costConstraint()).type().type()) .put(BANDWIDTH, ((PceBandwidthConstraint) path.bandwidthConstraint()).bandwidth().bps()); if (path.explicitPathInfo() != null && !path.explicitPathInfo().isEmpty()) { ArrayNode arrayNode = context.mapper().createArrayNode(); for (ExplicitPathInfo e : path.explicitPathInfo()) { ObjectNode node = context.mapper() .createObjectNode() .put("type", e.type().toString()) .put("value", e.value().toString()); arrayNode.add(node); } result.set(EXPLICIT_PATH_INFO, arrayNode); } result.set(CONSTRAINT, constraintNode); return result; } }