Simple changes to eliminate pmd warnings
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / core / Node.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
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
8  */
9
10 /**
11  * @file   Node.java
12  *
13  * @brief  Describe a generic network element in multiple SDNs technologies
14  *
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
18  */
19 package org.opendaylight.controller.sal.core;
20
21 import java.io.Serializable;
22 import java.math.BigInteger;
23 import java.util.Set;
24 import java.util.UUID;
25 import java.util.concurrent.ConcurrentHashMap;
26
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;
32
33 import org.opendaylight.controller.sal.utils.HexEncode;
34 import org.opendaylight.controller.sal.utils.INodeFactory;
35 import org.opendaylight.controller.sal.utils.ServiceHelper;
36
37 /**
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
41  *
42  */
43 @XmlAccessorType(XmlAccessType.NONE)
44 @XmlRootElement
45 public class Node implements Serializable {
46     private static final long serialVersionUID = 1L;
47
48     /**
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
54      * surround.
55      */
56     public static final class NodeIDType {
57         private static final ConcurrentHashMap<String, Class<? extends Object>> compatibleType =
58             new ConcurrentHashMap<String, Class<? extends Object>>();
59         /**
60          * Identifier for an OpenFlow node
61          */
62         public static String OPENFLOW = "OF";
63         /**
64          * Identifier for a PCEP node
65          */
66         public static String PCEP = "PE";
67         /**
68          * Identifier for a ONEPK node
69          */
70         public static String ONEPK = "PK";
71         /**
72          * Identifier for a node in a non-SDN network
73          */
74         public static String PRODUCTION = "PR";
75
76         // Pre-populated types, just here for convenience and ease of
77         // unit-testing, but certainly those could live also outside.
78         static {
79             compatibleType.put(OPENFLOW, Long.class);
80             compatibleType.put(PCEP, UUID.class);
81             compatibleType.put(ONEPK, String.class);
82             compatibleType.put(PRODUCTION, String.class);
83         }
84
85         /**
86          * Return the type of the class expected for the
87          * NodeID, it's used for validity check in the constructor
88          *
89          * @param nodeType the type of the node we want to check
90          * compatibility for
91          *
92          * @return The Class which is supposed to instantiate the ID
93          * for the NodeID
94          */
95         public static Class<?> getClassType(String nodeType) {
96             return compatibleType.get(nodeType);
97         }
98
99         /**
100          * Returns all the registered nodeIDTypes currently available
101          *
102          * @return The current registered NodeIDTypes
103          */
104         public static Set<String> values() {
105             return compatibleType.keySet();
106         }
107
108         /**
109          * Register a new ID for which Node can be created
110          *
111          * @param type, the new type being registered
112          * @param compatibleID, the type of class to be accepted as ID
113          *
114          * @return true if registered, false otherwise
115          */
116         public static boolean registerIDType(String type,
117                                              Class<? extends Object> compatibleID) {
118             if (compatibleType.get(type) != null) {
119                 return false;
120             }  else {
121                 compatibleType.put(type, compatibleID);
122                 return true;
123             }
124         }
125
126         /**
127          * UNRegister a new ID for which Node can be created
128          *
129          * @param type, the type being UN-registered
130          *
131          */
132         public static void unRegisterIDType(String type) {
133             compatibleType.remove(type);
134         }
135     }
136
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;
141
142     // Shadow value for unmarshalling
143     private String nodeIDString;
144
145     /**
146      * Private constructor used for JAXB mapping
147      */
148     private Node() {
149         this.nodeID = null;
150         this.nodeType = null;
151         this.nodeIDString = null;
152     }
153
154     /**
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.
158      *
159      * @param nodeType Type of the node we are building
160      * @param id ID used by the SDN technology to identify the node
161      *
162      */
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;
167             this.nodeID = id;
168         } else {
169             throw new ConstructionException("Type of incoming object:"
170                                             + id.getClass() + " not compatible with expected type:"
171                                             + NodeIDType.getClassType(nodeType));
172         }
173     }
174
175     /**
176      * Copy Constructor for the Node objects.
177      *
178      * @param src type of nodes to copy from
179      *
180      */
181     public Node(Node src) throws ConstructionException {
182         if (src != null) {
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
187             // of it
188             this.nodeID = src.getID();
189         } else {
190             throw
191                 new ConstructionException("Null incoming object to copy from");
192         }
193     }
194
195     /**
196      * getter for node type
197      *
198      *
199      * @return The node Type for this Node object
200      */
201     @XmlElement(name = "type")
202     public String getType() {
203         return this.nodeType;
204     }
205
206     /**
207      * fill the current object from the string parameters passed, will
208      * be only used by JAXB
209      *
210      * @param typeStr string representing the type of the Node
211      * @param IDStr String representation of the ID
212      */
213     private void fillmeFromString(String typeStr, String IDStr) {
214         if (typeStr == null) {
215             return;
216         }
217
218         if (IDStr == null) {
219             return;
220         }
221
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)) {
226             this.nodeID = IDStr;
227         } else if (typeStr.equals(NodeIDType.PCEP)) {
228             this.nodeID = UUID.fromString(IDStr);
229         } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
230             this.nodeID = IDStr;
231         } else {
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+")");
235             if(f!=null){
236                 Node n = f.fromString(typeStr, IDStr);
237                 this.nodeID = n.nodeID;
238             }
239         }
240     }
241
242     /**
243      * Private setter for nodeType to be called by JAXB not by anyone
244      * else, Node is immutable
245      *
246      * @param type of node to be set
247      */
248     private void setType(String type) {
249         this.nodeType = type;
250         if (this.nodeIDString != null) {
251             this.fillmeFromString(type, this.nodeIDString);
252         }
253     }
254
255     /**
256      * getter for node ID
257      *
258      *
259      * @return The node ID for this Node object
260      */
261     public Object getID() {
262         return this.nodeID;
263     }
264
265     /**
266      * Getter for the node ID in string format
267      *
268      * @return The nodeID in string format
269      */
270     @XmlElement(name = "id")
271     public String getNodeIDString() {
272         if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
273             return HexEncode.longToHexString((Long) this.nodeID);
274         } else {
275             return this.nodeID.toString();
276         }
277     }
278
279     /**
280      * private setter to be used by JAXB
281      *
282      * @param nodeIDString String representation for NodeID
283      */
284     private void setNodeIDString(String nodeIDString) {
285         this.nodeIDString = nodeIDString;
286         if (this.nodeType != null) {
287             this.fillmeFromString(this.nodeType, nodeIDString);
288         }
289     }
290
291     @Override
292     public int hashCode() {
293         final int prime = 31;
294         int result = 1;
295         result = prime * result + ((nodeID == null) ? 0 : nodeID.hashCode());
296         result = prime * result
297                 + ((nodeType == null) ? 0 : nodeType.hashCode());
298         return result;
299     }
300
301     @Override
302     public boolean equals(Object obj) {
303         if (this == obj)
304             return true;
305         if (obj == null)
306             return false;
307         if (getClass() != obj.getClass())
308             return false;
309         Node other = (Node) obj;
310         if (nodeID == null) {
311             if (other.nodeID != null)
312                 return false;
313         } else if (!nodeID.equals(other.nodeID))
314             return false;
315         if (nodeType == null) {
316             if (other.nodeType != null)
317                 return false;
318         } else if (!nodeType.equals(other.nodeType))
319             return false;
320         return true;
321     }
322
323     @Override
324     public String toString() {
325         if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
326             return this.nodeType + "|"
327                 + HexEncode.longToHexString((Long) this.nodeID);
328         } else {
329             return this.nodeType + "|" + this.nodeID.toString();
330         }
331     }
332
333     /**
334      * Static method to get back a Node from a string
335      *
336      * @param str string formatted in toString mode that can be
337      * converted back to a Node format.
338      *
339      * @return a Node if succed or null if no
340      */
341     public static Node fromString(String str) {
342         if (str == null) {
343             return null;
344         }
345
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();
352
353             Long ofNodeID = null;
354             if (numStr.startsWith("0X")) {
355                 // Try as an hex number
356                 try {
357                     BigInteger b = new BigInteger(
358                         numStr.replaceFirst("0X", ""), 16);
359                     ofNodeID = Long.valueOf(b.longValue());
360                 } catch (Exception ex) {
361                     ofNodeID = null;
362                 }
363             } else {
364                 // Try as a decimal number
365                 try {
366                     BigInteger b = new BigInteger(numStr);
367                     ofNodeID = Long.valueOf(b.longValue());
368                 } catch (Exception ex) {
369                     ofNodeID = null;
370                 }
371             }
372
373             // Startegy #3 parse as HexLong
374             if (ofNodeID == null) {
375                 try {
376                     ofNodeID = Long.valueOf(HexEncode.stringToLong(numStr));
377                 } catch (Exception ex) {
378                     ofNodeID = null;
379                 }
380             }
381
382             // We ran out of ideas ... return null
383             if (ofNodeID == null) {
384                 return null;
385             }
386
387             // Lets return the cooked up NodeID
388             try {
389                 return new Node(NodeIDType.OPENFLOW, ofNodeID);
390             } catch (ConstructionException ex) {
391                 return null;
392             }
393         }
394
395         String typeStr = parts[0];
396         String IDStr = parts[1];
397
398         return fromString(typeStr, IDStr);
399     }
400
401     /**
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
405      * northbound API.
406      *
407      * @param type, the type of the node we are parsing
408      * @param id, the string representation of the node id
409      *
410      * @return a Node if succed or null if no
411      */
412     public static Node fromString(String typeStr, String IDStr) {
413         if (typeStr == null) {
414             return null;
415         }
416
417         if (IDStr == null) {
418             return null;
419         }
420
421         if (typeStr.equals(NodeIDType.OPENFLOW)) {
422             try {
423                 Long ID = Long.valueOf(HexEncode.stringToLong(IDStr));
424                 return new Node(typeStr, ID);
425             } catch (Exception ex) {
426                 return null;
427             }
428         } else if (typeStr.equals(NodeIDType.ONEPK)) {
429             try {
430                 return new Node(typeStr, IDStr);
431             } catch (Exception ex) {
432                 return null;
433             }
434         } else if (typeStr.equals(NodeIDType.PCEP)) {
435             try {
436                 UUID ID = UUID.fromString(IDStr);
437                 return new Node(typeStr, ID);
438             } catch (Exception ex) {
439                 return null;
440             }
441         } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
442             try {
443                 return new Node(typeStr, IDStr);
444             } catch (Exception ex) {
445                 return null;
446             }
447         } else {
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+")");
452             if(f==null)
453                 return null;
454             return f.fromString(typeStr, IDStr);
455         }
456     }
457 }