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.util.concurrent.ConcurrentHashMap;
23 import java.math.BigInteger;
25 import java.io.Serializable;
26 import java.lang.String;
27 import java.util.UUID;
28 import java.lang.Long;
29 import java.lang.Class;
30 import org.apache.commons.lang3.builder.HashCodeBuilder;
31 import org.apache.commons.lang3.builder.EqualsBuilder;
32 import org.opendaylight.controller.sal.utils.HexEncode;
34 import javax.xml.bind.annotation.XmlRootElement;
35 import javax.xml.bind.annotation.XmlAccessType;
36 import javax.xml.bind.annotation.XmlAccessorType;
37 import javax.xml.bind.annotation.XmlAttribute;
40 * Describe a generic network element in multiple SDNs technologies. A
41 * Node is identified by the pair (NodeType, NodeID), the nodetype are
42 * needed in order to further specify the nodeID
45 @XmlAccessorType(XmlAccessType.NONE)
46 public class Node implements Serializable {
47 private static final long serialVersionUID = 1L;
50 * Enum-like static class created with the purpose of identifing
51 * multiple type of nodes in the SDN network. The type is
52 * necessary to figure out to later on correctly use the
53 * nodeID. Using a static class instead of an Enum so we can add
54 * dynamically new types without changing anything in the
57 public static final class NodeIDType {
58 private static final ConcurrentHashMap<String, Class> compatibleType =
59 new ConcurrentHashMap<String, Class>();
61 * Identifier for an OpenFlow node
63 public static String OPENFLOW = "OF";
65 * Identifier for a PCEP node
67 public static String PCEP = "PE";
69 * Identifier for a ONEPK node
71 public static String ONEPK = "PK";
73 * Identifier for a node in a non-SDN network
75 public static String PRODUCTION = "PR";
77 // Pre-populated types, just here for convenience and ease of
78 // unit-testing, but certainly those could live also outside.
80 compatibleType.put(OPENFLOW, Long.class);
81 compatibleType.put(PCEP, UUID.class);
82 compatibleType.put(ONEPK, String.class);
83 compatibleType.put(PRODUCTION, String.class);
87 * Return the type of the class expected for the
88 * NodeID, it's used for validity check in the constructor
90 * @param nodeType the type of the node we want to check
93 * @return The Class which is supposed to instantiate the ID
96 public static Class<?> getClassType(String nodeType) {
97 return compatibleType.get(nodeType);
101 * Returns all the registered nodeIDTypes currently available
103 * @return The current registered NodeIDTypes
105 public static Set<String> values() {
106 return compatibleType.keySet();
110 * Register a new ID for which Node can be created
112 * @param type, the new type being registered
113 * @param compatibleID, the type of class to be accepted as ID
115 * @return true if registered, false otherwise
117 public static boolean registerIDType(String type,
118 Class compatibleID) {
119 if (compatibleType.get(type) != null) {
122 compatibleType.put(type, compatibleID);
128 * UNRegister a new ID for which Node can be created
130 * @param type, the type being UN-registered
133 public static void unRegisterIDType(String type) {
134 compatibleType.remove(type);
138 // This is the identity of the Node a (Type,ID) pair!, the full
139 // essence of this class.
140 private Object nodeID;
141 private String nodeType;
143 // Shadow value for unmarshalling
144 private String nodeIDString;
147 * Private constructor used for JAXB mapping
151 this.nodeType = null;
152 this.nodeIDString = null;
156 * Constructor for the Node objects, it validate the input so if
157 * the ID passed is not of the type expected accordingly to the
158 * type an exception is raised.
160 * @param nodeType Type of the node we are building
161 * @param id ID used by the SDN technology to identify the node
164 public Node(String nodeType, Object id) throws ConstructionException {
165 if (NodeIDType.getClassType(nodeType) != null &&
166 NodeIDType.getClassType(nodeType).isInstance(id)) {
167 this.nodeType = nodeType;
170 throw new ConstructionException("Type of incoming object:"
171 + id.getClass() + " not compatible with expected type:"
172 + NodeIDType.getClassType(nodeType));
177 * Copy Constructor for the Node objects.
179 * @param src type of nodes to copy from
182 public Node(Node src) throws ConstructionException {
184 this.nodeType = src.getType();
185 // Here we can reference the object because that is
186 // supposed to be an immutable identifier as well like a
187 // UUID/Integer and so on, hence no need to create a copy
189 this.nodeID = src.getID();
192 new ConstructionException("Null incoming object to copy from");
197 * getter for node type
200 * @return The node Type for this Node object
202 @XmlAttribute(name = "type")
203 public String getType() {
204 return this.nodeType;
208 * fill the current object from the string parameters passed, will
209 * be only used by JAXB
211 * @param typeStr string representing the type of the Node
212 * @param IDStr String representation of the ID
214 private void fillmeFromString(String typeStr, String IDStr) {
215 if (typeStr == null) {
223 this.nodeType = typeStr;
224 if (typeStr.equals(NodeIDType.OPENFLOW)) {
225 this.nodeID = Long.valueOf(HexEncode.stringToLong(IDStr));
226 } else if (typeStr.equals(NodeIDType.ONEPK)) {
228 } else if (typeStr.equals(NodeIDType.PCEP)) {
229 this.nodeID = UUID.fromString(IDStr);
230 } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
233 // We need to lookup via OSGi service registry for an
239 * Private setter for nodeType to be called by JAXB not by anyone
240 * else, Node is immutable
242 * @param type of node to be set
244 private void setType(String type) {
245 this.nodeType = type;
246 if (this.nodeIDString != null) {
247 this.fillmeFromString(type, this.nodeIDString);
255 * @return The node ID for this Node object
257 public Object getID() {
262 * Getter for the node ID in string format
264 * @return The nodeID in string format
266 @XmlAttribute(name = "id")
267 public String getNodeIDString() {
268 if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
269 return HexEncode.longToHexString((Long) this.nodeID);
271 return this.nodeID.toString();
276 * private setter to be used by JAXB
278 * @param nodeIDString String representation for NodeID
280 private void setNodeIDString(String nodeIDString) {
281 this.nodeIDString = nodeIDString;
282 if (this.nodeType != null) {
283 this.fillmeFromString(this.nodeType, nodeIDString);
288 public int hashCode() {
289 return new HashCodeBuilder(163841, 56473)
296 public boolean equals(Object obj) {
297 if (obj == null) { return false; }
298 if (obj == this) { return true; }
299 if (obj.getClass() != getClass()) {
302 Node rhs = (Node)obj;
303 return new EqualsBuilder()
304 .append(this.getType(), rhs.getType())
305 .append(this.getID(), rhs.getID())
310 public String toString() {
311 if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
312 return this.nodeType.toString() + "|"
313 + HexEncode.longToHexString((Long) this.nodeID);
315 return this.nodeType.toString() + "|" + this.nodeID.toString();
320 * Static method to get back a Node from a string
322 * @param str string formatted in toString mode that can be
323 * converted back to a Node format.
325 * @return a Node if succed or null if no
327 public static Node fromString(String str) {
332 String parts[] = str.split("\\|");
333 if (parts.length != 2) {
334 // Try to guess from a String formatted as a long because
335 // for long time openflow has been prime citizen so lets
336 // keep this legacy for now
337 String numStr = str.toUpperCase();
339 Long ofNodeID = null;
340 if (numStr.startsWith("0X")) {
341 // Try as an hex number
343 BigInteger b = new BigInteger(
344 numStr.replaceFirst("0X", ""), 16);
345 ofNodeID = Long.valueOf(b.longValue());
346 } catch (Exception ex) {
350 // Try as a decimal number
352 BigInteger b = new BigInteger(numStr);
353 ofNodeID = Long.valueOf(b.longValue());
354 } catch (Exception ex) {
359 // Startegy #3 parse as HexLong
360 if (ofNodeID == null) {
362 ofNodeID = Long.valueOf(HexEncode.stringToLong(numStr));
363 } catch (Exception ex) {
368 // We ran out of ideas ... return null
369 if (ofNodeID == null) {
373 // Lets return the cooked up NodeID
375 return new Node(NodeIDType.OPENFLOW, ofNodeID);
376 } catch (ConstructionException ex) {
381 String typeStr = parts[0];
382 String IDStr = parts[1];
384 return fromString(typeStr, IDStr);
388 * Static method to get back a Node from a pair of strings, the
389 * first one being the Type representation, the second one being
390 * the ID string representation, expected to be heavily used in
393 * @param type, the type of the node we are parsing
394 * @param id, the string representation of the node id
396 * @return a Node if succed or null if no
398 public static Node fromString(String typeStr, String IDStr) {
399 if (typeStr == null) {
407 if (typeStr.equals(NodeIDType.OPENFLOW)) {
409 Long ID = Long.valueOf(HexEncode.stringToLong(IDStr));
410 return new Node(typeStr, ID);
411 } catch (Exception ex) {
414 } else if (typeStr.equals(NodeIDType.ONEPK)) {
416 return new Node(typeStr, IDStr);
417 } catch (Exception ex) {
420 } else if (typeStr.equals(NodeIDType.PCEP)) {
422 UUID ID = UUID.fromString(IDStr);
423 return new Node(typeStr, ID);
424 } catch (Exception ex) {
427 } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
429 return new Node(typeStr, IDStr);
430 } catch (Exception ex) {
434 // We need to lookup via OSGi service registry for an