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.XmlElement;
31 import javax.xml.bind.annotation.XmlRootElement;
33 import org.opendaylight.controller.sal.utils.HexEncode;
34 import org.opendaylight.controller.sal.utils.INodeFactory;
35 import org.opendaylight.controller.sal.utils.ServiceHelper;
38 * Describe a generic network element in multiple SDNs technologies. A
39 * Node is identified by the pair (NodeType, NodeID), the nodetype are
40 * needed in order to further specify the nodeID
43 @XmlAccessorType(XmlAccessType.NONE)
45 public class Node implements Serializable {
46 private static final long serialVersionUID = 1L;
49 * Enum-like static class created with the purpose of identifing
50 * multiple type of nodes in the SDN network. The type is
51 * necessary to figure out to later on correctly use the
52 * nodeID. Using a static class instead of an Enum so we can add
53 * dynamically new types without changing anything in the
56 public static final class NodeIDType {
57 private static final ConcurrentHashMap<String, Class<? extends Object>> compatibleType =
58 new ConcurrentHashMap<String, Class<? extends Object>>();
60 * Identifier for an OpenFlow node
62 public static String OPENFLOW = "OF";
64 * Identifier for a PCEP node
66 public static String PCEP = "PE";
68 * Identifier for a ONEPK node
70 public static String ONEPK = "PK";
72 * Identifier for a node in a non-SDN network
74 public static String PRODUCTION = "PR";
76 // Pre-populated types, just here for convenience and ease of
77 // unit-testing, but certainly those could live also outside.
79 compatibleType.put(OPENFLOW, Long.class);
80 compatibleType.put(PCEP, UUID.class);
81 compatibleType.put(ONEPK, String.class);
82 compatibleType.put(PRODUCTION, String.class);
86 * Return the type of the class expected for the
87 * NodeID, it's used for validity check in the constructor
89 * @param nodeType the type of the node we want to check
92 * @return The Class which is supposed to instantiate the ID
95 public static Class<?> getClassType(String nodeType) {
96 return compatibleType.get(nodeType);
100 * Returns all the registered nodeIDTypes currently available
102 * @return The current registered NodeIDTypes
104 public static Set<String> values() {
105 return compatibleType.keySet();
109 * Register a new ID for which Node can be created
111 * @param type, the new type being registered
112 * @param compatibleID, the type of class to be accepted as ID
114 * @return true if registered, false otherwise
116 public static boolean registerIDType(String type,
117 Class<? extends Object> compatibleID) {
118 if (compatibleType.get(type) != null) {
121 compatibleType.put(type, compatibleID);
127 * UNRegister a new ID for which Node can be created
129 * @param type, the type being UN-registered
132 public static void unRegisterIDType(String type) {
133 compatibleType.remove(type);
137 // This is the identity of the Node a (Type,ID) pair!, the full
138 // essence of this class.
139 private Object nodeID;
140 private String nodeType;
142 // Shadow value for unmarshalling
143 private String nodeIDString;
146 * Private constructor used for JAXB mapping
150 this.nodeType = null;
151 this.nodeIDString = null;
155 * Constructor for the Node objects, it validate the input so if
156 * the ID passed is not of the type expected accordingly to the
157 * type an exception is raised.
159 * @param nodeType Type of the node we are building
160 * @param id ID used by the SDN technology to identify the node
163 public Node(String nodeType, Object id) throws ConstructionException {
164 if (NodeIDType.getClassType(nodeType) != null &&
165 NodeIDType.getClassType(nodeType).isInstance(id)) {
166 this.nodeType = nodeType;
169 throw new ConstructionException("Type of incoming object:"
170 + id.getClass() + " not compatible with expected type:"
171 + NodeIDType.getClassType(nodeType));
176 * Copy Constructor for the Node objects.
178 * @param src type of nodes to copy from
181 public Node(Node src) throws ConstructionException {
183 this.nodeType = src.getType();
184 // Here we can reference the object because that is
185 // supposed to be an immutable identifier as well like a
186 // UUID/Integer and so on, hence no need to create a copy
188 this.nodeID = src.getID();
191 new ConstructionException("Null incoming object to copy from");
196 * getter for node type
199 * @return The node Type for this Node object
201 @XmlElement(name = "type")
202 public String getType() {
203 return this.nodeType;
207 * fill the current object from the string parameters passed, will
208 * be only used by JAXB
210 * @param typeStr string representing the type of the Node
211 * @param IDStr String representation of the ID
213 private void fillmeFromString(String typeStr, String IDStr) {
214 if (typeStr == null) {
222 this.nodeType = typeStr;
223 if (typeStr.equals(NodeIDType.OPENFLOW)) {
224 this.nodeID = Long.valueOf(HexEncode.stringToLong(IDStr));
225 } else if (typeStr.equals(NodeIDType.ONEPK)) {
227 } else if (typeStr.equals(NodeIDType.PCEP)) {
228 this.nodeID = UUID.fromString(IDStr);
229 } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
232 //Use plugin's method to get appropriate conversion from IDStr to nodeID
233 INodeFactory f = (INodeFactory) ServiceHelper
234 .getGlobalInstance(INodeFactory.class, new Node(), "(protocolName="+typeStr+")");
236 Node n = f.fromString(typeStr, IDStr);
237 this.nodeID = n.nodeID;
243 * Private setter for nodeType to be called by JAXB not by anyone
244 * else, Node is immutable
246 * @param type of node to be set
248 private void setType(String type) {
249 this.nodeType = type;
250 if (this.nodeIDString != null) {
251 this.fillmeFromString(type, this.nodeIDString);
259 * @return The node ID for this Node object
261 public Object getID() {
266 * Getter for the node ID in string format
268 * @return The nodeID in string format
270 @XmlElement(name = "id")
271 public String getNodeIDString() {
272 if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
273 return HexEncode.longToHexString((Long) this.nodeID);
275 return this.nodeID.toString();
280 * private setter to be used by JAXB
282 * @param nodeIDString String representation for NodeID
284 private void setNodeIDString(String nodeIDString) {
285 this.nodeIDString = nodeIDString;
286 if (this.nodeType != null) {
287 this.fillmeFromString(this.nodeType, nodeIDString);
292 public int hashCode() {
293 final int prime = 31;
295 result = prime * result + ((nodeID == null) ? 0 : nodeID.hashCode());
296 result = prime * result
297 + ((nodeType == null) ? 0 : nodeType.hashCode());
302 public boolean equals(Object obj) {
307 if (getClass() != obj.getClass())
309 Node other = (Node) obj;
310 if (nodeID == null) {
311 if (other.nodeID != null)
313 } else if (!nodeID.equals(other.nodeID))
315 if (nodeType == null) {
316 if (other.nodeType != null)
318 } else if (!nodeType.equals(other.nodeType))
324 public String toString() {
325 if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
326 return this.nodeType + "|"
327 + HexEncode.longToHexString((Long) this.nodeID);
329 return this.nodeType + "|" + this.nodeID.toString();
334 * Static method to get back a Node from a string
336 * @param str string formatted in toString mode that can be
337 * converted back to a Node format.
339 * @return a Node if succed or null if no
341 public static Node fromString(String str) {
346 String parts[] = str.split("\\|");
347 if (parts.length != 2) {
348 // Try to guess from a String formatted as a long because
349 // for long time openflow has been prime citizen so lets
350 // keep this legacy for now
351 String numStr = str.toUpperCase();
353 Long ofNodeID = null;
354 if (numStr.startsWith("0X")) {
355 // Try as an hex number
357 BigInteger b = new BigInteger(
358 numStr.replaceFirst("0X", ""), 16);
359 ofNodeID = Long.valueOf(b.longValue());
360 } catch (Exception ex) {
364 // Try as a decimal number
366 BigInteger b = new BigInteger(numStr);
367 ofNodeID = Long.valueOf(b.longValue());
368 } catch (Exception ex) {
373 // Startegy #3 parse as HexLong
374 if (ofNodeID == null) {
376 ofNodeID = Long.valueOf(HexEncode.stringToLong(numStr));
377 } catch (Exception ex) {
382 // We ran out of ideas ... return null
383 if (ofNodeID == null) {
387 // Lets return the cooked up NodeID
389 return new Node(NodeIDType.OPENFLOW, ofNodeID);
390 } catch (ConstructionException ex) {
395 String typeStr = parts[0];
396 String IDStr = parts[1];
398 return fromString(typeStr, IDStr);
402 * Static method to get back a Node from a pair of strings, the
403 * first one being the Type representation, the second one being
404 * the ID string representation, expected to be heavily used in
407 * @param type, the type of the node we are parsing
408 * @param id, the string representation of the node id
410 * @return a Node if succed or null if no
412 public static Node fromString(String typeStr, String IDStr) {
413 if (typeStr == null) {
421 if (typeStr.equals(NodeIDType.OPENFLOW)) {
423 Long ID = Long.valueOf(HexEncode.stringToLong(IDStr));
424 return new Node(typeStr, ID);
425 } catch (Exception ex) {
428 } else if (typeStr.equals(NodeIDType.ONEPK)) {
430 return new Node(typeStr, IDStr);
431 } catch (Exception ex) {
434 } else if (typeStr.equals(NodeIDType.PCEP)) {
436 UUID ID = UUID.fromString(IDStr);
437 return new Node(typeStr, ID);
438 } catch (Exception ex) {
441 } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
443 return new Node(typeStr, IDStr);
444 } catch (Exception ex) {
448 //Use INodeFactory to create a Node of registered Node type.
449 //The protocol plugin being used depends on typeStr.
450 INodeFactory f = (INodeFactory) ServiceHelper
451 .getGlobalInstance(INodeFactory.class, new Node(), "(protocolName="+typeStr+")");
454 return f.fromString(typeStr, IDStr);