495af7970c7f0597ad50fc1e39863aafd3753fd6
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / core / NodeConnector.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   NodeConnector.java
12  *
13  * @brief  Describe a generic network element attachment points,
14  * attached to one Node, the NodeConnector is formed by the pair
15  * (NodeConnectorType, NodeConnectorID) because each SDN technlogy can
16  * identify an attachment point on the Node in different way.
17  *
18  */
19 package org.opendaylight.controller.sal.core;
20
21 import java.io.Serializable;
22 import java.util.concurrent.ConcurrentHashMap;
23
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlAttribute;
27 import javax.xml.bind.annotation.XmlElement;
28 import javax.xml.bind.annotation.XmlRootElement;
29
30 import org.apache.commons.lang3.tuple.ImmutablePair;
31
32 /**
33  * Describe a generic network element attachment points,
34  * attached to one Node, the NodeConnector is formed by the pair
35  * (NodeConnectorType, NodeConnectorID) because each SDN technology can
36  * identify an attachment point on the Node in different way.
37  *
38  */
39 @XmlRootElement
40 @XmlAccessorType(XmlAccessType.NONE)
41 public class NodeConnector implements Serializable {
42     private static final long serialVersionUID = 1L;
43     public static final Short SPECIALNODECONNECTORID = (short) 0;
44
45     /**
46      * Enumerate the different types of NodeConnectors supported by the class
47      *
48      */
49     public static class NodeConnectorIDType {
50         private static final
51         ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>> compatibleType =
52             new ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>>();
53         /**
54          * Represents the OFPP_CONTROLLER reserved port to forward a
55          * packet to the controller, this is to send data packets
56          * to the controller from the data plane triggering
57          * a packet_in event.
58          */
59         public static String CONTROLLER = "CTRL";
60         /**
61          * Represents the OFPP_ALL reserved OF port
62          * to forward to ALL the ports in the system ,
63          * should be used for flooding like mechanism to
64          * be used cautiously to avoid excessive flooding.
65          */
66         public static String ALL = "ALL";
67         /**
68          * Represents the OFPP_LOCAL reserved OF port
69          * to access the local networking stack of the node
70          * of which the packet is destined. Typically used for
71          * inband OF communications channel.
72          */
73         public static String SWSTACK = "SW";
74         /**
75          * Describes OFPP_Normal reserved port destination that invokes
76          * the traditional native L2/L3 HW normal forwarding functionality
77          * if supported on the forwarding element.
78          */
79         public static String HWPATH = "HW";
80         public static String OPENFLOW = "OF";
81         public static String PCEP = "PE";
82         public static String ONEPK = "PK";
83         public static String OPENFLOW2PCEP = "O2E";
84         public static String PCEP2OPENFLOW = "E2O";
85         public static String OPENFLOW2ONEPK = "O2K";
86         public static String ONEPK2OPENFLOW = "K2O";
87         public static String PCEP2ONEPK = "E2K";
88         public static String ONEPK2PCEP = "K2E";
89         public static String PRODUCTION = "PR";
90
91         // Initialize the map with some well known, even though all of
92         // them could be siting outside of here, but it's convenient
93         // for Unit Testing coverage
94         static {
95             compatibleType.put(CONTROLLER,
96                                new ImmutablePair(Short.class, null));
97             compatibleType.put(ALL,
98                                new ImmutablePair(Short.class, null));
99             compatibleType.put(SWSTACK,
100                                new ImmutablePair(Short.class, null));
101             compatibleType.put(HWPATH,
102                                new ImmutablePair(Short.class, null));
103             compatibleType.put(OPENFLOW,
104                                new ImmutablePair(Short.class,
105                                                  Node.NodeIDType.OPENFLOW));
106             compatibleType.put(PCEP,
107                                new ImmutablePair(Integer.class,
108                                                  Node.NodeIDType.PCEP));
109             compatibleType.put(ONEPK,
110                                new ImmutablePair(String.class,
111                                                  Node.NodeIDType.ONEPK));
112             compatibleType.put(OPENFLOW2PCEP,
113                                new ImmutablePair(Short.class,
114                                                  Node.NodeIDType.OPENFLOW));
115             compatibleType.put(OPENFLOW2ONEPK,
116                                new ImmutablePair(Short.class,
117                                                  Node.NodeIDType.OPENFLOW));
118             compatibleType.put(PCEP2OPENFLOW,
119                                new ImmutablePair(Integer.class,
120                                                  Node.NodeIDType.PCEP));
121             compatibleType.put(PCEP2ONEPK,
122                                new ImmutablePair(Integer.class,
123                                                  Node.NodeIDType.PCEP));
124             compatibleType.put(ONEPK2OPENFLOW,
125                                new ImmutablePair(String.class,
126                                                  Node.NodeIDType.ONEPK));
127             compatibleType.put(ONEPK2PCEP,
128                                new ImmutablePair(String.class,
129                                                  Node.NodeIDType.ONEPK));
130             compatibleType.put(PRODUCTION,
131                                new ImmutablePair(String.class,
132                                                  Node.NodeIDType.PRODUCTION));
133         }
134
135         /**
136          * Return the type of the class expected for the
137          * NodeConnectorID, it's used for validity check in the constructor
138          *
139          * @param type, the type of the NodeConnector for which we
140          * want to retrieve the compatible class to be used as ID.
141          *
142          * @return The Class which is supposed to instantiate the ID
143          * for the NodeConnectorID
144          */
145         public static Class<?> getClassType(String type) {
146             if (compatibleType.get(type) == null) {
147                 return null;
148             }
149             return compatibleType.get(type).getLeft();
150         }
151
152         /**
153          * Return the NodeIDType compatible with this NodeConnector,
154          * in fact you cannot attach for example a PCEP NodeConnector
155          * to an OpenFlow Node.
156          *
157          * @param type, the type of the NodeConnector for which we
158          * want to retrieve the compatible class to be used as ID.
159          *
160          * @return The ID of the compatible Node
161          */
162         public static String getCompatibleNode(String type) {
163             if (compatibleType.get(type) == null) {
164                 return null;
165             }
166             return compatibleType.get(type).getRight();
167         }
168
169         /**
170          * Register a new ID for which Node can be created
171          *
172          * @param type, the new type being registered
173          * @param compatibleID, the type of class to be accepted as ID
174          * @param compatibleNode, the type of Node with which this
175          * NodeConnector is compatible
176          *
177          * @return true if registered, false otherwise
178          */
179         public static boolean registerIDType(String type,
180                                              Class<? extends Object> compatibleID,
181                                              String compatibleNode) {
182             if (compatibleType.get(type) != null) {
183                 return false;
184             }  else {
185                 compatibleType.put(type, new ImmutablePair(compatibleID,
186                                                            compatibleNode));
187                 return true;
188             }
189         }
190
191         /**
192          * UNRegister a new ID for which Node can be created
193          *
194          * @param type, the type being UN-registered
195          *
196          */
197         public static void unRegisterIDType(String type) {
198             compatibleType.remove(type);
199         }
200     }
201
202     // Elements that constitute the NodeConnector
203     private Object nodeConnectorID;
204     private String nodeConnectorType;
205     @XmlElement(name = "node")
206     private Node nodeConnectorNode;
207
208     // Helper field for JAXB
209     private String nodeConnectorIDString;
210
211     /**
212      * Private constructor used for JAXB mapping
213      */
214     private NodeConnector() {
215         this.nodeConnectorIDString = null;
216         this.nodeConnectorID = null;
217         this.nodeConnectorType = null;
218         this.nodeConnectorNode = null;
219     }
220
221     /**
222      * Create a NodeConnector from the component element. The
223      * constructor make sure the NodeConnector type is congruent with
224      * the Node used and also the NodeConnector ID is of type expected
225      *
226      * @param nodeConnectorType Type of the NodeConnector
227      * @param id ID portion of the NodeConnector
228      * @param node Node to which the NodeConnector is attached too
229      *
230      */
231     public NodeConnector(String nodeConnectorType, Object id,
232             Node node) throws ConstructionException {
233         // In case of compatible type being null then assume that this
234         // port can be attached on any node.
235         String compatibleNode =
236             NodeConnectorIDType.getCompatibleNode(nodeConnectorType);
237         if (NodeConnectorIDType.getClassType(nodeConnectorType) != null &&
238             NodeConnectorIDType.getClassType(nodeConnectorType).isInstance(id) &&
239             (compatibleNode == null ||
240              node.getType().equals(compatibleNode))) {
241             this.nodeConnectorType = nodeConnectorType;
242             this.nodeConnectorID = id;
243             this.nodeConnectorNode = node;
244         } else {
245             throw new ConstructionException("Type of incoming object:"
246                     + id.getClass() + " not compatible with expected type:"
247                     + NodeConnectorIDType.getClassType(nodeConnectorType)
248                     + " or Node type incompatible:" + node.getType());
249         }
250     }
251
252     /**
253      * Copy constructor for NodeConnector
254      *
255      * @param src NodeConnector to copy from
256      *
257      */
258     public NodeConnector(NodeConnector src) throws ConstructionException {
259         if (src != null) {
260             this.nodeConnectorType = src.getType();
261             // Here we can reference the object because that is
262             // supposed to be an immutable identifier as well like a
263             // UUID/Integer and so on, hence no need to create a copy
264             // of it
265             this.nodeConnectorID = src.getID();
266             this.nodeConnectorNode = new Node(src.getNode());
267         } else {
268             throw
269                 new ConstructionException("Null incoming object to copy from");
270         }
271     }
272
273     /**
274      * getter method for NodeConnector
275      *
276      *
277      * @return the NodeConnectorType of this object
278      */
279     @XmlAttribute(name = "type")
280     public String getType() {
281         return this.nodeConnectorType;
282     }
283
284     /**
285      * fill the current object from the string parameters passed, will
286      * be only used by JAXB
287      *
288      * @param typeStr string representing the type of the Node
289      * @param IDStr String representation of the ID
290      */
291     private void fillmeFromString(String typeStr, String IDStr) {
292         if (typeStr == null) {
293             return;
294         }
295
296         if (IDStr == null) {
297             return;
298         }
299
300         this.nodeConnectorType = typeStr;
301         if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
302             typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
303             typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
304             try {
305                 Short ID = Short.parseShort(IDStr);
306                 this.nodeConnectorID = ID;
307             } catch (Exception ex) {
308                 return;
309             }
310         } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
311                    typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
312                    typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
313                    typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
314             try {
315                 this.nodeConnectorID = IDStr;
316             } catch (Exception ex) {
317                 return;
318             }
319         } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
320                    typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
321                    typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
322             try {
323                 Integer ID = Integer.parseInt(IDStr);
324                 this.nodeConnectorID = ID;
325             } catch (Exception ex) {
326                 return;
327             }
328         } else {
329             // Lookup via OSGi service registry
330         }
331     }
332
333     /**
334      * Private setter for nodeConnectorType to be called by JAXB not by anyone
335      * else, NodeConnector is immutable
336      *
337      * @param type of node to be set
338      */
339     private void setType(String type) {
340         this.nodeConnectorType = type;
341         if (this.nodeConnectorIDString != null) {
342             this.fillmeFromString(type, this.nodeConnectorIDString);
343         }
344     }
345
346     /**
347      * getter method for NodeConnector
348      *
349      *
350      * @return the NodeConnector ID of this object
351      */
352     public Object getID() {
353         return this.nodeConnectorID;
354     }
355
356     /**
357      * getter method for NodeConnector ID in string format.
358      *
359      *
360      * @return the NodeConnector ID of this object in String format
361      */
362     @XmlAttribute(name = "id")
363     public String getNodeConnectorIDString() {
364         return this.nodeConnectorID.toString();
365     }
366
367     /**
368      * private setter to be used by JAXB
369      *
370      * @param nodeConnectorIDString String representation for NodeConnectorID
371      */
372     private void setNodeConnectorIDString(String IDStr) {
373         this.nodeConnectorIDString = IDStr;
374         if (this.nodeConnectorType != null) {
375             this.fillmeFromString(this.nodeConnectorType, IDStr);
376         }
377     }
378
379     /**
380      * getter method for NodeConnector
381      *
382      *
383      * @return the Node of this object
384      */
385     public Node getNode() {
386         return this.nodeConnectorNode;
387     }
388
389     @Override
390     public int hashCode() {
391         final int prime = 31;
392         int result = 1;
393         result = prime * result
394                 + ((nodeConnectorID == null) ? 0 : nodeConnectorID.hashCode());
395         result = prime
396                 * result
397                 + ((nodeConnectorNode == null) ? 0 : nodeConnectorNode
398                         .hashCode());
399         result = prime
400                 * result
401                 + ((nodeConnectorType == null) ? 0 : nodeConnectorType
402                         .hashCode());
403         return result;
404     }
405
406     @Override
407     public boolean equals(Object obj) {
408         if (this == obj)
409             return true;
410         if (obj == null)
411             return false;
412         if (getClass() != obj.getClass())
413             return false;
414         NodeConnector other = (NodeConnector) obj;
415         if (nodeConnectorID == null) {
416             if (other.nodeConnectorID != null)
417                 return false;
418         } else if (!nodeConnectorID.equals(other.nodeConnectorID))
419             return false;
420         if (nodeConnectorNode == null) {
421             if (other.nodeConnectorNode != null)
422                 return false;
423         } else if (!nodeConnectorNode.equals(other.nodeConnectorNode))
424             return false;
425         if (nodeConnectorType == null) {
426             if (other.nodeConnectorType != null)
427                 return false;
428         } else if (!nodeConnectorType.equals(other.nodeConnectorType))
429             return false;
430         return true;
431     }
432
433     @Override
434     public String toString() {
435         return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
436     }
437
438     /**
439      * A String representation of the NodeConnector without
440      * the Node context
441      *
442      * @return A String representation of the NodeConnector without
443      * the Node context
444      */
445     public String getNodeConnectorIdAsString() {
446         if (this.nodeConnectorType
447             .equals(NodeConnectorIDType.CONTROLLER) ||
448             this.nodeConnectorType
449             .equals(NodeConnectorIDType.ALL) ||
450             this.nodeConnectorType
451             .equals(NodeConnectorIDType.SWSTACK) ||
452             this.nodeConnectorType
453             .equals(NodeConnectorIDType.HWPATH)) {
454             return this.nodeConnectorType.toString();
455         } else {
456             return this.nodeConnectorType.toString() + "|"
457                     + this.nodeConnectorID.toString();
458         }
459     }
460
461     /**
462      * return a NodeConnector from a string
463      *
464      * @param str String to be parsed in a NodeConnector
465      *
466      * @return the NodeConnector if parse is successful, null otherwise
467      */
468     public static NodeConnector fromString(String str) {
469         if (str == null) {
470             return null;
471         }
472         String parts[] = str.split("\\@");
473         if (parts.length != 2) {
474             return null;
475         }
476         // Now get the Node from the Node portion
477         Node n = Node.fromString(parts[1]);
478         if (n == null) {
479             return null;
480         }
481         return fromStringNoNode(parts[0], n);
482     }
483
484     /**
485      * return a NodeConnector from a string not containing explicitly
486      * the Node portion which has to be supplied as parameter
487      *
488      * @param str String to be parsed in a NodeConnector
489      * @param n Node to which the NodeConnector is attached
490      *
491      * @return the NodeConnector if parse is successful, null otherwise
492      */
493     public static NodeConnector fromStringNoNode(String str, Node n) {
494         if (str == null) {
495             return null;
496         }
497         String nodeConnectorParts[] = str.split("\\|");
498         if (nodeConnectorParts.length != 2) {
499             // Try to guess from a String formatted as a short because
500             // for long time openflow has been prime citizen so lets
501             // keep this legacy for now
502             String numStr = str.toUpperCase();
503
504             Short ofPortID = null;
505             // Try as an decimal/hex number
506             try {
507                 ofPortID = Short.decode(numStr);
508             } catch (Exception ex) {
509                 ofPortID = null;
510             }
511
512             // Lets try the special ports we know about
513             if (ofPortID == null) {
514                 try {
515                     if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
516                             .toString())) {
517                         return new NodeConnector(
518                                 NodeConnectorIDType.CONTROLLER,
519                                 SPECIALNODECONNECTORID, n);
520                     }
521                     if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
522                             .toString())) {
523                         return new NodeConnector(NodeConnectorIDType.HWPATH,
524                                 SPECIALNODECONNECTORID, n);
525                     }
526                     if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
527                             .toString())) {
528                         return new NodeConnector(NodeConnectorIDType.SWSTACK,
529                                 SPECIALNODECONNECTORID, n);
530                     }
531                     if (str
532                             .equalsIgnoreCase(NodeConnectorIDType.ALL
533                                     .toString())) {
534                         return new NodeConnector(NodeConnectorIDType.ALL,
535                                 SPECIALNODECONNECTORID, n);
536                     }
537                 } catch (ConstructionException ex) {
538                     return null;
539                 }
540                 return null;
541             }
542
543             // Lets return the cooked up NodeID
544             try {
545                 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
546                         ofPortID, n);
547             } catch (ConstructionException ex) {
548                 return null;
549             }
550         }
551
552         String typeStr = nodeConnectorParts[0];
553         String IDStr = nodeConnectorParts[1];
554         return fromStringNoNode(typeStr, IDStr, n);
555     }
556
557     /**
558      * return a NodeConnector from a pair (type, ID) in string format
559      * not containing explicitly the Node portion which has to be
560      * supplied as parameter
561      *
562      * @param typeStr type String to be parsed in a NodeConnector
563      * @param IDStr ID String portion to be parsed in a NodeConnector
564      * @param n Node to which the NodeConnector is attached
565      *
566      * @return the NodeConnector if parse is successful, null otherwise
567      */
568     public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
569                                                  Node n) {
570         if (typeStr == null) {
571             return null;
572         }
573         if (IDStr == null) {
574             return null;
575         }
576
577         if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
578             typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
579             typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
580             try {
581                 Short ID = Short.parseShort(IDStr);
582                 return new NodeConnector(typeStr, ID, n);
583             } catch (Exception ex) {
584                 return null;
585             }
586         } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
587                    typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
588                    typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
589                    typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
590             try {
591                 return new NodeConnector(typeStr, IDStr, n);
592             } catch (Exception ex) {
593                 return null;
594             }
595         } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
596                    typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
597                    typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
598             try {
599                 Integer ID = Integer.parseInt(IDStr);
600                 return new NodeConnector(typeStr, ID, n);
601             } catch (Exception ex) {
602                 return null;
603             }
604         } else {
605             // Lookup via OSGi service registry
606         }
607         return null;
608     }
609 }