blob: 5a13e3ec41a27b79a7b8f267ba2ebe15f2298034 [file] [log] [blame]
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -08001package net.onrc.onos.datastore.topology;
2
3import java.nio.ByteBuffer;
4import java.util.Arrays;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.HashMap;
8import java.util.Map;
9import java.util.Set;
10import java.util.TreeSet;
11
12import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
15import com.esotericsoftware.kryo.Kryo;
16
17import net.onrc.onos.datastore.RCObject;
18import net.onrc.onos.datastore.RCTable;
19import net.onrc.onos.datastore.utils.ByteArrayComparator;
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080020import net.onrc.onos.datastore.utils.ByteArrayUtil;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080021
22public class RCPort extends RCObject {
23 private static final Logger log = LoggerFactory.getLogger(RCPort.class);
24
25 private static final ThreadLocal<Kryo> portKryo = new ThreadLocal<Kryo>() {
26 @Override
27 protected Kryo initialValue() {
28 Kryo kryo = new Kryo();
29 kryo.setRegistrationRequired(true);
30 kryo.setReferences(false);
31 kryo.register(byte[].class);
32 kryo.register(byte[][].class);
33 kryo.register(HashMap.class);
34 // TODO check if we should explicitly specify EnumSerializer
35 kryo.register(STATUS.class);
36 return kryo;
37 }
38 };
39
40 public static final String GLOBAL_PORT_TABLE_NAME = "G:Port";
41
42 // FIXME these should be Enum or some number, not String
43 private static final String PROP_DPID = "dpid";
44 private static final String PROP_NUMBER = "number";
45 private static final String PROP_STATUS = "status";
46 private static final String PROP_LINK_IDS = "link-ids";
47 private static final String PROP_DEVICE_IDS = "device-ids";
48
49 // must not re-order enum members, ordinal will be sent over wire
50 public enum STATUS {
51 INACTIVE, ACTIVE;
52 }
53
54 private final Long dpid;
55 private final Long number;
56
57 private STATUS status;
58 // XXX These 2 set of Ids can be removed from DataStore, if In-Memory cache
59 // build the indexing info from Link.
60 private TreeSet<byte[]> linkIds;
61 transient boolean isLinkIdsModified;
62 private TreeSet<byte[]> deviceIds;
63 transient boolean isDeviceIdsModified;
64
65 public static final int PORTID_BYTES = RCSwitch.SWITCHID_BYTES + 2 + 8;
66
67 public static byte[] getPortID(Long dpid, Long number) {
68 if (dpid == null) {
69 throw new IllegalArgumentException("dpid cannot be null");
70 }
71 if (number == null) {
72 throw new IllegalArgumentException("number cannot be null");
73 }
74 return ByteBuffer.allocate(PORTID_BYTES).putChar('S').putLong(dpid)
75 .putChar('P').putLong(number).array();
76 }
77
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080078 public static long[] getPortPairFromKey(byte[] key) {
79 return getPortPairFromKey(ByteBuffer.wrap(key));
80
81 }
82
83 public static long[] getPortPairFromKey(ByteBuffer keyBuf) {
84 long[] pair = new long[2];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080085 if (keyBuf.getChar() != 'S') {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080086 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
87 + " "
88 + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080089 }
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080090 pair[0] = keyBuf.getLong();
91 if (keyBuf.getChar() != 'P') {
92 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
93 + " "
94 + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
95 }
96 pair[1] = keyBuf.getLong();
97 return pair;
98
99 }
100
101 public static long getDpidFromKey(byte[] key) {
102 return getPortPairFromKey(key)[0];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800103 }
104
105 public static long getNumberFromKey(byte[] key) {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800106 return getPortPairFromKey(key)[1];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800107 }
108
109 // FIXME specify DPID,number here, or Should caller specify the key it self?
110 // In other words, should layer above have the control of the ID?
111 public RCPort(Long dpid, Long number) {
112 super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME), getPortID(dpid, number));
113
114 // TODO Auto-generated constructor stub
115
116 this.dpid = dpid;
117 this.number = number;
118 this.status = STATUS.INACTIVE;
119 this.linkIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
120 this.isLinkIdsModified = true;
121 this.deviceIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
122 this.isDeviceIdsModified = true;
123 }
124
125 public static RCPort createFromKey(byte[] key) {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800126 long[] pair = getPortPairFromKey(key);
127 return new RCPort(pair[0], pair[1]);
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800128 }
129
130 public STATUS getStatus() {
131 return status;
132 }
133
134 public void setStatus(STATUS status) {
135 this.status = status;
136 getObjectMap().put(PROP_STATUS, status);
137 }
138
139 public Long getDpid() {
140 return dpid;
141 }
142
143 public Long getNumber() {
144 return number;
145 }
146
147 public byte[] getId() {
148 return getKey();
149 }
150
151 public void addLinkId(byte[] linkId) {
152 isLinkIdsModified |= linkIds.add(linkId);
153 }
154
155 public void removeLinkId(byte[] linkId) {
156 isLinkIdsModified |= linkIds.remove(linkId);
157 }
158
159 public void emptyLinkIds() {
160 linkIds.clear();
161 isLinkIdsModified = true;
162 }
163
164 public void addAllToLinkIds(Collection<byte[]> linkIds) {
165 isLinkIdsModified |= this.linkIds.addAll(linkIds);
166 }
167
168 /**
169 *
170 * @return Unmodifiable Set view of all the LinkIds;
171 */
172 public Set<byte[]> getAllLinkIds() {
173 return Collections.unmodifiableSet(linkIds);
174 }
175
176 public void addDeviceId(byte[] deviceId) {
177 isDeviceIdsModified |= deviceIds.add(deviceId);
178 }
179
180 public void removeDeviceId(byte[] deviceId) {
181 isDeviceIdsModified |= deviceIds.remove(deviceId);
182 }
183
184 public void emptyDeviceIds() {
185 deviceIds.clear();
186 isDeviceIdsModified = true;
187 }
188
189 public void addAllToDeviceIds(Collection<byte[]> deviceIds) {
190 isDeviceIdsModified |= this.deviceIds.addAll(deviceIds);
191 }
192
193 /**
194 *
195 * @return Unmodifiable Set view of all the LinkIds;
196 */
197 public Set<byte[]> getAllDeviceIds() {
198 return Collections.unmodifiableSet(deviceIds);
199 }
200
201 @Override
202 public void serializeAndSetValue() {
203 Map<Object, Object> map = getObjectMap();
204
205 map.put(PROP_DPID, this.dpid);
206 map.put(PROP_NUMBER, this.number);
207 if (isLinkIdsModified) {
208 byte[] linkIdArray[] = new byte[linkIds.size()][];
209 map.put(PROP_LINK_IDS, linkIds.toArray(linkIdArray));
210 isLinkIdsModified = false;
211 }
212 if (isDeviceIdsModified) {
213 byte[] deviceIdArray[] = new byte[deviceIds.size()][];
214 map.put(PROP_DEVICE_IDS, deviceIds.toArray(deviceIdArray));
215 isDeviceIdsModified = false;
216 }
217 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
218 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
219 linkIds.size(), deviceIds.size());
220 }
221
222 serializeAndSetValue(portKryo.get(), map);
223 }
224
225 @Override
226 public Map<Object, Object> deserializeObjectFromValue() {
227 Map<Object, Object> map = deserializeObjectFromValue(portKryo.get());
228
229 this.status = (STATUS) map.get(PROP_STATUS);
230
231 if (this.linkIds == null) {
232 this.linkIds = new TreeSet<>(
233 ByteArrayComparator.BYTEARRAY_COMPARATOR);
234 }
235 byte[] linkIdArray[] = (byte[][]) map.get(PROP_LINK_IDS);
236 if (linkIdArray != null) {
237 this.linkIds.clear();
238 this.linkIds.addAll(Arrays.asList(linkIdArray));
239 isLinkIdsModified = false;
240 } else {
241 // trigger write on next serialize
242 isLinkIdsModified = true;
243 }
244
245 if (this.deviceIds == null) {
246 this.deviceIds = new TreeSet<>(
247 ByteArrayComparator.BYTEARRAY_COMPARATOR);
248 }
249 byte[] deviceIdArray[] = (byte[][]) map.get(PROP_DEVICE_IDS);
250 if (deviceIdArray != null) {
251 this.deviceIds.clear();
252 this.deviceIds.addAll(Arrays.asList(deviceIdArray));
253 isDeviceIdsModified = false;
254 } else {
255 // trigger write on next serialize
256 isDeviceIdsModified = true;
257 }
258
259 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
260 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
261 linkIds.size(), deviceIds.size());
262 }
263
264 return map;
265 }
266
267 @Override
268 public String toString() {
269 // TODO OUTPUT ALL?
270 return "[RCPort 0x" + Long.toHexString(dpid) + "@" + number
271 + " STATUS:" + status + "]";
272 }
273
274 public static void main(String[] args) {
275 // TODO Auto-generated method stub
276
277 }
278
279}