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.services.provider.simple;
11 import org.opendaylight.alto.commons.helper.NetworkMapIpPrefixHelper;
12 import org.opendaylight.alto.commons.types.converter.CostRequest2EndpointCostServiceInputConverter;
13 import org.opendaylight.alto.commons.types.converter.EndpointCostServiceOutput2CostResponseConverter;
14 import org.opendaylight.alto.commons.types.converter.YANGJSON2RFCCostMapConverter;
15 import org.opendaylight.alto.commons.types.converter.YANGJSON2RFCEndpointPropMapConverter;
16 import org.opendaylight.alto.commons.types.converter.YANGJSON2RFCIRDConverter;
17 import org.opendaylight.alto.commons.types.converter.YANGJSON2RFCNetworkMapConverter;
18 import org.opendaylight.alto.commons.types.rfc7285.RFC7285CostMap;
19 import org.opendaylight.alto.commons.types.rfc7285.RFC7285CostType;
20 import org.opendaylight.alto.commons.types.rfc7285.RFC7285Endpoint;
21 import org.opendaylight.alto.commons.types.rfc7285.RFC7285Endpoint.AddressGroup;
22 import org.opendaylight.alto.commons.types.rfc7285.RFC7285Endpoint.CostRequest;
23 import org.opendaylight.alto.commons.types.rfc7285.RFC7285Endpoint.CostResponse;
24 import org.opendaylight.alto.commons.types.rfc7285.RFC7285Endpoint.PropertyRequest;
25 import org.opendaylight.alto.commons.types.rfc7285.RFC7285Endpoint.PropertyResponse;
26 import org.opendaylight.alto.commons.types.rfc7285.RFC7285EndpointPropertyMap;
27 import org.opendaylight.alto.commons.types.rfc7285.RFC7285IRD;
28 import org.opendaylight.alto.commons.types.rfc7285.RFC7285JSONMapper;
29 import org.opendaylight.alto.commons.types.rfc7285.RFC7285NetworkMap;
30 import org.opendaylight.alto.commons.types.rfc7285.RFC7285VersionTag;
31 import org.opendaylight.alto.services.api.rfc7285.AltoService;
32 import org.opendaylight.alto.services.api.rfc7285.NetworkMapService;
33 import org.opendaylight.alto.services.api.rfc7285.CostMapService;
34 import org.opendaylight.alto.services.api.rfc7285.EndpointCostService;
35 import org.opendaylight.alto.services.api.rfc7285.EndpointPropertyService;
36 import org.opendaylight.alto.services.api.rfc7285.IRDService;
37 import org.opendaylight.alto.commons.helper.ServiceHelper;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.cost.map.map.DstCosts;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.AltoServiceService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.EndpointCostServiceInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.EndpointCostServiceOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.Resources;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.CostMaps;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.EndpointPropertyMap;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.IRD;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.NetworkMaps;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.cost.maps.CostMap;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.cost.maps.CostMapKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.network.maps.NetworkMap;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.rev150404.resources.network.maps.NetworkMapKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.types.rev150404.PidName;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.types.rev150404.ResourceId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.types.rev150404.TypedEndpointAddress;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.types.rev150404.TypedEndpointAddressBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.types.rev150404.ird.Meta;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.alto.service.types.rev150404.ird.meta.DefaultAltoNetworkMap;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.binding.Augmentation;
59 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
60 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
61 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
62 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
63 import org.opendaylight.yangtools.yang.common.RpcResult;
64 import org.osgi.framework.ServiceRegistration;
66 import com.google.common.base.Optional;
67 import com.google.common.util.concurrent.ListenableFuture;
69 import java.util.Iterator;
71 import java.util.LinkedHashMap;
72 import java.util.List;
73 import java.util.LinkedList;
74 import java.util.concurrent.ExecutionException;
75 import java.util.concurrent.Future;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 import com.fasterxml.jackson.core.JsonGenerator;
81 import com.fasterxml.jackson.databind.ObjectMapper;
82 import com.fasterxml.jackson.databind.node.ObjectNode;
83 import com.fasterxml.jackson.databind.JsonSerializer;
84 import com.fasterxml.jackson.databind.SerializerProvider;
85 import com.fasterxml.jackson.databind.module.SimpleModule;
87 @SuppressWarnings("rawtypes")
88 public class SimpleAltoService implements AltoService, AutoCloseable {
90 private final Logger m_logger = LoggerFactory.getLogger(SimpleAltoService.class);
91 private DataBroker m_db = null;
92 private AltoServiceService m_service = null;
94 private ObjectMapper m_mapper = new ObjectMapper();
95 private RFC7285JSONMapper j_mapper = new RFC7285JSONMapper();
96 private List<ServiceRegistration> m_reg = new LinkedList<ServiceRegistration>();
97 private YANGJSON2RFCNetworkMapConverter m_nmconverter = null;
98 private YANGJSON2RFCCostMapConverter m_cmconverter = null;
99 private YANGJSON2RFCEndpointPropMapConverter m_epmconverter = null;
100 private YANGJSON2RFCIRDConverter m_irdconverter = null;
101 private EndpointCostServiceOutput2CostResponseConverter ecsOutputConverter = null;
102 private CostRequest2EndpointCostServiceInputConverter ecsInputConverter = null;
103 private NetworkMapIpPrefixHelper iHelper = new NetworkMapIpPrefixHelper();
104 private final String PRIV_NETWORK_MAP = "private-network-map";
105 private final String PRIV_ENDPOINT_PROPERTY_NAME = "priv:ietf-type";
107 protected class DstCostSerializer extends JsonSerializer<DstCosts> {
109 public void serialize(DstCosts value, JsonGenerator jgen, SerializerProvider provider) {
111 jgen.writeStartObject();
113 jgen.writeObjectFieldStart("dst");
114 jgen.writeStringField("value", value.getDst().getValue());
115 jgen.writeEndObject();
117 Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations
118 = BindingReflections.getAugmentations(value);
120 for (Augmentation<?> aug : augmentations.values()) {
122 ObjectNode node = m_mapper.valueToTree(aug);
123 for (Iterator<String> itr = node.fieldNames(); itr.hasNext();) {
124 String field = itr.next();
125 if (field.toLowerCase().indexOf("cost") >= 0) {
126 cost = node.get(field).asText();
130 } catch (Exception e) {
131 m_logger.warn("Failed to write data from {}", cost);
135 jgen.writeStringField("cost", cost);
138 jgen.writeEndObject();
139 } catch (Exception e) {
140 m_logger.info("Failed to parse DstCosts");
145 public SimpleAltoService(DataBroker db, AltoServiceService service) {
147 this.m_service = service;
148 this.m_nmconverter = new YANGJSON2RFCNetworkMapConverter();
149 this.m_cmconverter = new YANGJSON2RFCCostMapConverter();
150 this.m_epmconverter = new YANGJSON2RFCEndpointPropMapConverter();
151 this.m_irdconverter = new YANGJSON2RFCIRDConverter();
152 this.ecsOutputConverter = new EndpointCostServiceOutput2CostResponseConverter();
153 this.ecsInputConverter = new CostRequest2EndpointCostServiceInputConverter();
155 this.register(IRDService.class);
156 this.register(NetworkMapService.class);
157 this.register(CostMapService.class);
158 this.register(EndpointPropertyService.class);
159 this.register(EndpointCostService.class);
162 SimpleModule module = new SimpleModule();
163 module.addSerializer(DstCosts.class, new DstCostSerializer());
164 m_mapper.registerModule(module);
165 } catch (Exception e) {
166 m_logger.info("failed to load customized serializer");
170 protected <E> void register(Class<E> clazz) {
171 ServiceRegistration reg = ServiceHelper.registerGlobalServiceWReg(clazz, this, null);
175 assert ServiceHelper.getGlobalInstance(clazz, this) != this;
179 public void close() {
180 for (ServiceRegistration reg : this.m_reg) {
187 public RFC7285NetworkMap getDefaultNetworkMap() {
193 public RFC7285NetworkMap getNetworkMap(String id) {
194 m_logger.info("Handling resource-id: {}", id);
195 InstanceIdentifier<NetworkMap> niid = getNetworkMapIID(id);
196 m_logger.info("IID: {}", niid);
199 ReadOnlyTransaction tx = m_db.newReadOnlyTransaction();
200 ListenableFuture<Optional<NetworkMap>> result
201 = tx.read(LogicalDatastoreType.CONFIGURATION, niid);
202 if (result.get().isPresent()) {
203 NetworkMap nm = result.get().get();
204 ObjectNode node = m_mapper.valueToTree(nm);
205 m_logger.info(m_mapper.writeValueAsString(nm));
207 RFC7285NetworkMap ret = m_nmconverter.convert(node);
210 m_logger.info("Failed to read with niid: {}", niid);
212 } catch (Exception e) {
219 public RFC7285NetworkMap getNetworkMap(RFC7285VersionTag vtag) {
220 RFC7285NetworkMap nm = getNetworkMap(vtag.rid);
222 if ((nm != null) && (vtag.equals(nm.meta.vtag))) {
229 public RFC7285NetworkMap getNetworkMap(String id, RFC7285NetworkMap.Filter filter) {
230 RFC7285NetworkMap nm = getNetworkMap(id);
235 LinkedHashMap<String, RFC7285Endpoint.AddressGroup> map = new LinkedHashMap<String, RFC7285Endpoint.AddressGroup>();
236 for (String pid : filter.pids) {
237 if (nm.map.get(pid) != null)
238 map.put(pid, nm.map.get(pid));
240 if (filter.pids.isEmpty()) {
241 map = new LinkedHashMap<String, RFC7285Endpoint.AddressGroup>(nm.map);
243 LinkedHashMap<String, RFC7285Endpoint.AddressGroup> ret = new LinkedHashMap<String, RFC7285Endpoint.AddressGroup>();
244 for (Map.Entry<String, RFC7285Endpoint.AddressGroup> entry : map.entrySet()) {
245 String pid = entry.getKey();
246 if (filter.addressTypes != null && (!filter.addressTypes.isEmpty())) {
247 AddressGroup ag = new AddressGroup();
248 if (filter.addressTypes.contains("ipv4")) {
249 ag.ipv4 = nm.map.get(pid).ipv4;
251 if (filter.addressTypes.contains("ipv6")) {
252 ag.ipv6 = nm.map.get(pid).ipv6;
254 if (!ag.ipv4.isEmpty() || !ag.ipv6.isEmpty())
257 ret.put(pid, entry.getValue());
265 public RFC7285NetworkMap getNetworkMap(RFC7285VersionTag vtag, RFC7285NetworkMap.Filter filter) {
266 RFC7285NetworkMap nm = getNetworkMap(vtag.rid, filter);
267 if ((nm != null) && (vtag.equals(nm.meta.vtag))) {
274 public Boolean validateNetworkMapFilter(String id, RFC7285NetworkMap.Filter filter) {
275 return (filter != null) && (filter.pids != null);
279 public Boolean validateNetworkMapFilter(RFC7285VersionTag vtag, RFC7285NetworkMap.Filter filter) {
280 return validateNetworkMapFilter(vtag.rid, filter);
284 public RFC7285CostMap getCostMap(String id) {
285 m_logger.info("Handling cost-map resource: {}", id);
286 InstanceIdentifier<CostMap> ciid = getCostMapIID(id);
287 m_logger.info("CostMap IID: {}", ciid);
290 ReadOnlyTransaction tx = m_db.newReadOnlyTransaction();
291 ListenableFuture<Optional<CostMap>> result
292 = tx.read(LogicalDatastoreType.CONFIGURATION, ciid);
293 if (result.get().isPresent()) {
294 CostMap cm = result.get().get();
295 m_logger.info(cm.toString());
296 m_logger.info(m_mapper.writeValueAsString(cm));
297 ObjectNode node = m_mapper.valueToTree(cm);
299 RFC7285CostMap ret = m_cmconverter.convert(node);
302 m_logger.info("Failed to read with ciid: {}", ciid);
304 } catch (Exception e) {
311 public RFC7285CostMap getCostMap(RFC7285VersionTag vtag) {
317 public RFC7285CostMap getCostMap(String id, RFC7285CostType type) {
318 RFC7285CostMap cm = getCostMap(id);
321 if (!type.equals(cm.meta.costType))
327 public RFC7285CostMap getCostMap(RFC7285VersionTag vtag, RFC7285CostType type) {
333 public RFC7285CostMap getCostMap(String id, RFC7285CostMap.Filter filter) {
334 RFC7285CostMap cm = getCostMap(id + "-" + filter.costType.metric + "-" + filter.costType.mode);
339 if (filter.pids != null) {
340 if (filter.pids.src.isEmpty())
341 filter.pids.src = new LinkedList<String>(cm.map.keySet());
342 if (filter.pids.dst.isEmpty())
343 filter.pids.dst = new LinkedList<String>(cm.map.keySet());
345 Map<String, Map<String, Object>> data = new LinkedHashMap<String, Map<String, Object>>();
346 for (String src : filter.pids.src) {
347 if (!cm.map.containsKey(src))
349 Map<String, Object> old_data = cm.map.get(src);
350 if (old_data == null)
353 Map<String, Object> new_data = new LinkedHashMap<String, Object>();
354 for (String dst : filter.pids.dst) {
355 if (!old_data.containsKey(dst))
357 if (filter.constraints == null || filter.constraints.isEmpty()
358 || meetConstraints(filter.constraints, old_data.get(dst)))
359 new_data.put(dst, old_data.get(dst));
361 data.put(src, new_data);
368 private boolean meetConstraints(List<String> constraints, Object object) {
369 // We'd better simplify the constraints before using it.
370 for (String constraint : constraints)
371 if (!meetConstraint(constraint, object))
376 private boolean meetConstraint(String constraint, Object object) {
377 String operator = constraint.substring(0, 2);
378 double target = Double.parseDouble(object.toString());
379 double value = Double.parseDouble(constraint.substring(3));
382 return target > value;
384 return target < value;
386 return target >= value;
388 return target <= value;
390 return target == value;
396 public RFC7285CostMap getCostMap(RFC7285VersionTag vtag, RFC7285CostMap.Filter filter) {
402 public Boolean supportCostType(String id, RFC7285CostType type) {
408 public Boolean supportCostType(RFC7285VersionTag vtag, RFC7285CostType type) {
414 public Boolean validateCostMapFilter(String id, RFC7285CostMap.Filter filter) {
420 public Boolean validateCostMapFilter(RFC7285VersionTag vtag, RFC7285CostMap.Filter filter) {
425 protected InstanceIdentifier<DefaultAltoNetworkMap> getDefaultNetworkMapIID() {
426 InstanceIdentifier<DefaultAltoNetworkMap> iid = InstanceIdentifier.builder(Resources.class)
429 .child(DefaultAltoNetworkMap.class).build();
433 protected InstanceIdentifier<NetworkMap> getNetworkMapIID(String resource_id) {
434 NetworkMapKey key = new NetworkMapKey(ResourceId.getDefaultInstance(resource_id));
435 InstanceIdentifier<NetworkMap> iid = InstanceIdentifier.builder(Resources.class)
436 .child(NetworkMaps.class)
437 .child(NetworkMap.class, key)
442 protected InstanceIdentifier<CostMap> getCostMapIID(String resource_id) {
443 CostMapKey key = new CostMapKey(ResourceId.getDefaultInstance(resource_id));
444 InstanceIdentifier<CostMap> iid = InstanceIdentifier.builder(Resources.class)
445 .child(CostMaps.class)
446 .child(CostMap.class, key)
451 protected InstanceIdentifier<EndpointPropertyMap> getEndpointPropertyMapIID() {
452 InstanceIdentifier<EndpointPropertyMap> iid = InstanceIdentifier.builder(Resources.class)
453 .child(EndpointPropertyMap.class).build();
458 public PropertyResponse getEndpointProperty(PropertyRequest request) {
459 InstanceIdentifier<EndpointPropertyMap> eiid = getEndpointPropertyMapIID();
460 m_logger.info("EndpointPropertyMap IID: {}", eiid);
461 updatePrivateNetworkMap();
464 ReadOnlyTransaction tx = m_db.newReadOnlyTransaction();
465 ListenableFuture<Optional<EndpointPropertyMap>> result = tx.read(LogicalDatastoreType.CONFIGURATION, eiid);
466 if (result.get().isPresent()) {
467 EndpointPropertyMap epm = result.get().get();
468 ObjectNode node = m_mapper.valueToTree(epm);
469 m_logger.info(m_mapper.writeValueAsString(epm));
471 RFC7285EndpointPropertyMap endpointPropMap = m_epmconverter.convert(node);
472 RFC7285EndpointPropertyMap ret = new RFC7285EndpointPropertyMap();
473 ret.meta = endpointPropMap.meta;
474 ret.meta.netmap_tags = getDependentTags(endpointPropMap.meta, request.properties);
475 for (String addr : request.endpoints) {
476 Map<String, String> newProps = new LinkedHashMap<String, String>();
477 if (endpointPropMap.map.containsKey(addr.toLowerCase())) {
478 Map<String, String> props = endpointPropMap.map.get(addr);
479 for (String type : request.properties) {
480 if (props.containsKey(type)) {
481 newProps.put(type, props.get(type));
484 } else if (request.properties.contains(PRIV_ENDPOINT_PROPERTY_NAME)) {
485 newProps = getPrivateEndpointProperty(addr);
487 if (!newProps.isEmpty())
488 ret.map.put(addr, newProps);
490 return j_mapper.asPropertyResponse(j_mapper.asJSON(ret));
492 m_logger.info("Failed to read with eiid: {}", eiid);
494 } catch (Exception e) {
500 private void updatePrivateNetworkMap() {
501 InstanceIdentifier<NetworkMap> niid = getNetworkMapIID(PRIV_NETWORK_MAP);
503 ReadOnlyTransaction tx = m_db.newReadOnlyTransaction();
504 ListenableFuture<Optional<NetworkMap>> result
505 = tx.read(LogicalDatastoreType.CONFIGURATION, niid);
506 if (result.get().isPresent()) {
507 NetworkMap privateNetworkMap = result.get().get();
508 iHelper.update(privateNetworkMap);
510 m_logger.info("Failed to read with niid: {}", niid);
512 } catch (Exception e) {
517 private List<RFC7285VersionTag> getDependentTags(RFC7285EndpointPropertyMap.Meta meta, List<String> properties) {
518 List<RFC7285VersionTag> dependentTags = new LinkedList<RFC7285VersionTag>();
519 for (RFC7285VersionTag vtag : meta.netmap_tags) {
520 if (properties.contains(vtag.rid + ".pid"))
521 dependentTags.add(vtag);
523 return dependentTags;
526 private Map<String, String> getPrivateEndpointProperty(String addr) {
527 Map<String, String> property = new LinkedHashMap<String, String>();
529 TypedEndpointAddress address = TypedEndpointAddressBuilder.getDefaultInstance(addr);
530 PidName pid = iHelper.getPIDByEndpointAddress(address);
532 property.put(PRIV_ENDPOINT_PROPERTY_NAME, pid.getValue());
533 } catch (Exception e) {
540 public RFC7285IRD getDefaultIRD() {
541 InstanceIdentifier<IRD> iid = getIRDIID();
544 ReadOnlyTransaction tx = m_db.newReadOnlyTransaction();
545 ListenableFuture<Optional<IRD>> result = tx.read(LogicalDatastoreType.CONFIGURATION, iid);
546 if (result.get().isPresent()) {
547 IRD iIRD = result.get().get();
548 m_logger.info(iIRD.toString());
549 m_logger.info(m_mapper.writeValueAsString(iIRD));
550 ObjectNode node = m_mapper.valueToTree(iIRD);
552 RFC7285IRD ret = m_irdconverter.convert(node);
553 m_logger.info("IRD convert compelete.");
556 m_logger.info("Failed to read with ciid: {}", iid);
558 } catch (Exception e) {
565 public PropertyResponse getEndpointProperty(RFC7285VersionTag vtag, PropertyRequest request) {
570 public CostResponse getEndpointCost(CostRequest request) {
571 CostResponse response = null;
572 EndpointCostServiceInput input = this.ecsInputConverter.convert(request);
573 Future<RpcResult<EndpointCostServiceOutput>> result = this.m_service.endpointCostService(input);
575 EndpointCostServiceOutput output = result.get().getResult();
576 response = this.ecsOutputConverter.convert(output);
577 } catch (InterruptedException | ExecutionException e) {
584 public CostResponse getEndpointCost(RFC7285VersionTag vtag, CostRequest request) {
588 public RFC7285IRD getIRD(String id) {
589 return this.getDefaultIRD();
592 protected InstanceIdentifier<IRD> getIRDIID() {
593 InstanceIdentifier<IRD> iid = InstanceIdentifier.builder(Resources.class).child(IRD.class).build();