Refactor SubnetConfig
[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(Short.class, null));
101             compatibleType.put(ALL,
102                                new ImmutablePair(Short.class, null));
103             compatibleType.put(SWSTACK,
104                                new ImmutablePair(Short.class, null));
105             compatibleType.put(HWPATH,
106                                new ImmutablePair(Short.class, null));
107             compatibleType.put(OPENFLOW,
108                                new ImmutablePair(Short.class,
109                                                  Node.NodeIDType.OPENFLOW));
110             compatibleType.put(PCEP,
111                                new ImmutablePair(Integer.class,
112                                                  Node.NodeIDType.PCEP));
113             compatibleType.put(ONEPK,
114                                new ImmutablePair(String.class,
115                                                  Node.NodeIDType.ONEPK));
116             compatibleType.put(OPENFLOW2PCEP,
117                                new ImmutablePair(Short.class,
118                                                  Node.NodeIDType.OPENFLOW));
119             compatibleType.put(OPENFLOW2ONEPK,
120                                new ImmutablePair(Short.class,
121                                                  Node.NodeIDType.OPENFLOW));
122             compatibleType.put(PCEP2OPENFLOW,
123                                new ImmutablePair(Integer.class,
124                                                  Node.NodeIDType.PCEP));
125             compatibleType.put(PCEP2ONEPK,
126                                new ImmutablePair(Integer.class,
127                                                  Node.NodeIDType.PCEP));
128             compatibleType.put(ONEPK2OPENFLOW,
129                                new ImmutablePair(String.class,
130                                                  Node.NodeIDType.ONEPK));
131             compatibleType.put(ONEPK2PCEP,
132                                new ImmutablePair(String.class,
133                                                  Node.NodeIDType.ONEPK));
134             compatibleType.put(PRODUCTION,
135                                new ImmutablePair(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(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     private void setType(String type) {
344         this.nodeConnectorType = type;
345         if (this.nodeConnectorIDString != null) {
346             this.fillmeFromString(type, this.nodeConnectorIDString);
347         }
348     }
349
350     /**
351      * getter method for NodeConnector
352      *
353      *
354      * @return the NodeConnector ID of this object
355      */
356     public Object getID() {
357         return this.nodeConnectorID;
358     }
359
360     /**
361      * getter method for NodeConnector ID in string format.
362      *
363      *
364      * @return the NodeConnector ID of this object in String format
365      */
366     @XmlElement(name = "id")
367     public String getNodeConnectorIDString() {
368         return this.nodeConnectorID.toString();
369     }
370
371     /**
372      * private setter to be used by JAXB
373      *
374      * @param nodeConnectorIDString String representation for NodeConnectorID
375      */
376     private void setNodeConnectorIDString(String IDStr) {
377         this.nodeConnectorIDString = IDStr;
378         if (this.nodeConnectorType != null) {
379             this.fillmeFromString(this.nodeConnectorType, IDStr);
380         }
381     }
382
383     /**
384      * getter method for NodeConnector
385      *
386      *
387      * @return the Node of this object
388      */
389     public Node getNode() {
390         return this.nodeConnectorNode;
391     }
392
393     @Override
394     public int hashCode() {
395         final int prime = 31;
396         int result = 1;
397         result = prime * result
398                 + ((nodeConnectorID == null) ? 0 : nodeConnectorID.hashCode());
399         result = prime
400                 * result
401                 + ((nodeConnectorNode == null) ? 0 : nodeConnectorNode
402                         .hashCode());
403         result = prime
404                 * result
405                 + ((nodeConnectorType == null) ? 0 : nodeConnectorType
406                         .hashCode());
407         return result;
408     }
409
410     @Override
411     public boolean equals(Object obj) {
412         if (this == obj) {
413             return true;
414         }
415         if (obj == null) {
416             return false;
417         }
418         if (getClass() != obj.getClass()) {
419             return false;
420         }
421         NodeConnector other = (NodeConnector) obj;
422         if (nodeConnectorID == null) {
423             if (other.nodeConnectorID != null) {
424                 return false;
425             }
426         } else if (!nodeConnectorID.equals(other.nodeConnectorID)) {
427             return false;
428         }
429         if (nodeConnectorNode == null) {
430             if (other.nodeConnectorNode != null) {
431                 return false;
432             }
433         } else if (!nodeConnectorNode.equals(other.nodeConnectorNode)) {
434             return false;
435         }
436         if (nodeConnectorType == null) {
437             if (other.nodeConnectorType != null) {
438                 return false;
439             }
440         } else if (!nodeConnectorType.equals(other.nodeConnectorType)) {
441             return false;
442         }
443         return true;
444     }
445
446     @Override
447     public String toString() {
448         return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
449     }
450
451     /**
452      * A String representation of the NodeConnector without
453      * the Node context
454      *
455      * @return A String representation of the NodeConnector without
456      * the Node context
457      */
458     public String getNodeConnectorIdAsString() {
459         if (this.nodeConnectorType
460             .equals(NodeConnectorIDType.CONTROLLER) ||
461             this.nodeConnectorType
462             .equals(NodeConnectorIDType.ALL) ||
463             this.nodeConnectorType
464             .equals(NodeConnectorIDType.SWSTACK) ||
465             this.nodeConnectorType
466             .equals(NodeConnectorIDType.HWPATH)) {
467             return this.nodeConnectorType.toString();
468         } else {
469             return this.nodeConnectorType.toString() + "|"
470                     + this.nodeConnectorID.toString();
471         }
472     }
473
474     /**
475      * return a NodeConnector from a string
476      *
477      * @param str String to be parsed in a NodeConnector
478      *
479      * @return the NodeConnector if parse is successful, null otherwise
480      */
481     public static NodeConnector fromString(String str) {
482         if (str == null) {
483             return null;
484         }
485         String parts[] = str.split("\\@");
486         if (parts.length != 2) {
487             return null;
488         }
489         // Now get the Node from the Node portion
490         Node n = Node.fromString(parts[1]);
491         if (n == null) {
492             return null;
493         }
494         return fromStringNoNode(parts[0], n);
495     }
496
497     /**
498      * return a set of NodeConnector from a collection of string
499      *
500      * @param stringCollection Collection of String object to be parsed as a NodeConnector
501      *
502      * @return the Set of unique NodeConnector objects if parse is successful, empty Set otherwise
503      */
504     public static Set<NodeConnector> fromString(Collection<String> stringCollection) {
505         Set<NodeConnector> set = new HashSet<NodeConnector>();
506         if (stringCollection != null) {
507
508             for (String str : stringCollection) {
509                 NodeConnector nodeConnector = NodeConnector.fromString(str);
510                 if (nodeConnector != null) {
511                     set.add(nodeConnector);
512                 }
513             }
514         }
515         return set;
516     }
517
518     /**
519      * return a NodeConnector from a string not containing explicitly
520      * the Node portion which has to be supplied as parameter
521      *
522      * @param str String to be parsed in a NodeConnector
523      * @param n Node to which the NodeConnector is attached
524      *
525      * @return the NodeConnector if parse is successful, null otherwise
526      */
527     public static NodeConnector fromStringNoNode(String str, Node n) {
528         if (str == null) {
529             return null;
530         }
531         String nodeConnectorParts[] = str.split("\\|");
532         if (nodeConnectorParts.length != 2) {
533             // Try to guess from a String formatted as a short because
534             // for long time openflow has been prime citizen so lets
535             // keep this legacy for now
536             String numStr = str.toUpperCase();
537
538             Short ofPortID = null;
539             // Try as an decimal/hex number
540             try {
541                 ofPortID = Short.decode(numStr);
542             } catch (Exception ex) {
543                 ofPortID = null;
544             }
545
546             // Lets try the special ports we know about
547             if (ofPortID == null) {
548                 try {
549                     if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
550                             .toString())) {
551                         return new NodeConnector(
552                                 NodeConnectorIDType.CONTROLLER,
553                                 SPECIALNODECONNECTORID, n);
554                     }
555                     if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
556                             .toString())) {
557                         return new NodeConnector(NodeConnectorIDType.HWPATH,
558                                 SPECIALNODECONNECTORID, n);
559                     }
560                     if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
561                             .toString())) {
562                         return new NodeConnector(NodeConnectorIDType.SWSTACK,
563                                 SPECIALNODECONNECTORID, n);
564                     }
565                     if (str
566                             .equalsIgnoreCase(NodeConnectorIDType.ALL
567                                     .toString())) {
568                         return new NodeConnector(NodeConnectorIDType.ALL,
569                                 SPECIALNODECONNECTORID, n);
570                     }
571                 } catch (ConstructionException ex) {
572                     return null;
573                 }
574                 return null;
575             }
576
577             // Lets return the cooked up NodeID
578             try {
579                 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
580                         ofPortID, n);
581             } catch (ConstructionException ex) {
582                 return null;
583             }
584         }
585
586         String typeStr = nodeConnectorParts[0];
587         String IDStr = nodeConnectorParts[1];
588         return fromStringNoNode(typeStr, IDStr, n);
589     }
590
591     /**
592      * return a NodeConnector from a pair (type, ID) in string format
593      * not containing explicitly the Node portion which has to be
594      * supplied as parameter
595      *
596      * @param typeStr type String to be parsed in a NodeConnector
597      * @param IDStr ID String portion to be parsed in a NodeConnector
598      * @param n Node to which the NodeConnector is attached
599      *
600      * @return the NodeConnector if parse is successful, null otherwise
601      */
602     public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
603                                                  Node n) {
604         if (typeStr == null) {
605             return null;
606         }
607         if (IDStr == null) {
608             return null;
609         }
610
611         if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
612             typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
613             typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
614             try {
615                 Short ID = Short.parseShort(IDStr);
616                 return new NodeConnector(typeStr, ID, n);
617             } catch (Exception ex) {
618                 return null;
619             }
620         } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
621                    typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
622                    typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
623                    typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
624             try {
625                 return new NodeConnector(typeStr, IDStr, n);
626             } catch (Exception ex) {
627                 return null;
628             }
629         } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
630                    typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
631                    typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
632             try {
633                 Integer ID = Integer.parseInt(IDStr);
634                 return new NodeConnector(typeStr, ID, n);
635             } catch (Exception ex) {
636                 return null;
637             }
638         } else {
639             //Use INodeConnectorFactory to create a NodeConnector of registered type.
640             //The protocol plugin being used depends on typeStr.
641             INodeConnectorFactory f = (INodeConnectorFactory) ServiceHelper
642                     .getGlobalInstance(INodeConnectorFactory.class, new NodeConnector(), "(protocolName="+typeStr+")");
643             if(f==null) {
644                 return null;
645             }
646             return f.fromStringNoNode(typeStr, IDStr, n);
647         }
648     }
649 }