Thomas Vachuska
Committed by Gerrit Code Review

ONOS-3515 Added ability to configure different link-weight functions as defaults…

…; or inject custom ones.

ONOS-3516 Added ability to inject alternate graph path search algorithms.

Change-Id: If5831c198a831ae79a9933fc794eb7deab776e2f
...@@ -25,7 +25,6 @@ package org.onosproject.net; ...@@ -25,7 +25,6 @@ package org.onosproject.net;
25 */ 25 */
26 public final class AnnotationKeys { 26 public final class AnnotationKeys {
27 27
28 -
29 // Prohibit instantiation 28 // Prohibit instantiation
30 private AnnotationKeys() { 29 private AnnotationKeys() {
31 } 30 }
...@@ -81,6 +80,12 @@ public final class AnnotationKeys { ...@@ -81,6 +80,12 @@ public final class AnnotationKeys {
81 public static final String DURABLE = "durable"; 80 public static final String DURABLE = "durable";
82 81
83 /** 82 /**
83 + * Annotation key for link metric; used by
84 + * {@link org.onosproject.net.topology.MetricLinkWeight} function.
85 + */
86 + public static final String METRIC = "metric";
87 +
88 + /**
84 * Annotation key for latency. 89 * Annotation key for latency.
85 * 90 *
86 * @deprecated since Cardinal 91 * @deprecated since Cardinal
...@@ -112,8 +117,14 @@ public final class AnnotationKeys { ...@@ -112,8 +117,14 @@ public final class AnnotationKeys {
112 */ 117 */
113 public static final String ROUTER_ID = "routerId"; 118 public static final String ROUTER_ID = "routerId";
114 119
120 + /**
121 + * Annotation key for the static lambda.
122 + */
115 public static final String STATIC_LAMBDA = "staticLambda"; 123 public static final String STATIC_LAMBDA = "staticLambda";
116 124
125 + /**
126 + * Annotation key for the static port.
127 + */
117 public static final String STATIC_PORT = "staticPort"; 128 public static final String STATIC_PORT = "staticPort";
118 129
119 /** 130 /**
......
...@@ -15,22 +15,32 @@ ...@@ -15,22 +15,32 @@
15 */ 15 */
16 package org.onosproject.net.config.basics; 16 package org.onosproject.net.config.basics;
17 17
18 +import com.fasterxml.jackson.databind.JsonNode;
18 import org.onosproject.net.Link; 19 import org.onosproject.net.Link;
19 import org.onosproject.net.LinkKey; 20 import org.onosproject.net.LinkKey;
20 -import com.fasterxml.jackson.databind.JsonNode;
21 21
22 import java.time.Duration; 22 import java.time.Duration;
23 23
24 +import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
25 +
24 /** 26 /**
25 * Basic configuration for network infrastructure link. 27 * Basic configuration for network infrastructure link.
26 */ 28 */
27 public class BasicLinkConfig extends AllowedEntityConfig<LinkKey> { 29 public class BasicLinkConfig extends AllowedEntityConfig<LinkKey> {
28 30
29 public static final String TYPE = "type"; 31 public static final String TYPE = "type";
32 + public static final String METRIC = "metric";
30 public static final String LATENCY = "latency"; 33 public static final String LATENCY = "latency";
31 public static final String BANDWIDTH = "bandwidth"; 34 public static final String BANDWIDTH = "bandwidth";
32 public static final String IS_DURABLE = "durable"; 35 public static final String IS_DURABLE = "durable";
33 36
37 + @Override
38 + public boolean isValid() {
39 + return hasOnlyFields(TYPE, METRIC, LATENCY, BANDWIDTH, IS_DURABLE) &&
40 + isNumber(METRIC, OPTIONAL) && isNumber(LATENCY, OPTIONAL) &&
41 + isNumber(BANDWIDTH, OPTIONAL);
42 + }
43 +
34 /** 44 /**
35 * Returns the link type. 45 * Returns the link type.
36 * 46 *
...@@ -51,6 +61,27 @@ public class BasicLinkConfig extends AllowedEntityConfig<LinkKey> { ...@@ -51,6 +61,27 @@ public class BasicLinkConfig extends AllowedEntityConfig<LinkKey> {
51 } 61 }
52 62
53 /** 63 /**
64 + * Returns link metric value for use by
65 + * {@link org.onosproject.net.topology.MetricLinkWeight} function.
66 + *
67 + * @return link metric; -1 if not set
68 + */
69 + public double metric() {
70 + return get(METRIC, -1);
71 + }
72 +
73 + /**
74 + * Sets the link metric for use by
75 + * {@link org.onosproject.net.topology.MetricLinkWeight} function.
76 + *
77 + * @param metric new metric; null to clear
78 + * @return self
79 + */
80 + public BasicLinkConfig metric(Double metric) {
81 + return (BasicLinkConfig) setOrClear(METRIC, metric);
82 + }
83 +
84 + /**
54 * Returns link latency in terms of nanos. 85 * Returns link latency in terms of nanos.
55 * 86 *
56 * @return link latency; -1 if not set 87 * @return link latency; -1 if not set
......
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.net.topology;
18 +
19 +import org.onlab.util.GeoLocation;
20 +import org.onosproject.net.AnnotationKeys;
21 +import org.onosproject.net.Annotations;
22 +import org.onosproject.net.Device;
23 +import org.onosproject.net.DeviceId;
24 +import org.onosproject.net.device.DeviceService;
25 +
26 +import static java.lang.Double.MAX_VALUE;
27 +
28 +/**
29 + * Link weight for measuring link cost using the geo distance between link
30 + * vertices as determined by the element longitude/latitude annotation.
31 + */
32 +public class GeoDistanceLinkWeight implements LinkWeight {
33 +
34 + private static final double MAX_KM = 40_075 / 2.0;
35 +
36 + private final DeviceService deviceService;
37 +
38 + /**
39 + * Creates a new link-weight with access to the specified device service.
40 + *
41 + * @param deviceService device service reference
42 + */
43 + public GeoDistanceLinkWeight(DeviceService deviceService) {
44 + this.deviceService = deviceService;
45 + }
46 +
47 + @Override
48 + public double weight(TopologyEdge edge) {
49 + GeoLocation src = getLocation(edge.link().src().deviceId());
50 + GeoLocation dst = getLocation(edge.link().dst().deviceId());
51 + return src != null && dst != null ? src.kilometersTo(dst) : MAX_KM;
52 + }
53 +
54 + private GeoLocation getLocation(DeviceId deviceId) {
55 + Device d = deviceService.getDevice(deviceId);
56 + Annotations a = d != null ? d.annotations() : null;
57 + double latitude = getDouble(a, AnnotationKeys.LATITUDE);
58 + double longitude = getDouble(a, AnnotationKeys.LONGITUDE);
59 + return latitude == MAX_VALUE || longitude == MAX_VALUE ? null :
60 + new GeoLocation(latitude, longitude);
61 + }
62 +
63 + private double getDouble(Annotations a, String key) {
64 + String value = a != null ? a.value(key) : null;
65 + try {
66 + return value != null ? Double.parseDouble(value) : MAX_VALUE;
67 + } catch (NumberFormatException e) {
68 + return MAX_VALUE;
69 + }
70 + }
71 +}
72 +
1 +package org.onosproject.net.topology;
2 +
3 +import static org.onosproject.net.Link.State.ACTIVE;
4 +import static org.onosproject.net.Link.Type.INDIRECT;
5 +
6 +/**
7 + * Link weight for measuring link cost as hop count with indirect links
8 + * being as expensive as traversing the entire graph to assume the worst.
9 + */
10 +public class HopCountLinkWeight implements LinkWeight {
11 + private final int indirectLinkCost;
12 +
13 + /**
14 + * Creates a new hop-count weight.
15 + */
16 + public HopCountLinkWeight() {
17 + this.indirectLinkCost = Short.MAX_VALUE;
18 + }
19 +
20 + /**
21 + * Creates a new hop-count weight with the specified cost of indirect links.
22 + */
23 + public HopCountLinkWeight(int indirectLinkCost) {
24 + this.indirectLinkCost = indirectLinkCost;
25 + }
26 +
27 + @Override
28 + public double weight(TopologyEdge edge) {
29 + // To force preference to use direct paths first, make indirect
30 + // links as expensive as the linear vertex traversal.
31 + return edge.link().state() ==
32 + ACTIVE ? (edge.link().type() ==
33 + INDIRECT ? indirectLinkCost : 1) : -1;
34 + }
35 +}
36 +
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.net.topology;
18 +
19 +import org.onosproject.net.AnnotationKeys;
20 +
21 +/**
22 + * Link weight for measuring link cost using the link metric annotation.
23 + */
24 +public class MetricLinkWeight implements LinkWeight {
25 +
26 + @Override
27 + public double weight(TopologyEdge edge) {
28 + String v = edge.link().annotations().value(AnnotationKeys.METRIC);
29 + try {
30 + return v != null ? Double.parseDouble(v) : 1;
31 + } catch (NumberFormatException e) {
32 + return 1;
33 + }
34 + }
35 +}
36 +
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.net.topology;
18 +
19 +import org.onlab.graph.GraphPathSearch;
20 +
21 +/**
22 + * Provides administrative abilities to tailor the path service behaviours.
23 + */
24 +public interface PathAdminService {
25 +
26 + /**
27 + * Sets the specified link-weight function to be used as a default.
28 + * If null is specified, the builtin default hop-count link-weight will be
29 + * used.
30 + *
31 + * @param linkWeight default link-weight function
32 + */
33 + void setDefaultLinkWeight(LinkWeight linkWeight);
34 +
35 + /**
36 + * Sets the specified graph path search algorightm to be used as a default.
37 + * If null is specified, the builtin default all-shortest-paths Dijkstra
38 + * algorithm will be used.
39 + *
40 + * @param graphPathSearch default graph path search algorithm
41 + */
42 + void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch);
43 +
44 +}
...@@ -30,8 +30,9 @@ import java.util.Set; ...@@ -30,8 +30,9 @@ import java.util.Set;
30 public interface PathService { 30 public interface PathService {
31 31
32 /** 32 /**
33 - * Returns the set of all shortest paths, precomputed in terms of hop-count, 33 + * Returns the set of all shortest paths between the specified source and
34 - * between the specified source and destination elements. 34 + * destination elements. The path is computed using the default edge-weight
35 + * function, which by default is hop-count.
35 * 36 *
36 * @param src source element 37 * @param src source element
37 * @param dst destination element 38 * @param dst destination element
...@@ -40,9 +41,9 @@ public interface PathService { ...@@ -40,9 +41,9 @@ public interface PathService {
40 Set<Path> getPaths(ElementId src, ElementId dst); 41 Set<Path> getPaths(ElementId src, ElementId dst);
41 42
42 /** 43 /**
43 - * Returns the set of all shortest paths, computed using the supplied 44 + * Returns the set of all shortest paths between the specified source and
44 - * edge-weight entity, between the specified source and destination 45 + * destination network elements. The path is computed using the supplied
45 - * network elements. 46 + * edge-weight function.
46 * 47 *
47 * @param src source element 48 * @param src source element
48 * @param dst destination element 49 * @param dst destination element
...@@ -52,8 +53,9 @@ public interface PathService { ...@@ -52,8 +53,9 @@ public interface PathService {
52 Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight); 53 Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight);
53 54
54 /** 55 /**
55 - * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, 56 + * Returns the set of all disjoint shortest path pairs between the
56 - * between the specified source and destination devices. 57 + * specified source and destination elements. The path is computed using
58 + * the default edge-weight function, which by default is hop-count.
57 * 59 *
58 * @param src source device 60 * @param src source device
59 * @param dst destination device 61 * @param dst destination device
...@@ -62,8 +64,9 @@ public interface PathService { ...@@ -62,8 +64,9 @@ public interface PathService {
62 Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst); 64 Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst);
63 65
64 /** 66 /**
65 - * Returns the set of all disjoint shortest path pairs, computed using the supplied 67 + * Returns the set of all disjoint shortest path pairs between the
66 - * edge-weight entity, between the specified source and destination devices. 68 + * specified source and destination elements. The path is computed using
69 + * the supplied edge-weight function.
67 * 70 *
68 * @param src source device 71 * @param src source device
69 * @param dst destination device 72 * @param dst destination device
...@@ -74,8 +77,10 @@ public interface PathService { ...@@ -74,8 +77,10 @@ public interface PathService {
74 LinkWeight weight); 77 LinkWeight weight);
75 78
76 /** 79 /**
77 - * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, 80 + * Returns the set of all disjoint shortest path pairs between the
78 - * between the specified source and destination devices. 81 + * specified source and destination elements and taking into consideration
82 + * the provided risk profile. The path is computed using the default
83 + * edge-weight function, which by default is hop-count.
79 * 84 *
80 * @param src source device 85 * @param src source device
81 * @param dst destination device 86 * @param dst destination device
...@@ -86,8 +91,10 @@ public interface PathService { ...@@ -86,8 +91,10 @@ public interface PathService {
86 Map<Link, Object> riskProfile); 91 Map<Link, Object> riskProfile);
87 92
88 /** 93 /**
89 - * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, 94 + * Returns the set of all disjoint shortest path pairs between the
90 - * between the specified source and destination devices. 95 + * specified source and destination elements and taking into consideration
96 + * the provided risk profile. The path is computed using the supplied
97 + * edge-weight function.
91 * 98 *
92 * @param src source device 99 * @param src source device
93 * @param dst destination device 100 * @param dst destination device
...@@ -96,6 +103,7 @@ public interface PathService { ...@@ -96,6 +103,7 @@ public interface PathService {
96 * @return set of all shortest paths between the two devices 103 * @return set of all shortest paths between the two devices
97 */ 104 */
98 Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst, 105 Set<DisjointPath> getDisjointPaths(ElementId src, ElementId dst,
99 - LinkWeight weight, Map<Link, Object> riskProfile); 106 + LinkWeight weight,
107 + Map<Link, Object> riskProfile);
100 108
101 } 109 }
......
...@@ -43,12 +43,15 @@ import org.onosproject.net.topology.ClusterId; ...@@ -43,12 +43,15 @@ import org.onosproject.net.topology.ClusterId;
43 import org.onosproject.net.topology.DefaultTopologyCluster; 43 import org.onosproject.net.topology.DefaultTopologyCluster;
44 import org.onosproject.net.topology.DefaultTopologyVertex; 44 import org.onosproject.net.topology.DefaultTopologyVertex;
45 import org.onosproject.net.topology.GraphDescription; 45 import org.onosproject.net.topology.GraphDescription;
46 +import org.onosproject.net.topology.HopCountLinkWeight;
46 import org.onosproject.net.topology.LinkWeight; 47 import org.onosproject.net.topology.LinkWeight;
47 import org.onosproject.net.topology.Topology; 48 import org.onosproject.net.topology.Topology;
48 import org.onosproject.net.topology.TopologyCluster; 49 import org.onosproject.net.topology.TopologyCluster;
49 import org.onosproject.net.topology.TopologyEdge; 50 import org.onosproject.net.topology.TopologyEdge;
50 import org.onosproject.net.topology.TopologyGraph; 51 import org.onosproject.net.topology.TopologyGraph;
51 import org.onosproject.net.topology.TopologyVertex; 52 import org.onosproject.net.topology.TopologyVertex;
53 +import org.slf4j.Logger;
54 +import org.slf4j.LoggerFactory;
52 55
53 import java.util.HashMap; 56 import java.util.HashMap;
54 import java.util.List; 57 import java.util.List;
...@@ -61,7 +64,6 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -61,7 +64,6 @@ import static com.google.common.base.Preconditions.checkArgument;
61 import static org.onlab.graph.GraphPathSearch.ALL_PATHS; 64 import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
62 import static org.onlab.util.Tools.isNullOrEmpty; 65 import static org.onlab.util.Tools.isNullOrEmpty;
63 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID; 66 import static org.onosproject.core.CoreService.CORE_PROVIDER_ID;
64 -import static org.onosproject.net.Link.State.ACTIVE;
65 import static org.onosproject.net.Link.State.INACTIVE; 67 import static org.onosproject.net.Link.State.INACTIVE;
66 import static org.onosproject.net.Link.Type.INDIRECT; 68 import static org.onosproject.net.Link.Type.INDIRECT;
67 69
...@@ -71,18 +73,22 @@ import static org.onosproject.net.Link.Type.INDIRECT; ...@@ -71,18 +73,22 @@ import static org.onosproject.net.Link.Type.INDIRECT;
71 */ 73 */
72 public class DefaultTopology extends AbstractModel implements Topology { 74 public class DefaultTopology extends AbstractModel implements Topology {
73 75
76 + private static final Logger log = LoggerFactory.getLogger(DefaultTopology.class);
77 +
74 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>(); 78 private static final DijkstraGraphSearch<TopologyVertex, TopologyEdge> DIJKSTRA = new DijkstraGraphSearch<>();
75 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>(); 79 private static final TarjanGraphSearch<TopologyVertex, TopologyEdge> TARJAN = new TarjanGraphSearch<>();
76 - private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE = 80 + private static final SuurballeGraphSearch<TopologyVertex, TopologyEdge> SUURBALLE = new SuurballeGraphSearch<>();
77 - new SuurballeGraphSearch<>();
78 81
82 + private static LinkWeight defaultLinkWeight = null;
83 + private static GraphPathSearch<TopologyVertex, TopologyEdge> defaultGraphPathSearch = null;
79 84
80 private final long time; 85 private final long time;
81 private final long creationTime; 86 private final long creationTime;
82 private final long computeCost; 87 private final long computeCost;
83 private final TopologyGraph graph; 88 private final TopologyGraph graph;
84 89
85 - private final LinkWeight weight; 90 + private final LinkWeight hopCountWeight;
91 +
86 private final Supplier<SccResult<TopologyVertex, TopologyEdge>> clusterResults; 92 private final Supplier<SccResult<TopologyVertex, TopologyEdge>> clusterResults;
87 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters; 93 private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters;
88 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints; 94 private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints;
...@@ -91,6 +97,30 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -91,6 +97,30 @@ public class DefaultTopology extends AbstractModel implements Topology {
91 private final Supplier<ClusterIndexes> clusterIndexes; 97 private final Supplier<ClusterIndexes> clusterIndexes;
92 98
93 /** 99 /**
100 + * Sets the default link-weight to be used when computing paths. If null is
101 + * specified, the builtin default link-weight measuring hop-counts will be
102 + * used.
103 + *
104 + * @param linkWeight new default link-weight
105 + */
106 + public static void setDefaultLinkWeight(LinkWeight linkWeight) {
107 + log.info("Setting new default link-weight function to {}", linkWeight);
108 + defaultLinkWeight = linkWeight;
109 + }
110 +
111 + /**
112 + * Sets the default lpath search algorighm to be used when computing paths.
113 + * If null is specified, the builtin default Dijkstra will be used.
114 + *
115 + * @param graphPathSearch new default algorithm
116 + */
117 + public static void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch) {
118 + log.info("Setting new default graph path algorithm to {}", graphPathSearch);
119 + defaultGraphPathSearch = graphPathSearch;
120 + }
121 +
122 +
123 + /**
94 * Creates a topology descriptor attributed to the specified provider. 124 * Creates a topology descriptor attributed to the specified provider.
95 * 125 *
96 * @param providerId identity of the provider 126 * @param providerId identity of the provider
...@@ -113,7 +143,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -113,7 +143,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
113 143
114 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes()); 144 this.clusterIndexes = Suppliers.memoize(() -> buildIndexes());
115 145
116 - this.weight = new HopCountLinkWeight(graph.getVertexes().size()); 146 + this.hopCountWeight = new HopCountLinkWeight(graph.getVertexes().size());
117 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets()); 147 this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets());
118 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints()); 148 this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints());
119 this.computeCost = Math.max(0, System.nanoTime() - time); 149 this.computeCost = Math.max(0, System.nanoTime() - time);
...@@ -294,7 +324,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -294,7 +324,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
294 * @return set of shortest paths 324 * @return set of shortest paths
295 */ 325 */
296 public Set<Path> getPaths(DeviceId src, DeviceId dst) { 326 public Set<Path> getPaths(DeviceId src, DeviceId dst) {
297 - return getPaths(src, dst, null); 327 + return getPaths(src, dst, linkWeight());
298 } 328 }
299 329
300 /** 330 /**
...@@ -307,8 +337,8 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -307,8 +337,8 @@ public class DefaultTopology extends AbstractModel implements Topology {
307 * @return set of shortest paths 337 * @return set of shortest paths
308 */ 338 */
309 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) { 339 public Set<Path> getPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
310 - final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); 340 + DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
311 - final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); 341 + DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
312 Set<TopologyVertex> vertices = graph.getVertexes(); 342 Set<TopologyVertex> vertices = graph.getVertexes();
313 if (!vertices.contains(srcV) || !vertices.contains(dstV)) { 343 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
314 // src or dst not part of the current graph 344 // src or dst not part of the current graph
...@@ -316,7 +346,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -316,7 +346,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
316 } 346 }
317 347
318 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result = 348 GraphPathSearch.Result<TopologyVertex, TopologyEdge> result =
319 - DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS); 349 + graphPathSearch().search(graph, srcV, dstV, weight, ALL_PATHS);
320 ImmutableSet.Builder<Path> builder = ImmutableSet.builder(); 350 ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
321 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) { 351 for (org.onlab.graph.Path<TopologyVertex, TopologyEdge> path : result.paths()) {
322 builder.add(networkPath(path)); 352 builder.add(networkPath(path));
...@@ -334,7 +364,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -334,7 +364,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
334 * @return set of shortest disjoint path pairs 364 * @return set of shortest disjoint path pairs
335 */ 365 */
336 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) { 366 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst) {
337 - return getDisjointPaths(src, dst, (LinkWeight) null); 367 + return getDisjointPaths(src, dst, linkWeight());
338 } 368 }
339 369
340 /** 370 /**
...@@ -347,8 +377,8 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -347,8 +377,8 @@ public class DefaultTopology extends AbstractModel implements Topology {
347 * @return set of disjoint shortest path pairs 377 * @return set of disjoint shortest path pairs
348 */ 378 */
349 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) { 379 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) {
350 - final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); 380 + DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
351 - final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); 381 + DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
352 Set<TopologyVertex> vertices = graph.getVertexes(); 382 Set<TopologyVertex> vertices = graph.getVertexes();
353 if (!vertices.contains(srcV) || !vertices.contains(dstV)) { 383 if (!vertices.contains(srcV) || !vertices.contains(dstV)) {
354 // src or dst not part of the current graph 384 // src or dst not part of the current graph
...@@ -375,7 +405,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -375,7 +405,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
375 * @return set of shortest disjoint paths 405 * @return set of shortest disjoint paths
376 */ 406 */
377 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight, 407 private Set<DisjointPath> disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight,
378 - Map<TopologyEdge, Object> riskProfile) { 408 + Map<TopologyEdge, Object> riskProfile) {
379 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); 409 DefaultTopologyVertex srcV = new DefaultTopologyVertex(src);
380 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); 410 DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst);
381 411
...@@ -438,7 +468,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -438,7 +468,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
438 * @return set of shortest disjoint paths 468 * @return set of shortest disjoint paths
439 */ 469 */
440 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) { 470 public Set<DisjointPath> getDisjointPaths(DeviceId src, DeviceId dst, Map<Link, Object> riskProfile) {
441 - return getDisjointPaths(src, dst, null, riskProfile); 471 + return getDisjointPaths(src, dst, linkWeight(), riskProfile);
442 } 472 }
443 473
444 // Converts graph path to a network path with the same cost. 474 // Converts graph path to a network path with the same cost.
...@@ -499,8 +529,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -499,8 +529,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
499 529
500 // Processes a map of broadcast sets for each cluster. 530 // Processes a map of broadcast sets for each cluster.
501 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() { 531 private ImmutableSetMultimap<ClusterId, ConnectPoint> buildBroadcastSets() {
502 - Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap 532 + Builder<ClusterId, ConnectPoint> builder = ImmutableSetMultimap.builder();
503 - .builder();
504 for (TopologyCluster cluster : clusters.get().values()) { 533 for (TopologyCluster cluster : clusters.get().values()) {
505 addClusterBroadcastSet(cluster, builder); 534 addClusterBroadcastSet(cluster, builder);
506 } 535 }
...@@ -512,7 +541,7 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -512,7 +541,7 @@ public class DefaultTopology extends AbstractModel implements Topology {
512 // all other devices within the cluster. 541 // all other devices within the cluster.
513 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) { 542 private void addClusterBroadcastSet(TopologyCluster cluster, Builder<ClusterId, ConnectPoint> builder) {
514 // Use the graph root search results to build the broadcast set. 543 // Use the graph root search results to build the broadcast set.
515 - Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1); 544 + Result<TopologyVertex, TopologyEdge> result = DIJKSTRA.search(graph, cluster.root(), null, hopCountWeight, 1);
516 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) { 545 for (Map.Entry<TopologyVertex, Set<TopologyEdge>> entry : result.parents().entrySet()) {
517 TopologyVertex vertex = entry.getKey(); 546 TopologyVertex vertex = entry.getKey();
518 547
...@@ -577,23 +606,12 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -577,23 +606,12 @@ public class DefaultTopology extends AbstractModel implements Topology {
577 linksBuilder.build()); 606 linksBuilder.build());
578 } 607 }
579 608
580 - // Link weight for measuring link cost as hop count with indirect links 609 + private GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch() {
581 - // being as expensive as traversing the entire graph to assume the worst. 610 + return defaultGraphPathSearch != null ? defaultGraphPathSearch : DIJKSTRA;
582 - private static class HopCountLinkWeight implements LinkWeight { 611 + }
583 - private final int indirectLinkCost;
584 -
585 - HopCountLinkWeight(int indirectLinkCost) {
586 - this.indirectLinkCost = indirectLinkCost;
587 - }
588 612
589 - @Override 613 + private LinkWeight linkWeight() {
590 - public double weight(TopologyEdge edge) { 614 + return defaultLinkWeight != null ? defaultLinkWeight : hopCountWeight;
591 - // To force preference to use direct paths first, make indirect
592 - // links as expensive as the linear vertex traversal.
593 - return edge.link().state() ==
594 - ACTIVE ? (edge.link().type() ==
595 - INDIRECT ? indirectLinkCost : 1) : -1;
596 - }
597 } 615 }
598 616
599 // Link weight for preventing traversal over indirect links. 617 // Link weight for preventing traversal over indirect links.
......
...@@ -38,6 +38,7 @@ import org.slf4j.Logger; ...@@ -38,6 +38,7 @@ import org.slf4j.Logger;
38 public final class BasicLinkOperator implements ConfigOperator { 38 public final class BasicLinkOperator implements ConfigOperator {
39 39
40 private static final long DEF_BANDWIDTH = -1L; 40 private static final long DEF_BANDWIDTH = -1L;
41 + private static final double DEF_METRIC = -1;
41 private static final Duration DEF_DURATION = Duration.ofNanos(-1L); 42 private static final Duration DEF_DURATION = Duration.ofNanos(-1L);
42 private static final Logger log = getLogger(BasicLinkOperator.class); 43 private static final Logger log = getLogger(BasicLinkOperator.class);
43 44
...@@ -77,6 +78,9 @@ public final class BasicLinkOperator implements ConfigOperator { ...@@ -77,6 +78,9 @@ public final class BasicLinkOperator implements ConfigOperator {
77 */ 78 */
78 public static SparseAnnotations combine(BasicLinkConfig cfg, SparseAnnotations an) { 79 public static SparseAnnotations combine(BasicLinkConfig cfg, SparseAnnotations an) {
79 DefaultAnnotations.Builder b = DefaultAnnotations.builder(); 80 DefaultAnnotations.Builder b = DefaultAnnotations.builder();
81 + if (cfg.metric() != DEF_METRIC) {
82 + b.set(AnnotationKeys.METRIC, String.valueOf(cfg.metric()));
83 + }
80 if (cfg.latency() != DEF_DURATION) { 84 if (cfg.latency() != DEF_DURATION) {
81 b.set(AnnotationKeys.LATENCY, cfg.latency().toString()); 85 b.set(AnnotationKeys.LATENCY, cfg.latency().toString());
82 } 86 }
......
...@@ -15,44 +15,43 @@ ...@@ -15,44 +15,43 @@
15 */ 15 */
16 package org.onosproject.store.topology.impl; 16 package org.onosproject.store.topology.impl;
17 17
18 -import static com.google.common.base.Preconditions.checkArgument;
19 -import static org.onlab.util.Tools.isNullOrEmpty;
20 -import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
21 -import static org.slf4j.LoggerFactory.getLogger;
22 -
23 -import java.util.Collections;
24 -import java.util.Map;
25 -import java.util.List;
26 -import java.util.Set;
27 -import java.util.stream.Collectors;
28 -
29 import org.apache.felix.scr.annotations.Activate; 18 import org.apache.felix.scr.annotations.Activate;
30 import org.apache.felix.scr.annotations.Component; 19 import org.apache.felix.scr.annotations.Component;
31 import org.apache.felix.scr.annotations.Deactivate; 20 import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Modified;
22 +import org.apache.felix.scr.annotations.Property;
32 import org.apache.felix.scr.annotations.Reference; 23 import org.apache.felix.scr.annotations.Reference;
33 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
34 import org.apache.felix.scr.annotations.Service; 25 import org.apache.felix.scr.annotations.Service;
26 +import org.onlab.graph.GraphPathSearch;
35 import org.onlab.util.KryoNamespace; 27 import org.onlab.util.KryoNamespace;
28 +import org.onosproject.cfg.ComponentConfigService;
36 import org.onosproject.common.DefaultTopology; 29 import org.onosproject.common.DefaultTopology;
37 import org.onosproject.event.Event; 30 import org.onosproject.event.Event;
38 import org.onosproject.mastership.MastershipService; 31 import org.onosproject.mastership.MastershipService;
39 import org.onosproject.net.ConnectPoint; 32 import org.onosproject.net.ConnectPoint;
40 import org.onosproject.net.Device; 33 import org.onosproject.net.Device;
41 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
35 +import org.onosproject.net.DisjointPath;
42 import org.onosproject.net.Link; 36 import org.onosproject.net.Link;
43 import org.onosproject.net.Path; 37 import org.onosproject.net.Path;
44 -import org.onosproject.net.DisjointPath; 38 +import org.onosproject.net.device.DeviceService;
45 import org.onosproject.net.provider.ProviderId; 39 import org.onosproject.net.provider.ProviderId;
46 import org.onosproject.net.topology.ClusterId; 40 import org.onosproject.net.topology.ClusterId;
47 import org.onosproject.net.topology.DefaultGraphDescription; 41 import org.onosproject.net.topology.DefaultGraphDescription;
42 +import org.onosproject.net.topology.GeoDistanceLinkWeight;
48 import org.onosproject.net.topology.GraphDescription; 43 import org.onosproject.net.topology.GraphDescription;
49 import org.onosproject.net.topology.LinkWeight; 44 import org.onosproject.net.topology.LinkWeight;
45 +import org.onosproject.net.topology.MetricLinkWeight;
46 +import org.onosproject.net.topology.PathAdminService;
50 import org.onosproject.net.topology.Topology; 47 import org.onosproject.net.topology.Topology;
51 import org.onosproject.net.topology.TopologyCluster; 48 import org.onosproject.net.topology.TopologyCluster;
49 +import org.onosproject.net.topology.TopologyEdge;
52 import org.onosproject.net.topology.TopologyEvent; 50 import org.onosproject.net.topology.TopologyEvent;
53 import org.onosproject.net.topology.TopologyGraph; 51 import org.onosproject.net.topology.TopologyGraph;
54 import org.onosproject.net.topology.TopologyStore; 52 import org.onosproject.net.topology.TopologyStore;
55 import org.onosproject.net.topology.TopologyStoreDelegate; 53 import org.onosproject.net.topology.TopologyStoreDelegate;
54 +import org.onosproject.net.topology.TopologyVertex;
56 import org.onosproject.store.AbstractStore; 55 import org.onosproject.store.AbstractStore;
57 import org.onosproject.store.serializers.KryoNamespaces; 56 import org.onosproject.store.serializers.KryoNamespaces;
58 import org.onosproject.store.service.EventuallyConsistentMap; 57 import org.onosproject.store.service.EventuallyConsistentMap;
...@@ -60,8 +59,23 @@ import org.onosproject.store.service.EventuallyConsistentMapEvent; ...@@ -60,8 +59,23 @@ import org.onosproject.store.service.EventuallyConsistentMapEvent;
60 import org.onosproject.store.service.EventuallyConsistentMapListener; 59 import org.onosproject.store.service.EventuallyConsistentMapListener;
61 import org.onosproject.store.service.LogicalClockService; 60 import org.onosproject.store.service.LogicalClockService;
62 import org.onosproject.store.service.StorageService; 61 import org.onosproject.store.service.StorageService;
62 +import org.osgi.service.component.ComponentContext;
63 import org.slf4j.Logger; 63 import org.slf4j.Logger;
64 64
65 +import java.util.Collections;
66 +import java.util.Dictionary;
67 +import java.util.List;
68 +import java.util.Map;
69 +import java.util.Objects;
70 +import java.util.Set;
71 +import java.util.stream.Collectors;
72 +
73 +import static com.google.common.base.Preconditions.checkArgument;
74 +import static org.onlab.util.Tools.get;
75 +import static org.onlab.util.Tools.isNullOrEmpty;
76 +import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
77 +import static org.slf4j.LoggerFactory.getLogger;
78 +
65 /** 79 /**
66 * Manages inventory of topology snapshots using trivial in-memory 80 * Manages inventory of topology snapshots using trivial in-memory
67 * structures implementation. 81 * structures implementation.
...@@ -73,9 +87,12 @@ import org.slf4j.Logger; ...@@ -73,9 +87,12 @@ import org.slf4j.Logger;
73 @Service 87 @Service
74 public class DistributedTopologyStore 88 public class DistributedTopologyStore
75 extends AbstractStore<TopologyEvent, TopologyStoreDelegate> 89 extends AbstractStore<TopologyEvent, TopologyStoreDelegate>
76 - implements TopologyStore { 90 + implements TopologyStore, PathAdminService {
77 91
78 private final Logger log = getLogger(getClass()); 92 private final Logger log = getLogger(getClass());
93 +
94 + private static final String FORMAT = "Settings: linkWeightFunction={}";
95 +
79 private volatile DefaultTopology current = 96 private volatile DefaultTopology current =
80 new DefaultTopology(ProviderId.NONE, 97 new DefaultTopology(ProviderId.NONE,
81 new DefaultGraphDescription(0L, System.currentTimeMillis(), 98 new DefaultGraphDescription(0L, System.currentTimeMillis(),
...@@ -91,6 +108,21 @@ public class DistributedTopologyStore ...@@ -91,6 +108,21 @@ public class DistributedTopologyStore
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected MastershipService mastershipService; 109 protected MastershipService mastershipService;
93 110
111 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 + protected ComponentConfigService configService;
113 +
114 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 + protected DeviceService deviceService;
116 +
117 + private static final String HOP_COUNT = "hopCount";
118 + private static final String LINK_METRIC = "linkMetric";
119 + private static final String GEO_DISTANCE = "geoDistance";
120 +
121 + private static final String DEFAULT_LINK_WEIGHT_FUNCTION = "hopCount";
122 + @Property(name = "linkWeightFunction", value = DEFAULT_LINK_WEIGHT_FUNCTION,
123 + label = "Default link-weight function: hopCount, linkMetric, geoDistance")
124 + private String linkWeightFunction = DEFAULT_LINK_WEIGHT_FUNCTION;
125 +
94 // Cluster root to broadcast points bindings to allow convergence to 126 // Cluster root to broadcast points bindings to allow convergence to
95 // a shared broadcast tree; node that is the master of the cluster root 127 // a shared broadcast tree; node that is the master of the cluster root
96 // is the primary. 128 // is the primary.
...@@ -100,7 +132,8 @@ public class DistributedTopologyStore ...@@ -100,7 +132,8 @@ public class DistributedTopologyStore
100 new InternalBroadcastPointListener(); 132 new InternalBroadcastPointListener();
101 133
102 @Activate 134 @Activate
103 - public void activate() { 135 + protected void activate() {
136 + configService.registerProperties(getClass());
104 KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder() 137 KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder()
105 .register(KryoNamespaces.API); 138 .register(KryoNamespaces.API);
106 139
...@@ -114,12 +147,30 @@ public class DistributedTopologyStore ...@@ -114,12 +147,30 @@ public class DistributedTopologyStore
114 } 147 }
115 148
116 @Deactivate 149 @Deactivate
117 - public void deactivate() { 150 + protected void deactivate() {
151 + configService.unregisterProperties(getClass(), false);
118 broadcastPoints.removeListener(listener); 152 broadcastPoints.removeListener(listener);
119 broadcastPoints.destroy(); 153 broadcastPoints.destroy();
120 log.info("Stopped"); 154 log.info("Stopped");
121 } 155 }
122 156
157 + @Modified
158 + protected void modified(ComponentContext context) {
159 + Dictionary<?, ?> properties = context.getProperties();
160 +
161 + String newLinkWeightFunction = get(properties, "linkWeightFunction");
162 + if (newLinkWeightFunction != null &&
163 + !Objects.equals(newLinkWeightFunction, linkWeightFunction)) {
164 + linkWeightFunction = newLinkWeightFunction;
165 + LinkWeight weight = linkWeightFunction.equals(LINK_METRIC) ?
166 + new MetricLinkWeight() :
167 + linkWeightFunction.equals(GEO_DISTANCE) ?
168 + new GeoDistanceLinkWeight(deviceService) : null;
169 + setDefaultLinkWeight(weight);
170 + }
171 + log.info(FORMAT, linkWeightFunction);
172 + }
173 +
123 @Override 174 @Override
124 public Topology currentTopology() { 175 public Topology currentTopology() {
125 return current; 176 return current;
...@@ -263,6 +314,16 @@ public class DistributedTopologyStore ...@@ -263,6 +314,16 @@ public class DistributedTopologyStore
263 return (DefaultTopology) topology; 314 return (DefaultTopology) topology;
264 } 315 }
265 316
317 + @Override
318 + public void setDefaultLinkWeight(LinkWeight linkWeight) {
319 + DefaultTopology.setDefaultLinkWeight(linkWeight);
320 + }
321 +
322 + @Override
323 + public void setDefaultGraphPathSearch(GraphPathSearch<TopologyVertex, TopologyEdge> graphPathSearch) {
324 + DefaultTopology.setDefaultGraphPathSearch(graphPathSearch);
325 + }
326 +
266 private class InternalBroadcastPointListener 327 private class InternalBroadcastPointListener
267 implements EventuallyConsistentMapListener<DeviceId, Set<ConnectPoint>> { 328 implements EventuallyConsistentMapListener<DeviceId, Set<ConnectPoint>> {
268 @Override 329 @Override
......
...@@ -168,7 +168,7 @@ public class NullProviders { ...@@ -168,7 +168,7 @@ public class NullProviders {
168 168
169 169
170 @Activate 170 @Activate
171 - public void activate(ComponentContext context) { 171 + public void activate() {
172 cfgService.registerProperties(getClass()); 172 cfgService.registerProperties(getClass());
173 173
174 deviceProviderService = deviceProviderRegistry.register(deviceProvider); 174 deviceProviderService = deviceProviderRegistry.register(deviceProvider);
...@@ -180,7 +180,7 @@ public class NullProviders { ...@@ -180,7 +180,7 @@ public class NullProviders {
180 } 180 }
181 181
182 @Deactivate 182 @Deactivate
183 - public void deactivate(ComponentContext context) { 183 + public void deactivate() {
184 cfgService.unregisterProperties(getClass(), false); 184 cfgService.unregisterProperties(getClass(), false);
185 tearDown(); 185 tearDown();
186 186
......
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.util;
18 +
19 +import com.google.common.base.MoreObjects;
20 +
21 +/**
22 + * Geo location specified in terms of longitude and latitude.
23 + */
24 +public class GeoLocation {
25 +
26 + public static final double EARTH_RADIUS_KM = 6378.1370D;
27 +
28 + private final double latitude;
29 + private final double longitude;
30 +
31 + /**
32 + * Creates a new location using the specified coordinates.
33 + *
34 + * @param latitude latitude line
35 + * @param longitude longitude line
36 + */
37 + public GeoLocation(double latitude, double longitude) {
38 + this.latitude = latitude;
39 + this.longitude = longitude;
40 + }
41 +
42 + /**
43 + * Returns the latitude of this location.
44 + *
45 + * @return latitude
46 + */
47 + public double latitude() {
48 + return latitude;
49 + }
50 +
51 + /**
52 + * Returns the longitude of this location.
53 + *
54 + * @return longitude
55 + */
56 + public double longitude() {
57 + return longitude;
58 + }
59 +
60 + /**
61 + * Returns the distance in kilometers, between this location and another.
62 + *
63 + * @param other other geo location
64 + * @return distance in kilometers
65 + */
66 + public double kilometersTo(GeoLocation other) {
67 + double hereLat = Math.toRadians(latitude);
68 + double hereLon = Math.toRadians(longitude);
69 + double thereLat = Math.toRadians(other.latitude);
70 + double thereLon = Math.toRadians(other.longitude);
71 +
72 + double cos = Math.sin(hereLat) * Math.sin(thereLat) +
73 + Math.cos(hereLat) * Math.cos(thereLat) * Math.cos(hereLon - thereLon);
74 + return Math.acos(cos) * EARTH_RADIUS_KM;
75 + }
76 +
77 + @Override
78 + public String toString() {
79 + return MoreObjects.toStringHelper(this)
80 + .add("latitude", latitude)
81 + .add("longitude", longitude)
82 + .toString();
83 + }
84 +
85 +}
1 +/*
2 + * Copyright 2014-2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.util;
18 +
19 +import org.junit.Test;
20 +
21 +import static org.junit.Assert.assertEquals;
22 +
23 +/**
24 + * Test suite of the geo location.
25 + */
26 +public class GeoLocationTest {
27 +
28 + @Test
29 + public void basics() {
30 + GeoLocation nLoc = new GeoLocation(40.7127, -74.0059);
31 + GeoLocation wLoc = new GeoLocation(38.9047, -77.0164);
32 +
33 + assertEquals("incorrect latitude", 40.7127, nLoc.latitude(), 0.0001);
34 + assertEquals("incorrect longitude", -74.00598, nLoc.longitude(), 0.0001);
35 + assertEquals("incorrect distance", 326.74, nLoc.kilometersTo(wLoc), 0.01);
36 + }
37 +
38 +}
...\ No newline at end of file ...\ No newline at end of file