2 * Copyright (c) 2015 Yale University and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.alto.core.northbound.route.costmap.impl;
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import com.fasterxml.jackson.core.JsonProcessingException;
15 import com.fasterxml.jackson.databind.JsonNode;
16 import com.fasterxml.jackson.databind.ObjectMapper;
17 import com.fasterxml.jackson.databind.node.ArrayNode;
18 import com.google.common.base.Optional;
19 import org.opendaylight.alto.core.northbound.api.AltoNorthboundRoute;
20 import org.opendaylight.alto.core.northbound.api.AltoNorthboundRouter;
21 import org.opendaylight.alto.core.northbound.api.utils.rfc7285.RFC7285CostMap;
22 import org.opendaylight.alto.core.northbound.api.utils.rfc7285.RFC7285CostType;
23 import org.opendaylight.alto.core.northbound.api.utils.rfc7285.RFC7285VersionTag;
25 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
26 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
29 import org.opendaylight.yang.gen.v1.urn.alto.northbound.route.costmap.rev151021.Records;
30 import org.opendaylight.yang.gen.v1.urn.alto.northbound.route.costmap.rev151021.records.Record;
31 import org.opendaylight.yang.gen.v1.urn.alto.northbound.route.costmap.rev151021.records.RecordKey;
32 import org.opendaylight.yang.gen.v1.urn.alto.resourcepool.rev150921.context.Resource;
33 import org.opendaylight.yang.gen.v1.urn.alto.resourcepool.rev150921.context.resource.ContextTag;
34 import org.opendaylight.yang.gen.v1.urn.alto.resourcepool.rev150921.context.resource.ContextTagKey;
35 import org.opendaylight.yang.gen.v1.urn.alto.types.rev150921.CostMetric;
36 import org.opendaylight.yang.gen.v1.urn.alto.types.rev150921.PidName;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.AltoModelCostmapService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.QueryInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.QueryInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.QueryOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.ResourceTypeCostmap;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.alto.request.costmap.request.CostmapRequestBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.alto.response.costmap.response.CostmapResponse;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.cost.type.data.CostTypeBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.costmap.request.data.CostmapParamsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.costmap.response.data.CostmapResponseData;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.costmap.response.data.costmap.response.data.CostmapSource;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.costmap.response.data.costmap.response.data.costmap.source.CostmapDestination;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rev151021.costmap.response.data.costmap.response.data.costmap.source.costmap.destination.Cost;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rfc7285.rev151021.costmap.filter.data.CostmapFilterBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.model.costmap.rfc7285.rev151021.query.input.request.costmap.request.costmap.params.filter.CostmapFilterDataBuilder;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.opendaylight.yangtools.yang.common.RpcResult;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import javax.ws.rs.Consumes;
58 import javax.ws.rs.GET;
59 import javax.ws.rs.POST;
60 import javax.ws.rs.Path;
61 import javax.ws.rs.PathParam;
62 import javax.ws.rs.Produces;
63 import javax.ws.rs.core.Response;
64 import java.util.HashMap;
65 import java.util.HashSet;
66 import java.util.Iterator;
67 import java.util.LinkedHashMap;
68 import java.util.LinkedList;
69 import java.util.List;
71 import java.util.concurrent.Future;
73 public class AltoNorthboundRouteCostmap implements AltoNorthboundRoute {
74 public static final String COSTMAP_ROUTE = "costmap";
76 public static final String ALTO_COSTMAP_FILTER = "application/alto-costmapfilter+json";
77 public static final String ALTO_COSTMAP = "application/alto-costmap+json";
79 public static final String FIELD_PIDS = "pids";
80 public static final String FIELD_COST_TYPE = "cost-type";
81 public static final String FIELD_COST_MODE = "cost-mode";
82 public static final String FIELD_COST_METRIC = "cost-metric";
83 public static final String FIELD_PID_SOURCE = "srcs";
84 public static final String FIELD_PID_DESTINSTION = "dsts";
86 private ObjectMapper mapper = new ObjectMapper();
87 private static final Logger LOG = LoggerFactory.getLogger(AltoNorthboundRouteCostmap.class);
89 private DataBroker dataBroker = null;
91 private AltoNorthboundRouter router = null;
93 private static AltoModelCostmapService mapService = null;
95 public void setDataBroker(DataBroker dataBroker) {
96 this.dataBroker = dataBroker;
99 public void setMapService(final AltoModelCostmapService mapService) {
100 this.mapService = mapService;
105 if (dataBroker == null) {
106 LOG.error("Failed to init: data broker is null");
110 LOG.info("AltoNorthboundRouteCostmap initiated");
114 public void register(AltoNorthboundRouter router) {
115 this.router = router;
116 this.router.addRoute(COSTMAP_ROUTE, new AltoNorthboundRouteCostmap());
119 public void close() {
120 router.removeRoute(COSTMAP_ROUTE);
125 @Produces({ALTO_COSTMAP, ALTO_ERROR})
126 public Response getFullMap(@PathParam("path") String path) throws JsonProcessingException{
127 QueryInput input = prepareDefaultInput(path, "numerical", "hopcount");
128 Future<RpcResult<QueryOutput>> outputFuture = mapService.query(input);
129 QueryOutput output = null;
131 output = outputFuture.get().getResult();
132 } catch (Exception e) {
133 LOG.warn("get output failed:" , e);
135 Response response = buildOutput(input, output);
139 return Response.status(404).build();
142 @Path("{path}/{mode}")
144 @Produces({ALTO_COSTMAP, ALTO_ERROR})
145 public Response getFullMap(@PathParam("path") String path,
146 @PathParam("mode") String mode) throws JsonProcessingException{
147 QueryInput input = prepareDefaultInput(path, mode, "hopcount");
148 Future<RpcResult<QueryOutput>> outputFuture = mapService.query(input);
149 QueryOutput output = null;
151 output = outputFuture.get().getResult();
152 } catch (Exception e) {
153 LOG.warn("get output failed:" , e);
155 Response response = buildOutput(input, output);
159 return Response.status(404).build();
162 @Path("{path}/{mode}/{metric}")
164 @Produces({ALTO_COSTMAP, ALTO_ERROR})
165 public Response getFullMap(@PathParam("path") String path,
166 @PathParam("mode") String mode,
167 @PathParam("metric") String metric) throws JsonProcessingException{
168 QueryInput input = prepareDefaultInput(path, mode, metric);
169 Future<RpcResult<QueryOutput>> outputFuture = mapService.query(input);
170 QueryOutput output = null;
172 output = outputFuture.get().getResult();
173 } catch (Exception e) {
174 LOG.warn("get output failed:" , e);
176 Response response = buildOutput(input, output);
180 return Response.status(404).build();
185 @Consumes({ALTO_COSTMAP_FILTER})
186 @Produces({ALTO_COSTMAP, ALTO_ERROR})
187 public Response getFilteredMap(@PathParam("path") String path, String filter) throws JsonProcessingException {
190 String cost_mode = null;
191 String cost_metric = null;
192 List<String> pid_source = null;
193 List<String> pid_destination = null;
197 JsonNode filterNode = mapper.readTree(filter);
199 JsonNode _pids = filterNode.get(FIELD_PIDS);
201 error = CostmapRouteChecker.checkMissing(_pids, FIELD_PIDS, filter);
205 error = CostmapRouteChecker.checkList(_pids, FIELD_PIDS, filter);
209 //need check pid_source
210 JsonNode _pid_source = _pids.get(FIELD_PID_SOURCE);
211 error = CostmapRouteChecker.checkList(_pid_source, FIELD_PID_SOURCE, filter);
215 pid_source = arrayNode2List(FIELD_PID_SOURCE, (ArrayNode)_pid_source);
217 //need check pid_destination
218 JsonNode _pid_destination = _pids.get(FIELD_PID_DESTINSTION);
219 error = CostmapRouteChecker.checkList(_pid_destination, FIELD_PID_DESTINSTION, filter);
223 pid_destination = arrayNode2List(FIELD_PID_DESTINSTION, (ArrayNode) _pid_destination);
225 JsonNode _cost_type = filterNode.get(FIELD_COST_TYPE);
226 if(_cost_type == null){
230 cost_mode = _cost_type.get(FIELD_COST_MODE).asText();
231 cost_metric = _cost_type.get(FIELD_COST_METRIC).asText();
235 } catch (JsonProcessingException e) {
237 } catch (Exception e) {
238 return Response.status(500).build();
242 QueryInput input = prepareInput(path, cost_mode, cost_metric, pid_source, pid_destination);
243 Future<RpcResult<QueryOutput>> outputFuture = mapService.query(input);
244 QueryOutput output = null;
246 output = outputFuture.get().getResult();
247 } catch (Exception e) {
248 LOG.warn("get output failed:" , e);
250 Response response = buildOutput(input, output);
254 return Response.status(404).build();
257 protected List<String> arrayNode2List(String field, ArrayNode node) {
258 HashSet<String> retval = new HashSet<String>();
260 for (Iterator<JsonNode> itr = node.elements(); itr.hasNext(); ) {
261 JsonNode data = itr.next();
263 retval.add(data.asText());
265 return new LinkedList<String>(retval);
268 protected QueryInput prepareDefaultInput(String rid, String cost_mode, String cost_metric) {
270 * Set source and destination pids as empty so all PID pairs should be returned.
272 * See https://tools.ietf.org/html/rfc7285#section-11.3.2.3
275 return prepareInput(rid, cost_mode, cost_metric, new LinkedList<String>(), new LinkedList<String>());
278 protected QueryInput prepareInput(String path, String cost_mode, String cost_metric, List<String> pid_source, List<String> pid_destination) {
280 QueryInputBuilder queryInputBuilder = new QueryInputBuilder();
282 CostmapRequestBuilder costmapRequestBuilder = new CostmapRequestBuilder();
283 CostmapParamsBuilder costmapParamsBuilder = new CostmapParamsBuilder();
285 CostTypeBuilder costTypeBuilder = new CostTypeBuilder();
286 costTypeBuilder.setCostMetric(new CostMetric(cost_metric));
287 costTypeBuilder.setCostMode(cost_mode);
289 CostmapFilterBuilder costmapFilterBuilder = new CostmapFilterBuilder();
291 List<PidName> pidNames1 = new LinkedList<PidName>();
292 for (String pid:pid_source){
293 PidName p = new PidName(pid);
296 costmapFilterBuilder.setPidSource(pidNames1);
298 List<PidName> pidNames2 = new LinkedList<PidName>();
299 for (String pid:pid_destination){
300 PidName p = new PidName(pid);
303 costmapFilterBuilder.setPidDestination(pidNames2);
305 CostmapFilterDataBuilder filterdata = new CostmapFilterDataBuilder();
306 filterdata.setCostmapFilter(costmapFilterBuilder.build());
308 costmapParamsBuilder.setFilter(filterdata.build());
309 costmapParamsBuilder.setCostType(costTypeBuilder.build());
311 costmapRequestBuilder.setCostmapParams(costmapParamsBuilder.build());
313 ReadOnlyTransaction rtx = dataBroker.newReadOnlyTransaction();
314 InstanceIdentifier<ContextTag> ctagIID = getResourceByPath(path, rtx);
319 queryInputBuilder.setRequest(costmapRequestBuilder.build());
320 queryInputBuilder.setType(ResourceTypeCostmap.class);
321 queryInputBuilder.setServiceReference(ctagIID);
322 return queryInputBuilder.build();
325 public InstanceIdentifier<ContextTag> getResourceByPath(String path, ReadTransaction transaction){
326 //get iid from (list Records)
327 InstanceIdentifier<Record> recordIID = InstanceIdentifier.builder(Records.class).child(Record.class, new RecordKey(new Uri(path))).build();
329 Future<Optional<Record>> recordFuture = transaction.read(LogicalDatastoreType.CONFIGURATION, recordIID);
330 Optional<Record> optional = null;
332 optional = recordFuture.get();
334 LOG.error("Reading Record failed", e);
337 //get resourceIID from nbr-costmap.yang
338 InstanceIdentifier<?> record2resourceIID = null;
339 if(optional.isPresent())
340 record2resourceIID = optional.get().getResourceIid();
341 InstanceIdentifier<Resource> resourceIID = (InstanceIdentifier<Resource>)record2resourceIID;
342 Future<Optional<Resource>> resourceFuture = transaction.read(LogicalDatastoreType.OPERATIONAL, resourceIID);
344 Optional<Resource> optional1 = null;
346 optional1 = resourceFuture.get();
349 LOG.error("Read resource failed:", e);
352 Resource resource = null;
353 if(optional1.isPresent())
354 resource = optional1.get();
355 InstanceIdentifier<ContextTag> finalresourceIID = resourceIID.child(ContextTag.class, new ContextTagKey(resource.getDefaultTag()));
356 return finalresourceIID;
362 protected RFC7285CostMap.Meta buildMeta(InstanceIdentifier<?> iid, RFC7285CostType costtype) {
363 RFC7285CostMap.Meta meta = new RFC7285CostMap.Meta();
364 RFC7285VersionTag vtag = new RFC7285VersionTag();
365 vtag.rid = iid.firstKeyOf(Resource.class).getResourceId().getValue();
366 vtag.tag = iid.firstKeyOf(ContextTag.class).getTag().getValue();
367 meta.netmap_tags.add(vtag);
368 meta.costType = costtype;
372 //Cost.toString is a String like Ordinal [_cost=2, augmentation=[]],and I need to extrat "_cost=2" from this String
373 protected String getCostValue(Cost cost){
374 String costValue = null;
375 String costString = cost.toString();
376 String[] a1 = costString.split(",");
377 String[] a2 = a1[0].split("=");
382 protected Response buildOutput(QueryInput input, QueryOutput output) throws JsonProcessingException{
384 CostmapResponse costmapResponse = (CostmapResponse)output.getResponse();
385 CostmapResponseData responseData = costmapResponse.getCostmapResponseData();
387 RFC7285CostMap rfccostmap = new RFC7285CostMap();
388 RFC7285CostType rfccosttype = new RFC7285CostType();
390 rfccosttype.mode = responseData.getCostType().getCostMode();
391 rfccosttype.metric = responseData.getCostType().getCostMetric().getValue();
393 Map<String, Map<String, Object>> costmapsource
394 = new LinkedHashMap<String, Map<String, Object>>();
396 for(CostmapSource source:responseData.getCostmapSource()){
398 Map<String, Object> dst2cost = new HashMap<String, Object>();
400 for(CostmapDestination destination:source.getCostmapDestination()){
401 String destinationName = destination.getPidDestination().getValue();
402 Cost pidcost = destination.getCost();
403 dst2cost.put(destinationName, getCostValue(pidcost));
406 costmapsource.put(source.getPidSource().getValue(), dst2cost);
410 rfccostmap.meta = buildMeta(input.getServiceReference(), rfccosttype);
411 rfccostmap.map = costmapsource;
413 String responseString = mapper.writeValueAsString(rfccostmap);
415 return Response.ok(responseString, ALTO_COSTMAP).build();