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