blob: 306ebc5be647ff674ef5eaae6f487077f41cafc1 [file] [log] [blame]
Jonathan Hart6df90172014-04-03 10:13:11 -07001package net.onrc.onos.core.datastore.topology;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07002
3import java.nio.ByteBuffer;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07004import java.util.Collection;
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.Iterator;
8import java.util.Map;
9import java.util.Set;
10import java.util.TreeSet;
11
Jonathan Hart6df90172014-04-03 10:13:11 -070012import net.onrc.onos.core.datastore.DataStoreClient;
13import net.onrc.onos.core.datastore.IKVTable.IKVEntry;
TeruU28adcc32014-04-15 17:57:35 -070014import net.onrc.onos.core.datastore.serializers.Device.DeviceProperty;
Jonathan Hart6df90172014-04-03 10:13:11 -070015import net.onrc.onos.core.datastore.topology.KVLink.STATUS;
16import net.onrc.onos.core.datastore.utils.ByteArrayComparator;
17import net.onrc.onos.core.datastore.utils.ByteArrayUtil;
18import net.onrc.onos.core.datastore.utils.KVObject;
Jonathan Hart472062d2014-04-03 10:56:48 -070019import net.onrc.onos.core.topology.DeviceEvent;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070020
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23
24import com.esotericsoftware.kryo.Kryo;
TeruU28adcc32014-04-15 17:57:35 -070025import com.google.protobuf.ByteString;
26import com.google.protobuf.InvalidProtocolBufferException;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070027
28/**
29 * Device object.
Ray Milkey269ffb92014-04-03 14:43:30 -070030 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070031 */
32public class KVDevice extends KVObject {
33 private static final Logger log = LoggerFactory.getLogger(KVDevice.class);
34
Ray Milkey5c9f2db2014-04-09 10:31:21 -070035 private static final ThreadLocal<Kryo> DEVICE_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070036 @Override
37 protected Kryo initialValue() {
38 Kryo kryo = new Kryo();
39 kryo.setRegistrationRequired(true);
40 kryo.setReferences(false);
41 kryo.register(byte[].class);
42 kryo.register(byte[][].class);
43 kryo.register(HashMap.class);
44 // TODO check if we should explicitly specify EnumSerializer
45 kryo.register(STATUS.class);
46 return kryo;
47 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070048 };
49
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070050 static final String DEVICE_TABLE_SUFFIX = ":Device";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070051
52 private final byte[] mac;
53 private TreeSet<byte[]> portIds;
Ray Milkey269ffb92014-04-03 14:43:30 -070054
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070055 /**
56 * Generate a DeviceID from MAC address.
57 * <p/>
58 * We're assuming MAC address can be an unique identifier for Device.
59 *
60 * @param mac MAC address
61 * @return DeviceID
62 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070063 public static byte[] getDeviceID(final byte[] mac) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070064 return DeviceEvent.getDeviceID(mac).array();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070065 }
66
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070067 /**
68 * Gets the MAC address from DeviceID.
69 *
70 * @param key DeviceID
71 * @return MAC address
72 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070073 public static byte[] getMacFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070074 ByteBuffer keyBuf = ByteBuffer.wrap(key);
75 if (keyBuf.getChar() != 'D') {
76 throw new IllegalArgumentException("Invalid Device key");
77 }
78 byte[] mac = new byte[keyBuf.remaining()];
79 keyBuf.get(mac);
80 return mac;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070081 }
82
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070083 /**
84 * KVDevice constructor for default namespace.
85 *
86 * @param mac MAC address
87 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070088 public KVDevice(final byte[] mac) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070089 this(mac, DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070090 }
91
92 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070093 * KVDevice constructor for specified namespace.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070094 *
Yuta HIGUCHIcc561882014-05-22 10:31:32 -070095 * @param mac MAC address
96 * @param namespace namespace to create this object
97 */
98 public KVDevice(final byte[] mac, final String namespace) {
99 super(DataStoreClient.getClient()
100 .getTable(namespace + DEVICE_TABLE_SUFFIX),
101 getDeviceID(mac), namespace);
102
103 this.mac = mac.clone();
104 this.portIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
105 }
106
107 /**
108 * Gets an instance from DeviceID in default namespace.
109 *
110 * @param key DeviceID
111 * @return KVDevice instance
Ray Milkey269ffb92014-04-03 14:43:30 -0700112 * @note You need to call `read()` to get the DB content.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700113 */
114 public static KVDevice createFromKey(final byte[] key) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700115 return createFromKey(key, DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700116 }
117
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700118 /**
119 * Gets an instance from DeviceID in specified namespace.
120 *
121 * @param key DeviceID
122 * @param namespace namespace to create this object in
123 * @return KVDevice instance
124 * @note You need to call `read()` to get the DB content.
125 */
126 public static KVDevice createFromKey(final byte[] key, final String namespace) {
127 return new KVDevice(getMacFromKey(key), namespace);
128 }
129
130 /**
131 * Gets all the Devices in default namespace.
132 *
133 * @return Devices
134 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700135 public static Iterable<KVDevice> getAllDevices() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700136 return new DeviceEnumerator(DEFAULT_NAMESPACE);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700137 }
138
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700139 /**
140 * Gets all the Devices in specified namespace.
141 *
142 * @param namespace namespace to iterate over
143 * @return Devices
144 */
145 public static Iterable<KVDevice> getAllDevices(final String namespace) {
146 return new DeviceEnumerator(namespace);
147 }
148
149 /**
150 * Utility class to provide Iterable interface.
151 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700152 public static class DeviceEnumerator implements Iterable<KVDevice> {
153
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700154 private final String namespace;
155
156 /**
157 * Constructor to iterate Links in specified namespace.
158 *
159 * @param namespace namespace to iterate through
160 */
161 public DeviceEnumerator(final String namespace) {
162 this.namespace = namespace;
163 }
164
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700165 @Override
166 public Iterator<KVDevice> iterator() {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700167 return new DeviceIterator(namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700168 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700169 }
170
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700171 /**
172 * Utility class to provide Iterator over all the Device objects.
173 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700174 public static class DeviceIterator extends AbstractObjectIterator<KVDevice> {
175
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700176 /**
177 * Constructor to create an iterator to iterate all the Devices
178 * in specified namespace.
179 *
180 * @param namespace namespace to iterate through
181 */
182 public DeviceIterator(final String namespace) {
183 super(DataStoreClient.getClient()
184 .getTable(namespace + DEVICE_TABLE_SUFFIX), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700185 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700186
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700187 @Override
188 public KVDevice next() {
189 IKVEntry o = enumerator.next();
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700190 KVDevice e = KVDevice.createFromKey(o.getKey(), namespace);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700191 e.deserialize(o.getValue(), o.getVersion());
192 return e;
193 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700194 }
195
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700196 /**
197 * Gets the MAC address.
198 *
199 * @return MAC address
200 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700201 public byte[] getMac() {
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -0700202 return mac.clone();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700203 }
204
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700205 /**
206 * Gets the DeviceID.
207 *
208 * @return DeviceID
209 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700210 public byte[] getId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700211 return getKey();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700212 }
213
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700214 /**
215 * Add a port to this Device's attachment points.
216 *
217 * @param portId PortID of the port which this Device is attached
218 */
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700219 public void addPortId(final byte[] portId) {
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700220 portIds.add(portId.clone());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700221 }
222
223 /**
Yuta HIGUCHIcc561882014-05-22 10:31:32 -0700224 * Remove a port from this Device's attachment points.
225 *
226 * @param portId PortID to remove
227 */
228 public void removePortId(final byte[] portId) {
229 portIds.remove(portId);
230 }
231
232 /**
233 * Empty this Device's attachment points.
234 */
235 public void emptyPortIds() {
236 portIds.clear();
237 }
238
239 /**
240 * Add ports to this Device's attachment points.
241 *
242 * @param newPortIds PortIDs which this Device is attached
243 */
244 public void addAllToPortIds(final Collection<byte[]> newPortIds) {
245 // TODO: Should we copy each portId, or reference is OK.
246 portIds.addAll(newPortIds);
247 }
248
249 /**
250 * Gets all the PortIDs which this Device is attached.
251 *
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700252 * @return Unmodifiable Set view of all the PortIds;
253 */
254 public Set<byte[]> getAllPortIds() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700255 return Collections.unmodifiableSet(portIds);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700256 }
257
258 @Override
259 public byte[] serialize() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700260 Map<Object, Object> map = getPropertyMap();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700261
TeruU28adcc32014-04-15 17:57:35 -0700262 DeviceProperty.Builder dev = DeviceProperty.newBuilder();
263
264 dev.setMac(ByteString.copyFrom(mac));
265 for (byte[] port : portIds) {
266 dev.addPortIds(ByteString.copyFrom(port));
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700267 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700268
TeruU28adcc32014-04-15 17:57:35 -0700269 if (!map.isEmpty()) {
270 byte[] propMaps = serializePropertyMap(DEVICE_KRYO.get(), map);
271 dev.setValue(ByteString.copyFrom(propMaps));
272 }
273
274 return dev.build().toByteArray();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700275 }
276
277 @Override
278 protected boolean deserialize(final byte[] bytes) {
TeruU28adcc32014-04-15 17:57:35 -0700279
280 try {
281 boolean success = true;
282
283 DeviceProperty dev = DeviceProperty.parseFrom(bytes);
284 for (ByteString portId : dev.getPortIdsList()) {
285 this.addPortId(portId.toByteArray());
286 }
287 byte[] props = dev.getValue().toByteArray();
288 success &= deserializePropertyMap(DEVICE_KRYO.get(), props);
289 return success;
290 } catch (InvalidProtocolBufferException e) {
291 log.error("Deserializing Device: " + this + " failed.", e);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700292 return false;
293 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700294 }
295
296 @Override
297 public String toString() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700298 // TODO output all properties?
299 return "[" + this.getClass().getSimpleName()
Yuta HIGUCHI805bc8f2014-04-16 11:51:43 -0700300 + " " + ByteArrayUtil.toHexStringBuilder(mac, ":") + "]";
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700301 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700302}