Clean up handling of lat/long geo-coordinates.
Change-Id: I64fca56c7deb9a8baa6c68558365ec2a8c38168c
Showing
6 changed files
with
144 additions
and
28 deletions
| ... | @@ -30,12 +30,13 @@ public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> { | ... | @@ -30,12 +30,13 @@ public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> { |
| 30 | protected static final String RACK_ADDRESS = "rackAddress"; | 30 | protected static final String RACK_ADDRESS = "rackAddress"; |
| 31 | protected static final String OWNER = "owner"; | 31 | protected static final String OWNER = "owner"; |
| 32 | 32 | ||
| 33 | - protected static final double DEFAULT_COORD = -1.0; | 33 | + protected static final double ZERO_THRESHOLD = Double.MIN_VALUE * 2.0; |
| 34 | + private static final double DEFAULT_COORD = 0.0; | ||
| 34 | 35 | ||
| 35 | /** | 36 | /** |
| 36 | * Returns friendly label for the element. | 37 | * Returns friendly label for the element. |
| 37 | * | 38 | * |
| 38 | - * @return friendly label or element id itself if not set | 39 | + * @return friendly label or element identifier itself if not set |
| 39 | */ | 40 | */ |
| 40 | public String name() { | 41 | public String name() { |
| 41 | return get(NAME, subject.toString()); | 42 | return get(NAME, subject.toString()); |
| ... | @@ -51,10 +52,25 @@ public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> { | ... | @@ -51,10 +52,25 @@ public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> { |
| 51 | return (BasicElementConfig) setOrClear(NAME, name); | 52 | return (BasicElementConfig) setOrClear(NAME, name); |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 55 | + private static boolean doubleIsZero(double value) { | ||
| 56 | + return value >= -ZERO_THRESHOLD && value <= ZERO_THRESHOLD; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Returns true if the geographical coordinates (latitude and longitude) | ||
| 61 | + * are set on this element. | ||
| 62 | + * | ||
| 63 | + * @return true if geo-coordinates are set | ||
| 64 | + */ | ||
| 65 | + public boolean geoCoordsSet() { | ||
| 66 | + return !doubleIsZero(latitude()) || !doubleIsZero(longitude()); | ||
| 67 | + } | ||
| 68 | + | ||
| 54 | /** | 69 | /** |
| 55 | * Returns element latitude. | 70 | * Returns element latitude. |
| 56 | * | 71 | * |
| 57 | - * @return element latitude; -1 if not set | 72 | + * @return element latitude; 0.0 if (possibly) not set |
| 73 | + * @see #geoCoordsSet() | ||
| 58 | */ | 74 | */ |
| 59 | public double latitude() { | 75 | public double latitude() { |
| 60 | return get(LATITUDE, DEFAULT_COORD); | 76 | return get(LATITUDE, DEFAULT_COORD); |
| ... | @@ -71,9 +87,10 @@ public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> { | ... | @@ -71,9 +87,10 @@ public abstract class BasicElementConfig<S> extends AllowedEntityConfig<S> { |
| 71 | } | 87 | } |
| 72 | 88 | ||
| 73 | /** | 89 | /** |
| 74 | - * Returns element latitude. | 90 | + * Returns element longitude. |
| 75 | * | 91 | * |
| 76 | - * @return element latitude; -1 if not set | 92 | + * @return element longitude; 0 if (possibly) not set |
| 93 | + * @see #geoCoordsSet() | ||
| 77 | */ | 94 | */ |
| 78 | public double longitude() { | 95 | public double longitude() { |
| 79 | return get(LONGITUDE, DEFAULT_COORD); | 96 | return get(LONGITUDE, DEFAULT_COORD); | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present 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.config.basics; | ||
| 18 | + | ||
| 19 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 20 | +import org.junit.Before; | ||
| 21 | +import org.junit.Test; | ||
| 22 | + | ||
| 23 | +import static org.junit.Assert.assertEquals; | ||
| 24 | +import static org.junit.Assert.assertFalse; | ||
| 25 | +import static org.junit.Assert.assertTrue; | ||
| 26 | +import static org.onosproject.net.config.basics.BasicElementConfig.ZERO_THRESHOLD; | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * Unit tests for {@link BasicElementConfig}. | ||
| 30 | + */ | ||
| 31 | +public class BasicElementConfigTest { | ||
| 32 | + | ||
| 33 | + private static final ObjectMapper MAPPER = new ObjectMapper(); | ||
| 34 | + | ||
| 35 | + private static final String E1 = "e1"; | ||
| 36 | + | ||
| 37 | + // concrete subclass of abstract class we are testing | ||
| 38 | + private static class ElmCfg extends BasicElementConfig<String> { | ||
| 39 | + ElmCfg() { | ||
| 40 | + object = MAPPER.createObjectNode(); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public String toString() { | ||
| 45 | + return object.toString(); | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + private static void print(String fmt, Object... args) { | ||
| 50 | + System.out.println(String.format(fmt, args)); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + private static void print(Object o) { | ||
| 54 | + print("%s", o); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + private BasicElementConfig<?> cfg; | ||
| 58 | + | ||
| 59 | + @Before | ||
| 60 | + public void setUp() { | ||
| 61 | + cfg = new ElmCfg().name(E1); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @Test | ||
| 65 | + public void basicNoGeo() { | ||
| 66 | + print(cfg); | ||
| 67 | + assertFalse("geo set?", cfg.geoCoordsSet()); | ||
| 68 | + assertEquals("lat", 0.0, cfg.latitude(), ZERO_THRESHOLD); | ||
| 69 | + assertEquals("lon", 0.0, cfg.longitude(), ZERO_THRESHOLD); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Test | ||
| 73 | + public void geoLatitudeOnly() { | ||
| 74 | + cfg.latitude(0.1); | ||
| 75 | + print(cfg); | ||
| 76 | + assertTrue("geo NOT set", cfg.geoCoordsSet()); | ||
| 77 | + assertEquals("lat", 0.1, cfg.latitude(), ZERO_THRESHOLD); | ||
| 78 | + assertEquals("lon", 0.0, cfg.longitude(), ZERO_THRESHOLD); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Test | ||
| 82 | + public void geoLongitudeOnly() { | ||
| 83 | + cfg.longitude(-0.1); | ||
| 84 | + print(cfg); | ||
| 85 | + assertTrue("geo NOT set", cfg.geoCoordsSet()); | ||
| 86 | + assertEquals("lat", 0.0, cfg.latitude(), ZERO_THRESHOLD); | ||
| 87 | + assertEquals("lon", -0.1, cfg.longitude(), ZERO_THRESHOLD); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Test | ||
| 91 | + public void geoLatLong() { | ||
| 92 | + cfg.latitude(3.1415).longitude(2.71828); | ||
| 93 | + print(cfg); | ||
| 94 | + assertTrue("geo NOT set", cfg.geoCoordsSet()); | ||
| 95 | + assertEquals("lat", 3.1415, cfg.latitude(), ZERO_THRESHOLD); | ||
| 96 | + assertEquals("lon", 2.71828, cfg.longitude(), ZERO_THRESHOLD); | ||
| 97 | + } | ||
| 98 | +} |
| ... | @@ -34,8 +34,6 @@ import java.util.Set; | ... | @@ -34,8 +34,6 @@ import java.util.Set; |
| 34 | */ | 34 | */ |
| 35 | public final class BasicHostOperator implements ConfigOperator { | 35 | public final class BasicHostOperator implements ConfigOperator { |
| 36 | 36 | ||
| 37 | - protected static final double DEFAULT_COORD = -1.0; | ||
| 38 | - | ||
| 39 | private BasicHostOperator() { | 37 | private BasicHostOperator() { |
| 40 | } | 38 | } |
| 41 | 39 | ||
| ... | @@ -81,10 +79,8 @@ public final class BasicHostOperator implements ConfigOperator { | ... | @@ -81,10 +79,8 @@ public final class BasicHostOperator implements ConfigOperator { |
| 81 | if (cfg.name() != null) { | 79 | if (cfg.name() != null) { |
| 82 | newBuilder.set(AnnotationKeys.NAME, cfg.name()); | 80 | newBuilder.set(AnnotationKeys.NAME, cfg.name()); |
| 83 | } | 81 | } |
| 84 | - if (cfg.latitude() != DEFAULT_COORD) { | 82 | + if (cfg.geoCoordsSet()) { |
| 85 | newBuilder.set(AnnotationKeys.LATITUDE, Double.toString(cfg.latitude())); | 83 | newBuilder.set(AnnotationKeys.LATITUDE, Double.toString(cfg.latitude())); |
| 86 | - } | ||
| 87 | - if (cfg.longitude() != DEFAULT_COORD) { | ||
| 88 | newBuilder.set(AnnotationKeys.LONGITUDE, Double.toString(cfg.longitude())); | 84 | newBuilder.set(AnnotationKeys.LONGITUDE, Double.toString(cfg.longitude())); |
| 89 | } | 85 | } |
| 90 | if (cfg.rackAddress() != null) { | 86 | if (cfg.rackAddress() != null) { | ... | ... |
| ... | @@ -54,18 +54,20 @@ public class BasicHostOperatorTest { | ... | @@ -54,18 +54,20 @@ public class BasicHostOperatorTest { |
| 54 | private static final BasicHostConfig BHC = new BasicHostConfig(); | 54 | private static final BasicHostConfig BHC = new BasicHostConfig(); |
| 55 | private static final String NAME = "testhost"; | 55 | private static final String NAME = "testhost"; |
| 56 | private static final double LAT = 40.96; | 56 | private static final double LAT = 40.96; |
| 57 | + private static final double LON = 0.0; | ||
| 57 | 58 | ||
| 58 | @Before | 59 | @Before |
| 59 | public void setUp() { | 60 | public void setUp() { |
| 60 | BHC.init(ID, "test", JsonNodeFactory.instance.objectNode(), mapper, delegate); | 61 | BHC.init(ID, "test", JsonNodeFactory.instance.objectNode(), mapper, delegate); |
| 61 | BHC.name(NAME).latitude(40.96); | 62 | BHC.name(NAME).latitude(40.96); |
| 63 | + // if you set lat or long, the other becomes valid as 0.0 (not null) | ||
| 62 | } | 64 | } |
| 63 | 65 | ||
| 64 | @Test | 66 | @Test |
| 65 | public void testDescOps() { | 67 | public void testDescOps() { |
| 66 | HostDescription desc = BasicHostOperator.combine(BHC, HOST); | 68 | HostDescription desc = BasicHostOperator.combine(BHC, HOST); |
| 67 | assertEquals(NAME, desc.annotations().value(AnnotationKeys.NAME)); | 69 | assertEquals(NAME, desc.annotations().value(AnnotationKeys.NAME)); |
| 68 | - assertEquals(null, desc.annotations().value(AnnotationKeys.LONGITUDE)); | 70 | + assertEquals(String.valueOf(LON), desc.annotations().value(AnnotationKeys.LONGITUDE)); |
| 69 | assertEquals(String.valueOf(LAT), desc.annotations().value(AnnotationKeys.LATITUDE)); | 71 | assertEquals(String.valueOf(LAT), desc.annotations().value(AnnotationKeys.LATITUDE)); |
| 70 | } | 72 | } |
| 71 | } | 73 | } | ... | ... |
| ... | @@ -7,12 +7,15 @@ onos ${host} null-simulation stop custom | ... | @@ -7,12 +7,15 @@ onos ${host} null-simulation stop custom |
| 7 | onos ${host} wipe-out please | 7 | onos ${host} wipe-out please |
| 8 | onos ${host} null-simulation start custom | 8 | onos ${host} null-simulation start custom |
| 9 | 9 | ||
| 10 | +# null-create-device <type> <name> <#ports> <latitude> <longitude> | ||
| 11 | +# null-create-link <type> <src> <dst> | ||
| 12 | + | ||
| 10 | onos ${host} <<-EOF | 13 | onos ${host} <<-EOF |
| 11 | 14 | ||
| 12 | -null-create-device switch s1 10 0 0 | 15 | +null-create-device switch s1-Bristol 10 51.4500 -2.5833 |
| 13 | -null-create-device switch s2 10 0 0 | 16 | +null-create-device switch s2-London 10 51.5072 -0.1275 |
| 14 | -null-create-device switch s3 10 0 0 | 17 | +null-create-device switch s3-Dover 10 51.1295 1.3089 |
| 15 | -null-create-device switch s4 10 0 0 | 18 | +null-create-device switch s4-Brighton 10 50.8429 -0.1313 |
| 16 | null-create-device switch s5 10 0 0 | 19 | null-create-device switch s5 10 0 0 |
| 17 | null-create-device switch s6 10 0 0 | 20 | null-create-device switch s6 10 0 0 |
| 18 | null-create-device switch s7 10 0 0 | 21 | null-create-device switch s7 10 0 0 |
| ... | @@ -20,11 +23,11 @@ null-create-device switch s8 10 0 0 | ... | @@ -20,11 +23,11 @@ null-create-device switch s8 10 0 0 |
| 20 | null-create-device switch s9 10 0 0 | 23 | null-create-device switch s9 10 0 0 |
| 21 | # null-create-device switch s10 10 0 0 | 24 | # null-create-device switch s10 10 0 0 |
| 22 | 25 | ||
| 23 | -null-create-link direct s1 s2 | 26 | +null-create-link direct s1-Bristol s2-London |
| 24 | -null-create-link direct s2 s3 | 27 | +null-create-link direct s2-London s3-Dover |
| 25 | -null-create-link direct s2 s4 | 28 | +null-create-link direct s2-London s4-Brighton |
| 26 | -null-create-link direct s3 s4 | 29 | +null-create-link direct s3-Dover s4-Brighton |
| 27 | -null-create-link direct s3 s5 | 30 | +null-create-link direct s3-Dover s5 |
| 28 | null-create-link direct s6 s5 | 31 | null-create-link direct s6 s5 |
| 29 | null-create-link direct s6 s8 | 32 | null-create-link direct s6 s8 |
| 30 | null-create-link direct s7 s9 | 33 | null-create-link direct s7 s9 | ... | ... |
| ... | @@ -31,7 +31,6 @@ import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; | ... | @@ -31,7 +31,6 @@ import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; |
| 31 | import org.onosproject.incubator.net.tunnel.Tunnel; | 31 | import org.onosproject.incubator.net.tunnel.Tunnel; |
| 32 | import org.onosproject.incubator.net.tunnel.TunnelService; | 32 | import org.onosproject.incubator.net.tunnel.TunnelService; |
| 33 | import org.onosproject.mastership.MastershipService; | 33 | import org.onosproject.mastership.MastershipService; |
| 34 | -import org.onosproject.net.ElementId; | ||
| 35 | import org.onosproject.net.Annotated; | 34 | import org.onosproject.net.Annotated; |
| 36 | import org.onosproject.net.AnnotationKeys; | 35 | import org.onosproject.net.AnnotationKeys; |
| 37 | import org.onosproject.net.Annotations; | 36 | import org.onosproject.net.Annotations; |
| ... | @@ -40,6 +39,7 @@ import org.onosproject.net.DefaultEdgeLink; | ... | @@ -40,6 +39,7 @@ import org.onosproject.net.DefaultEdgeLink; |
| 40 | import org.onosproject.net.Device; | 39 | import org.onosproject.net.Device; |
| 41 | import org.onosproject.net.DeviceId; | 40 | import org.onosproject.net.DeviceId; |
| 42 | import org.onosproject.net.EdgeLink; | 41 | import org.onosproject.net.EdgeLink; |
| 42 | +import org.onosproject.net.ElementId; | ||
| 43 | import org.onosproject.net.Host; | 43 | import org.onosproject.net.Host; |
| 44 | import org.onosproject.net.HostId; | 44 | import org.onosproject.net.HostId; |
| 45 | import org.onosproject.net.HostLocation; | 45 | import org.onosproject.net.HostLocation; |
| ... | @@ -77,8 +77,8 @@ import java.util.HashSet; | ... | @@ -77,8 +77,8 @@ import java.util.HashSet; |
| 77 | import java.util.Iterator; | 77 | import java.util.Iterator; |
| 78 | import java.util.List; | 78 | import java.util.List; |
| 79 | import java.util.Map; | 79 | import java.util.Map; |
| 80 | -import java.util.Set; | ||
| 81 | import java.util.Optional; | 80 | import java.util.Optional; |
| 81 | +import java.util.Set; | ||
| 82 | import java.util.concurrent.ConcurrentHashMap; | 82 | import java.util.concurrent.ConcurrentHashMap; |
| 83 | 83 | ||
| 84 | import static com.google.common.base.Preconditions.checkNotNull; | 84 | import static com.google.common.base.Preconditions.checkNotNull; |
| ... | @@ -94,6 +94,8 @@ import static org.onosproject.ui.topo.TopoUtils.compactLinkString; | ... | @@ -94,6 +94,8 @@ import static org.onosproject.ui.topo.TopoUtils.compactLinkString; |
| 94 | */ | 94 | */ |
| 95 | public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { | 95 | public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { |
| 96 | 96 | ||
| 97 | + private static final String NO_GEO_VALUE = "0.0"; | ||
| 98 | + | ||
| 97 | // default to an "add" event... | 99 | // default to an "add" event... |
| 98 | private static final DefaultHashMap<ClusterEvent.Type, String> CLUSTER_EVENT = | 100 | private static final DefaultHashMap<ClusterEvent.Type, String> CLUSTER_EVENT = |
| 99 | new DefaultHashMap<>("addInstance"); | 101 | new DefaultHashMap<>("addInstance"); |
| ... | @@ -361,10 +363,10 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { | ... | @@ -361,10 +363,10 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { |
| 361 | 363 | ||
| 362 | String slng = annotations.value(AnnotationKeys.LONGITUDE); | 364 | String slng = annotations.value(AnnotationKeys.LONGITUDE); |
| 363 | String slat = annotations.value(AnnotationKeys.LATITUDE); | 365 | String slat = annotations.value(AnnotationKeys.LATITUDE); |
| 364 | - boolean haveLng = slng != null && !slng.isEmpty(); | 366 | + boolean validLng = slng != null && !slng.equals(NO_GEO_VALUE); |
| 365 | - boolean haveLat = slat != null && !slat.isEmpty(); | 367 | + boolean validLat = slat != null && !slat.equals(NO_GEO_VALUE); |
| 368 | + if (validLat && validLng) { | ||
| 366 | try { | 369 | try { |
| 367 | - if (haveLng && haveLat) { | ||
| 368 | double lng = Double.parseDouble(slng); | 370 | double lng = Double.parseDouble(slng); |
| 369 | double lat = Double.parseDouble(slat); | 371 | double lat = Double.parseDouble(slat); |
| 370 | ObjectNode loc = objectNode() | 372 | ObjectNode loc = objectNode() |
| ... | @@ -372,13 +374,11 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { | ... | @@ -372,13 +374,11 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { |
| 372 | .put("lng", lng) | 374 | .put("lng", lng) |
| 373 | .put("lat", lat); | 375 | .put("lat", lat); |
| 374 | payload.set("location", loc); | 376 | payload.set("location", loc); |
| 375 | - } else { | ||
| 376 | - log.trace("missing Lng/Lat: lng={}, lat={}", slng, slat); | ||
| 377 | - } | ||
| 378 | } catch (NumberFormatException e) { | 377 | } catch (NumberFormatException e) { |
| 379 | log.warn("Invalid geo data: longitude={}, latitude={}", slng, slat); | 378 | log.warn("Invalid geo data: longitude={}, latitude={}", slng, slat); |
| 380 | } | 379 | } |
| 381 | } | 380 | } |
| 381 | + } | ||
| 382 | 382 | ||
| 383 | // Updates meta UI information for the specified object. | 383 | // Updates meta UI information for the specified object. |
| 384 | protected void updateMetaUi(ObjectNode payload) { | 384 | protected void updateMetaUi(ObjectNode payload) { | ... | ... |
-
Please register or login to post a comment