Make sure invokeOperation is set once
[controller.git] / opendaylight / adsal / 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.XmlElement;
30 import javax.xml.bind.annotation.XmlRootElement;
31
32 import org.opendaylight.controller.sal.utils.HexEncode;
33 import org.opendaylight.controller.sal.utils.INodeFactory;
34 import org.opendaylight.controller.sal.utils.ServiceHelper;
35
36 /**
37  * Describe a generic network element in multiple SDNs technologies. A
38  * Node is identified by the pair (NodeType, NodeID), the nodetype are
39  * needed in order to further specify the nodeID
40  *
41  */
42 @XmlAccessorType(XmlAccessType.NONE)
43 @XmlRootElement
44 @Deprecated
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     @SuppressWarnings("unused")
249     private void setType(String type) {
250         this.nodeType = type;
251         if (this.nodeIDString != null) {
252             this.fillmeFromString(type, this.nodeIDString);
253         }
254     }
255
256     /**
257      * getter for node ID
258      *
259      *
260      * @return The node ID for this Node object
261      */
262     public Object getID() {
263         return this.nodeID;
264     }
265
266     /**
267      * Getter for the node ID in string format
268      *
269      * @return The nodeID in string format
270      */
271     @XmlElement(name = "id")
272     public String getNodeIDString() {
273         if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
274             return HexEncode.longToHexString((Long) this.nodeID);
275         } else {
276             return this.nodeID.toString();
277         }
278     }
279
280     /**
281      * private setter to be used by JAXB
282      *
283      * @param nodeIDString String representation for NodeID
284      */
285     @SuppressWarnings("unused")
286     private void setNodeIDString(String nodeIDString) {
287         this.nodeIDString = nodeIDString;
288         if (this.nodeType != null) {
289             this.fillmeFromString(this.nodeType, nodeIDString);
290         }
291     }
292
293     @Override
294     public int hashCode() {
295         final int prime = 31;
296         int result = 1;
297         result = prime * result + ((nodeID == null) ? 0 : nodeID.hashCode());
298         result = prime * result
299                 + ((nodeType == null) ? 0 : nodeType.hashCode());
300         return result;
301     }
302
303     @Override
304     public boolean equals(Object obj) {
305         if (this == obj)
306             return true;
307         if (obj == null)
308             return false;
309         if (getClass() != obj.getClass())
310             return false;
311         Node other = (Node) obj;
312         if (nodeID == null) {
313             if (other.nodeID != null)
314                 return false;
315         } else if (!nodeID.equals(other.nodeID))
316             return false;
317         if (nodeType == null) {
318             if (other.nodeType != null)
319                 return false;
320         } else if (!nodeType.equals(other.nodeType))
321             return false;
322         return true;
323     }
324
325     @Override
326     public String toString() {
327         if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
328             return this.nodeType + "|"
329                 + HexEncode.longToHexString((Long) this.nodeID);
330         } else {
331             return this.nodeType + "|" + this.nodeID.toString();
332         }
333     }
334
335     /**
336      * Static method to get back a Node from a string
337      *
338      * @param str string formatted in toString mode that can be
339      * converted back to a Node format.
340      *
341      * @return a Node if succed or null if no
342      */
343     public static Node fromString(String str) {
344         if (str == null) {
345             return null;
346         }
347
348         String parts[] = str.split("\\|");
349         if (parts.length != 2) {
350             // Try to guess from a String formatted as a long because
351             // for long time openflow has been prime citizen so lets
352             // keep this legacy for now
353             String numStr = str.toUpperCase();
354
355             Long ofNodeID = null;
356             if (numStr.startsWith("0X")) {
357                 // Try as an hex number
358                 try {
359                     BigInteger b = new BigInteger(
360                         numStr.replaceFirst("0X", ""), 16);
361                     ofNodeID = Long.valueOf(b.longValue());
362                 } catch (Exception ex) {
363                     ofNodeID = null;
364                 }
365             } else {
366                 // Try as a decimal number
367                 try {
368                     BigInteger b = new BigInteger(numStr);
369                     ofNodeID = Long.valueOf(b.longValue());
370                 } catch (Exception ex) {
371                     ofNodeID = null;
372                 }
373             }
374
375             // Startegy #3 parse as HexLong
376             if (ofNodeID == null) {
377                 try {
378                     ofNodeID = Long.valueOf(HexEncode.stringToLong(numStr));
379                 } catch (Exception ex) {
380                     ofNodeID = null;
381                 }
382             }
383
384             // We ran out of ideas ... return null
385             if (ofNodeID == null) {
386                 return null;
387             }
388
389             // Lets return the cooked up NodeID
390             try {
391                 return new Node(NodeIDType.OPENFLOW, ofNodeID);
392             } catch (ConstructionException ex) {
393                 return null;
394             }
395         }
396
397         String typeStr = parts[0];
398         String IDStr = parts[1];
399
400         return fromString(typeStr, IDStr);
401     }
402
403     /**
404      * Static method to get back a Node from a pair of strings, the
405      * first one being the Type representation, the second one being
406      * the ID string representation, expected to be heavily used in
407      * northbound API.
408      *
409      * @param type, the type of the node we are parsing
410      * @param id, the string representation of the node id
411      *
412      * @return a Node if succed or null if no
413      */
414     public static Node fromString(String typeStr, String IDStr) {
415         if (typeStr == null) {
416             return null;
417         }
418
419         if (IDStr == null) {
420             return null;
421         }
422
423         if (typeStr.equals(NodeIDType.OPENFLOW)) {
424             try {
425                 Long ID = Long.valueOf(HexEncode.stringToLong(IDStr));
426                 return new Node(typeStr, ID);
427             } catch (Exception ex) {
428                 return null;
429             }
430         } else if (typeStr.equals(NodeIDType.ONEPK)) {
431             try {
432                 return new Node(typeStr, IDStr);
433             } catch (Exception ex) {
434                 return null;
435             }
436         } else if (typeStr.equals(NodeIDType.PCEP)) {
437             try {
438                 UUID ID = UUID.fromString(IDStr);
439                 return new Node(typeStr, ID);
440             } catch (Exception ex) {
441                 return null;
442             }
443         } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
444             try {
445                 return new Node(typeStr, IDStr);
446             } catch (Exception ex) {
447                 return null;
448             }
449         } else {
450             //Use INodeFactory to create a Node of registered Node type.
451             //The protocol plugin being used depends on typeStr.
452             INodeFactory f = (INodeFactory) ServiceHelper
453                     .getGlobalInstance(INodeFactory.class, new Node(), "(protocolName="+typeStr+")");
454             if(f==null)
455                 return null;
456             return f.fromString(typeStr, IDStr);
457         }
458     }
459 }