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