3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
13 * @brief Describe a generic network element in multiple SDNs technologies
15 * Describe a generic network element in multiple SDNs technologies. A
16 * Node is identified by the pair (NodeType, NodeID), the nodetype are
17 * needed in order to further specify the nodeID
19 package org.opendaylight.controller.sal.core;
21 import java.io.Serializable;
22 import java.math.BigInteger;
24 import java.util.UUID;
25 import java.util.concurrent.ConcurrentHashMap;
27 import javax.xml.bind.annotation.XmlAccessType;
28 import javax.xml.bind.annotation.XmlAccessorType;
29 import javax.xml.bind.annotation.XmlAttribute;
30 import javax.xml.bind.annotation.XmlRootElement;
32 import org.opendaylight.controller.sal.utils.HexEncode;
35 * Describe a generic network element in multiple SDNs technologies. A
36 * Node is identified by the pair (NodeType, NodeID), the nodetype are
37 * needed in order to further specify the nodeID
40 @XmlAccessorType(XmlAccessType.NONE)
42 public class Node implements Serializable {
43 private static final long serialVersionUID = 1L;
46 * Enum-like static class created with the purpose of identifing
47 * multiple type of nodes in the SDN network. The type is
48 * necessary to figure out to later on correctly use the
49 * nodeID. Using a static class instead of an Enum so we can add
50 * dynamically new types without changing anything in the
53 public static final class NodeIDType {
54 private static final ConcurrentHashMap<String, Class<? extends Object>> compatibleType =
55 new ConcurrentHashMap<String, Class<? extends Object>>();
57 * Identifier for an OpenFlow node
59 public static String OPENFLOW = "OF";
61 * Identifier for a PCEP node
63 public static String PCEP = "PE";
65 * Identifier for a ONEPK node
67 public static String ONEPK = "PK";
69 * Identifier for a node in a non-SDN network
71 public static String PRODUCTION = "PR";
73 // Pre-populated types, just here for convenience and ease of
74 // unit-testing, but certainly those could live also outside.
76 compatibleType.put(OPENFLOW, Long.class);
77 compatibleType.put(PCEP, UUID.class);
78 compatibleType.put(ONEPK, String.class);
79 compatibleType.put(PRODUCTION, String.class);
83 * Return the type of the class expected for the
84 * NodeID, it's used for validity check in the constructor
86 * @param nodeType the type of the node we want to check
89 * @return The Class which is supposed to instantiate the ID
92 public static Class<?> getClassType(String nodeType) {
93 return compatibleType.get(nodeType);
97 * Returns all the registered nodeIDTypes currently available
99 * @return The current registered NodeIDTypes
101 public static Set<String> values() {
102 return compatibleType.keySet();
106 * Register a new ID for which Node can be created
108 * @param type, the new type being registered
109 * @param compatibleID, the type of class to be accepted as ID
111 * @return true if registered, false otherwise
113 public static boolean registerIDType(String type,
114 Class<? extends Object> compatibleID) {
115 if (compatibleType.get(type) != null) {
118 compatibleType.put(type, compatibleID);
124 * UNRegister a new ID for which Node can be created
126 * @param type, the type being UN-registered
129 public static void unRegisterIDType(String type) {
130 compatibleType.remove(type);
134 // This is the identity of the Node a (Type,ID) pair!, the full
135 // essence of this class.
136 private Object nodeID;
137 private String nodeType;
139 // Shadow value for unmarshalling
140 private String nodeIDString;
143 * Private constructor used for JAXB mapping
147 this.nodeType = null;
148 this.nodeIDString = null;
152 * Constructor for the Node objects, it validate the input so if
153 * the ID passed is not of the type expected accordingly to the
154 * type an exception is raised.
156 * @param nodeType Type of the node we are building
157 * @param id ID used by the SDN technology to identify the node
160 public Node(String nodeType, Object id) throws ConstructionException {
161 if (NodeIDType.getClassType(nodeType) != null &&
162 NodeIDType.getClassType(nodeType).isInstance(id)) {
163 this.nodeType = nodeType;
166 throw new ConstructionException("Type of incoming object:"
167 + id.getClass() + " not compatible with expected type:"
168 + NodeIDType.getClassType(nodeType));
173 * Copy Constructor for the Node objects.
175 * @param src type of nodes to copy from
178 public Node(Node src) throws ConstructionException {
180 this.nodeType = src.getType();
181 // Here we can reference the object because that is
182 // supposed to be an immutable identifier as well like a
183 // UUID/Integer and so on, hence no need to create a copy
185 this.nodeID = src.getID();
188 new ConstructionException("Null incoming object to copy from");
193 * getter for node type
196 * @return The node Type for this Node object
198 @XmlAttribute(name = "type")
199 public String getType() {
200 return this.nodeType;
204 * fill the current object from the string parameters passed, will
205 * be only used by JAXB
207 * @param typeStr string representing the type of the Node
208 * @param IDStr String representation of the ID
210 private void fillmeFromString(String typeStr, String IDStr) {
211 if (typeStr == null) {
219 this.nodeType = typeStr;
220 if (typeStr.equals(NodeIDType.OPENFLOW)) {
221 this.nodeID = Long.valueOf(HexEncode.stringToLong(IDStr));
222 } else if (typeStr.equals(NodeIDType.ONEPK)) {
224 } else if (typeStr.equals(NodeIDType.PCEP)) {
225 this.nodeID = UUID.fromString(IDStr);
226 } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
229 // We need to lookup via OSGi service registry for an
235 * Private setter for nodeType to be called by JAXB not by anyone
236 * else, Node is immutable
238 * @param type of node to be set
240 private void setType(String type) {
241 this.nodeType = type;
242 if (this.nodeIDString != null) {
243 this.fillmeFromString(type, this.nodeIDString);
251 * @return The node ID for this Node object
253 public Object getID() {
258 * Getter for the node ID in string format
260 * @return The nodeID in string format
262 @XmlAttribute(name = "id")
263 public String getNodeIDString() {
264 if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
265 return HexEncode.longToHexString((Long) this.nodeID);
267 return this.nodeID.toString();
272 * private setter to be used by JAXB
274 * @param nodeIDString String representation for NodeID
276 private void setNodeIDString(String nodeIDString) {
277 this.nodeIDString = nodeIDString;
278 if (this.nodeType != null) {
279 this.fillmeFromString(this.nodeType, nodeIDString);
284 public int hashCode() {
285 final int prime = 31;
287 result = prime * result + ((nodeID == null) ? 0 : nodeID.hashCode());
288 result = prime * result
289 + ((nodeType == null) ? 0 : nodeType.hashCode());
294 public boolean equals(Object obj) {
299 if (getClass() != obj.getClass())
301 Node other = (Node) obj;
302 if (nodeID == null) {
303 if (other.nodeID != null)
305 } else if (!nodeID.equals(other.nodeID))
307 if (nodeType == null) {
308 if (other.nodeType != null)
310 } else if (!nodeType.equals(other.nodeType))
316 public String toString() {
317 if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
318 return this.nodeType.toString() + "|"
319 + HexEncode.longToHexString((Long) this.nodeID);
321 return this.nodeType.toString() + "|" + this.nodeID.toString();
326 * Static method to get back a Node from a string
328 * @param str string formatted in toString mode that can be
329 * converted back to a Node format.
331 * @return a Node if succed or null if no
333 public static Node fromString(String str) {
338 String parts[] = str.split("\\|");
339 if (parts.length != 2) {
340 // Try to guess from a String formatted as a long because
341 // for long time openflow has been prime citizen so lets
342 // keep this legacy for now
343 String numStr = str.toUpperCase();
345 Long ofNodeID = null;
346 if (numStr.startsWith("0X")) {
347 // Try as an hex number
349 BigInteger b = new BigInteger(
350 numStr.replaceFirst("0X", ""), 16);
351 ofNodeID = Long.valueOf(b.longValue());
352 } catch (Exception ex) {
356 // Try as a decimal number
358 BigInteger b = new BigInteger(numStr);
359 ofNodeID = Long.valueOf(b.longValue());
360 } catch (Exception ex) {
365 // Startegy #3 parse as HexLong
366 if (ofNodeID == null) {
368 ofNodeID = Long.valueOf(HexEncode.stringToLong(numStr));
369 } catch (Exception ex) {
374 // We ran out of ideas ... return null
375 if (ofNodeID == null) {
379 // Lets return the cooked up NodeID
381 return new Node(NodeIDType.OPENFLOW, ofNodeID);
382 } catch (ConstructionException ex) {
387 String typeStr = parts[0];
388 String IDStr = parts[1];
390 return fromString(typeStr, IDStr);
394 * Static method to get back a Node from a pair of strings, the
395 * first one being the Type representation, the second one being
396 * the ID string representation, expected to be heavily used in
399 * @param type, the type of the node we are parsing
400 * @param id, the string representation of the node id
402 * @return a Node if succed or null if no
404 public static Node fromString(String typeStr, String IDStr) {
405 if (typeStr == null) {
413 if (typeStr.equals(NodeIDType.OPENFLOW)) {
415 Long ID = Long.valueOf(HexEncode.stringToLong(IDStr));
416 return new Node(typeStr, ID);
417 } catch (Exception ex) {
420 } else if (typeStr.equals(NodeIDType.ONEPK)) {
422 return new Node(typeStr, IDStr);
423 } catch (Exception ex) {
426 } else if (typeStr.equals(NodeIDType.PCEP)) {
428 UUID ID = UUID.fromString(IDStr);
429 return new Node(typeStr, ID);
430 } catch (Exception ex) {
433 } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
435 return new Node(typeStr, IDStr);
436 } catch (Exception ex) {
440 // We need to lookup via OSGi service registry for an