tom

Working on model & description annotations.

Showing 22 changed files with 267 additions and 180 deletions
package org.onlab.onos.net;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
/**
......@@ -13,13 +7,13 @@ import static com.google.common.base.Preconditions.checkArgument;
*/
public class AbstractAnnotated implements Annotated {
private static final Map<String, String> EMPTY = new HashMap<>();
private static final Annotations EMPTY = DefaultAnnotations.builder().build();
private final Map<String, String> annotations;
private final Annotations annotations;
// For serialization
protected AbstractAnnotated() {
this.annotations = EMPTY;
this.annotations = null;
}
/**
......@@ -27,19 +21,14 @@ public class AbstractAnnotated implements Annotated {
*
* @param annotations optional key/value annotations map
*/
protected AbstractAnnotated(Map<String, String>[] annotations) {
protected AbstractAnnotated(Annotations... annotations) {
checkArgument(annotations.length <= 1, "Only one set of annotations is expected");
this.annotations = annotations.length == 1 ? annotations[0] : EMPTY;
}
@Override
public Set<String> annotationKeys() {
return ImmutableSet.copyOf(annotations.keySet());
}
@Override
public String annotation(String key) {
return annotations.get(key);
public Annotations annotations() {
return annotations;
}
}
......
package org.onlab.onos.net;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Base implementation of an annotated model description.
*/
public class AbstractDescription implements Annotated {
private static final SparseAnnotations EMPTY = DefaultAnnotations.builder().build();
private final SparseAnnotations annotations;
// For serialization
protected AbstractDescription() {
this.annotations = null;
}
/**
* Creates a new entity, annotated with the specified annotations.
*
* @param annotations optional key/value annotations map
*/
protected AbstractDescription(SparseAnnotations... annotations) {
checkArgument(annotations.length <= 1, "Only one set of annotations is expected");
this.annotations = annotations.length == 1 ? annotations[0] : EMPTY;
}
@Override
public SparseAnnotations annotations() {
return annotations;
}
}
......@@ -17,11 +17,13 @@ public class AbstractElement extends AbstractModel implements Element {
/**
* Creates a network element attributed to the specified provider.
*
* @param providerId identity of the provider
* @param id element identifier
* @param providerId identity of the provider
* @param id element identifier
* @param annotations optional key/value annotations
*/
protected AbstractElement(ProviderId providerId, ElementId id) {
super(providerId);
protected AbstractElement(ProviderId providerId, ElementId id,
Annotations... annotations) {
super(providerId, annotations);
this.id = id;
}
......
......@@ -2,8 +2,6 @@ package org.onlab.onos.net;
import org.onlab.onos.net.provider.ProviderId;
import java.util.Map;
/**
* Base implementation of a network model entity.
*/
......@@ -23,9 +21,7 @@ public class AbstractModel extends AbstractAnnotated implements Provided {
* @param providerId identity of the provider
* @param annotations optional key/value annotations
*/
@SafeVarargs
protected AbstractModel(ProviderId providerId,
Map<String, String>... annotations) {
protected AbstractModel(ProviderId providerId, Annotations... annotations) {
super(annotations);
this.providerId = providerId;
}
......
package org.onlab.onos.net;
import java.util.Set;
/**
* Represents an entity that carries arbitrary annotations.
*/
public interface Annotated {
/**
* Returns the set of annotation keys currently available.
*
* @return set of annotation keys
*/
Set<String> annotationKeys();
/**
* Returns the annotation value for the specified key.
* Returns the key/value annotations.
*
* @param key annotation key
* @return annotation value; null if there is no annotation
* @return key/value annotations
*/
String annotation(String key);
Annotations annotations();
}
......
package org.onlab.onos.net;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* Represents a set of simple annotations that can be used to add arbitrary
* attributes to various parts of the data model.
* Represents an set of simply key/value string annotations.
*/
public final class Annotations {
private final Map<String, String> map;
/**
* Creates a new set of annotations using the specified immutable map.
*
* @param map immutable map of key/value pairs
*/
private Annotations(ImmutableMap<String, String> map) {
this.map = map;
}
public interface Annotations {
/**
* Creates a new annotations builder.
*
* @return new annotations builder
*/
public static Builder builder() {
return new Builder();
}
/**
* Returns the set of keys for available annotations. Note that this set
* includes keys for any attributes tagged for removal.
* Returns the set of keys for available annotations.
*
* @return annotation keys
*/
public Set<String> keys() {
return map.keySet();
}
public Set<String> keys();
/**
* Returns the value of the specified annotation.
......@@ -48,66 +20,6 @@ public final class Annotations {
* @param key annotation key
* @return annotation value
*/
public String value(String key) {
String value = map.get(key);
return Objects.equals(Builder.REMOVED, value) ? null : value;
}
/**
* Indicates whether the specified key has been tagged as removed. This is
* used to for merging sparse annotation sets.
*
* @param key annotation key
* @return true if the previous annotation has been tagged for removal
*/
public boolean isRemoved(String key) {
return Objects.equals(Builder.REMOVED, map.get(key));
}
/**
* Facility for gradually building model annotations.
*/
public static final class Builder {
private static final String REMOVED = "~rEmOvEd~";
private final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
// Private construction is forbidden.
private Builder() {
}
/**
* Adds the specified annotation. Any previous value associated with
* the given annotation key will be overwritten.
*
* @param key annotation key
* @param value annotation value
* @return self
*/
public Builder set(String key, String value) {
builder.put(key, value);
return this;
}
/**
* Adds the specified annotation. Any previous value associated with
* the given annotation key will be tagged for removal.
*
* @param key annotation key
* @return self
*/
public Builder remove(String key) {
builder.put(key, REMOVED);
return this;
}
public String value(String key);
/**
* Returns immutable annotations built from the accrued key/values pairs.
*
* @return annotations
*/
public Annotations build() {
return new Annotations(builder.build());
}
}
}
......
package org.onlab.onos.net;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* Represents a set of simple annotations that can be used to add arbitrary
* attributes to various parts of the data model.
*/
public final class DefaultAnnotations implements SparseAnnotations {
private final Map<String, String> map;
// For serialization
private DefaultAnnotations() {
this.map = null;
}
/**
* Creates a new set of annotations using the specified immutable map.
*
* @param map immutable map of key/value pairs
*/
private DefaultAnnotations(Map<String, String> map) {
this.map = map;
}
/**
* Creates a new annotations builder.
*
* @return new annotations builder
*/
public static Builder builder() {
return new Builder();
}
@Override
public Set<String> keys() {
return map.keySet();
}
@Override
public String value(String key) {
String value = map.get(key);
return Objects.equals(Builder.REMOVED, value) ? null : value;
}
@Override
public boolean isRemoved(String key) {
return Objects.equals(Builder.REMOVED, map.get(key));
}
/**
* Facility for gradually building model annotations.
*/
public static final class Builder {
private static final String REMOVED = "~rEmOvEd~";
// FIXME: Figure out whether and how to make this immutable and serializable
// private final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
private final Map<String, String> builder = new HashMap<>();
// Private construction is forbidden.
private Builder() {
}
/**
* Adds the specified annotation. Any previous value associated with
* the given annotation key will be overwritten.
*
* @param key annotation key
* @param value annotation value
* @return self
*/
public Builder set(String key, String value) {
builder.put(key, value);
return this;
}
/**
* Adds the specified annotation. Any previous value associated with
* the given annotation key will be tagged for removal.
*
* @param key annotation key
* @return self
*/
public Builder remove(String key) {
builder.put(key, REMOVED);
return this;
}
/**
* Returns immutable annotations built from the accrued key/values pairs.
*
* @return annotations
*/
public DefaultAnnotations build() {
// return new DefaultAnnotations(builder.build());
return new DefaultAnnotations(builder);
}
}
}
......@@ -36,11 +36,12 @@ public class DefaultDevice extends AbstractElement implements Device {
* @param hwVersion device HW version
* @param swVersion device SW version
* @param serialNumber device serial number
* @param annotations optional key/value annotations
*/
public DefaultDevice(ProviderId providerId, DeviceId id, Type type,
String manufacturer, String hwVersion, String swVersion,
String serialNumber) {
super(providerId, id);
String serialNumber, Annotations... annotations) {
super(providerId, id, annotations);
this.type = type;
this.manufacturer = manufacturer;
this.hwVersion = hwVersion;
......
......@@ -20,11 +20,13 @@ public class DefaultEdgeLink extends DefaultLink implements EdgeLink {
* @param hostLocation location where host attaches to the network
* @param isIngress true to indicated host-to-network direction; false
* for network-to-host direction
* @param annotations optional key/value annotations
*/
public DefaultEdgeLink(ProviderId providerId, ConnectPoint hostPoint,
HostLocation hostLocation, boolean isIngress) {
HostLocation hostLocation, boolean isIngress,
Annotations... annotations) {
super(providerId, isIngress ? hostPoint : hostLocation,
isIngress ? hostLocation : hostPoint, Type.EDGE);
isIngress ? hostLocation : hostPoint, Type.EDGE, annotations);
checkArgument(hostPoint.elementId() instanceof HostId,
"Host point does not refer to a host ID");
this.hostId = (HostId) hostPoint.elementId();
......
package org.onlab.onos.net;
import static com.google.common.base.MoreObjects.toStringHelper;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* A basic implementation of a Host.
......@@ -22,12 +22,24 @@ public class DefaultHost extends AbstractElement implements Host {
private final HostLocation location;
private final Set<IpPrefix> ips;
/**
* Creates an end-station host using the supplied information.
*
* @param providerId provider identity
* @param id host identifier
* @param mac host MAC address
* @param vlan host VLAN identifier
* @param location host location
* @param ips host IP addresses
* @param annotations optional key/value annotations
*/
public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
VlanId vlan, HostLocation loc, Set<IpPrefix> ips) {
super(providerId, id);
VlanId vlan, HostLocation location, Set<IpPrefix> ips,
Annotations... annotations) {
super(providerId, id, annotations);
this.mac = mac;
this.vlan = vlan;
this.location = loc;
this.location = location;
this.ips = new HashSet<IpPrefix>(ips);
}
......
......@@ -22,10 +22,11 @@ public class DefaultLink extends AbstractModel implements Link {
* @param src link source
* @param dst link destination
* @param type link type
* @param annotations optional key/value annotations
*/
public DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst,
Type type) {
super(providerId);
Type type, Annotations... annotations) {
super(providerId, annotations);
this.src = src;
this.dst = dst;
this.type = type;
......
......@@ -24,9 +24,11 @@ public class DefaultPath extends DefaultLink implements Path {
* @param providerId provider identity
* @param links contiguous links that comprise the path
* @param cost unit-less path cost
* @param annotations optional key/value annotations
*/
public DefaultPath(ProviderId providerId, List<Link> links, double cost) {
super(providerId, source(links), destination(links), Type.INDIRECT);
public DefaultPath(ProviderId providerId, List<Link> links, double cost,
Annotations... annotations) {
super(providerId, source(links), destination(links), Type.INDIRECT, annotations);
this.links = ImmutableList.copyOf(links);
this.cost = cost;
}
......
package org.onlab.onos.net;
import static com.google.common.base.MoreObjects.toStringHelper;
import java.util.Map;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Default port implementation.
*/
......@@ -22,10 +21,8 @@ public class DefaultPort extends AbstractAnnotated implements Port {
* @param isEnabled indicator whether the port is up and active
* @param annotations optional key/value annotations
*/
@SafeVarargs
public DefaultPort(Element element, PortNumber number,
boolean isEnabled,
Map<String, String>... annotations) {
boolean isEnabled, Annotations... annotations) {
super(annotations);
this.element = element;
this.number = number;
......
......@@ -4,4 +4,8 @@ package org.onlab.onos.net;
* Base abstraction of a piece of information about network elements.
*/
public interface Description extends Annotated {
@Override
SparseAnnotations annotations();
}
......
......@@ -9,16 +9,23 @@ public class HostLocation extends ConnectPoint {
// Note that time is explicitly excluded from the notion of equality.
private final long time;
/**
* Creates a new host location using the supplied device &amp; port.
*
* @param deviceId device identity
* @param portNumber device port number
* @param time time when detected, in millis since start of epoch
*/
public HostLocation(DeviceId deviceId, PortNumber portNumber, long time) {
super(deviceId, portNumber);
this.time = time;
}
/**
* Returns the timestamp when the location was established, given in
* Returns the time when the location was established, given in
* milliseconds since start of epoch.
*
* @return timestamp in milliseconds since start of epoch
* @return time in milliseconds since start of epoch
*/
public long time() {
return time;
......
package org.onlab.onos.net;
import java.util.Set;
/**
* Represents an set of simply key/value string annotations.
*/
public interface SparseAnnotations extends Annotations {
/**
* {@inheritDoc}
* <p/>
* Note that this set includes keys for any attributes tagged for removal.
*/
@Override
public Set<String> keys();
/**
* Indicates whether the specified key has been tagged as removed. This is
* used to for merging sparse annotation sets.
*
* @param key annotation key
* @return true if the previous annotation has been tagged for removal
*/
public boolean isRemoved(String key);
}
package org.onlab.onos.net.device;
import org.onlab.onos.net.AbstractAnnotated;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.SparseAnnotations;
import java.net.URI;
import java.util.Map;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -12,7 +12,7 @@ import static org.onlab.onos.net.Device.Type;
/**
* Default implementation of immutable device description entity.
*/
public class DefaultDeviceDescription extends AbstractAnnotated
public class DefaultDeviceDescription extends AbstractDescription
implements DeviceDescription {
private final URI uri;
private final Type type;
......@@ -32,11 +32,10 @@ public class DefaultDeviceDescription extends AbstractAnnotated
* @param serialNumber device serial number
* @param annotations optional key/value annotations map
*/
@SafeVarargs
public DefaultDeviceDescription(URI uri, Type type, String manufacturer,
String hwVersion, String swVersion,
String serialNumber,
Map<String, String>... annotations) {
SparseAnnotations... annotations) {
super(annotations);
this.uri = checkNotNull(uri, "Device URI cannot be null");
this.type = checkNotNull(type, "Device type cannot be null");
......
package org.onlab.onos.net.host;
import com.google.common.collect.ImmutableSet;
import org.onlab.onos.net.AbstractAnnotated;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.SparseAnnotations;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
......@@ -16,7 +16,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Default implementation of an immutable host description.
*/
public class DefaultHostDescription extends AbstractAnnotated
public class DefaultHostDescription extends AbstractDescription
implements HostDescription {
private final MacAddress mac;
......@@ -32,10 +32,9 @@ public class DefaultHostDescription extends AbstractAnnotated
* @param location host location
* @param annotations optional key/value annotations map
*/
@SafeVarargs
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location,
Map<String, String>... annotations) {
SparseAnnotations... annotations) {
this(mac, vlan, location, new HashSet<IpPrefix>(), annotations);
}
......@@ -48,10 +47,9 @@ public class DefaultHostDescription extends AbstractAnnotated
* @param ips of host IP addresses
* @param annotations optional key/value annotations map
*/
@SafeVarargs
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, Set<IpPrefix> ips,
Map<String, String>... annotations) {
SparseAnnotations... annotations) {
super(annotations);
this.mac = mac;
this.vlan = vlan;
......
package org.onlab.onos.net.link;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.SparseAnnotations;
/**
* Default implementation of immutable link description entity.
*/
public class DefaultLinkDescription implements LinkDescription {
public class DefaultLinkDescription extends AbstractDescription
implements LinkDescription {
private final ConnectPoint src;
private final ConnectPoint dst;
......@@ -18,8 +21,11 @@ public class DefaultLinkDescription implements LinkDescription {
* @param src link source
* @param dst link destination
* @param type link type
* @param annotations optional key/value annotations
*/
public DefaultLinkDescription(ConnectPoint src, ConnectPoint dst, Link.Type type) {
public DefaultLinkDescription(ConnectPoint src, ConnectPoint dst,
Link.Type type, SparseAnnotations... annotations) {
super(annotations);
this.src = src;
this.dst = dst;
this.type = type;
......
......@@ -6,6 +6,7 @@ import org.onlab.packet.IpPrefix;
/**
* Service for processing arp requests on behalf of applications.
*/
// TODO: move to the peer host package
public interface ProxyArpService {
/**
......
......@@ -2,18 +2,19 @@ package org.onlab.onos.net.topology;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import org.onlab.onos.net.AbstractAnnotated;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.SparseAnnotations;
import java.util.Map;
/**
* Default implementation of an immutable topology graph data carrier.
*/
public class DefaultGraphDescription extends AbstractAnnotated
public class DefaultGraphDescription extends AbstractDescription
implements GraphDescription {
private final long nanos;
......@@ -32,10 +33,9 @@ public class DefaultGraphDescription extends AbstractAnnotated
* @param links collection of infrastructure links
* @param annotations optional key/value annotations map
*/
@SafeVarargs
public DefaultGraphDescription(long nanos, Iterable<Device> devices,
Iterable<Link> links,
Map<String, String>... annotations) {
SparseAnnotations... annotations) {
super(annotations);
this.nanos = nanos;
this.vertexes = buildVertexes(devices);
......
package org.onlab.onos.store.serializers;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import de.javakaffee.kryoserializers.URISerializer;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -13,6 +9,7 @@ import org.onlab.onos.cluster.ControllerNode;
import org.onlab.onos.cluster.DefaultControllerNode;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultAnnotations;
import org.onlab.onos.net.DefaultDevice;
import org.onlab.onos.net.DefaultLink;
import org.onlab.onos.net.DefaultPort;
......@@ -30,7 +27,10 @@ import org.onlab.util.KryoPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.javakaffee.kryoserializers.URISerializer;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Serialization service using Kryo.
......@@ -66,6 +66,7 @@ public class KryoSerializationManager implements KryoSerializationService {
ControllerNode.State.class,
Device.Type.class,
DefaultAnnotations.class,
DefaultControllerNode.class,
DefaultDevice.class,
MastershipRole.class,
......