3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
11 * @file NodeConnector.java
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.
19 package org.opendaylight.controller.sal.core;
21 import java.io.Serializable;
22 import java.util.Collection;
23 import java.util.HashSet;
25 import java.util.concurrent.ConcurrentHashMap;
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;
32 import org.apache.commons.lang3.tuple.ImmutablePair;
33 import org.opendaylight.controller.sal.utils.INodeConnectorFactory;
34 import org.opendaylight.controller.sal.utils.ServiceHelper;
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.
44 @XmlAccessorType(XmlAccessType.NONE)
46 public class NodeConnector implements Serializable {
47 private static final long serialVersionUID = 1L;
48 public static final Short SPECIALNODECONNECTORID = (short) 0;
51 * Enumerate the different types of NodeConnectors supported by the class
54 public static class NodeConnectorIDType {
56 ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>> compatibleType =
57 new ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>>();
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
64 public static String CONTROLLER = "CTRL";
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.
71 public static String ALL = "ALL";
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.
78 public static String SWSTACK = "SW";
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.
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";
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
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));
141 * Return the type of the class expected for the
142 * NodeConnectorID, it's used for validity check in the constructor
144 * @param type, the type of the NodeConnector for which we
145 * want to retrieve the compatible class to be used as ID.
147 * @return The Class which is supposed to instantiate the ID
148 * for the NodeConnectorID
150 public static Class<?> getClassType(String type) {
151 if (compatibleType.get(type) == null) {
154 return compatibleType.get(type).getLeft();
158 * Return the NodeIDType compatible with this NodeConnector,
159 * in fact you cannot attach for example a PCEP NodeConnector
160 * to an OpenFlow Node.
162 * @param type, the type of the NodeConnector for which we
163 * want to retrieve the compatible class to be used as ID.
165 * @return The ID of the compatible Node
167 public static String getCompatibleNode(String type) {
168 if (compatibleType.get(type) == null) {
171 return compatibleType.get(type).getRight();
175 * Register a new ID for which Node can be created
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
182 * @return true if registered, false otherwise
184 public static boolean registerIDType(String type,
185 Class<? extends Object> compatibleID,
186 String compatibleNode) {
187 if (compatibleType.get(type) != null) {
190 compatibleType.put(type, new ImmutablePair<Class<? extends Object>, String>(compatibleID,
197 * UNRegister a new ID for which Node can be created
199 * @param type, the type being UN-registered
202 public static void unRegisterIDType(String type) {
203 compatibleType.remove(type);
207 // Elements that constitute the NodeConnector
208 private Object nodeConnectorID;
209 private String nodeConnectorType;
210 @XmlElement(name = "node")
211 private Node nodeConnectorNode;
213 // Helper field for JAXB
214 private String nodeConnectorIDString;
217 * Private constructor used for JAXB mapping
219 private NodeConnector() {
220 this.nodeConnectorIDString = null;
221 this.nodeConnectorID = null;
222 this.nodeConnectorType = null;
223 this.nodeConnectorNode = null;
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
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
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;
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());
258 * Copy constructor for NodeConnector
260 * @param src NodeConnector to copy from
263 public NodeConnector(NodeConnector src) throws ConstructionException {
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
270 this.nodeConnectorID = src.getID();
271 this.nodeConnectorNode = new Node(src.getNode());
274 new ConstructionException("Null incoming object to copy from");
279 * getter method for NodeConnector
282 * @return the NodeConnectorType of this object
284 @XmlElement(name = "type")
285 public String getType() {
286 return this.nodeConnectorType;
290 * fill the current object from the string parameters passed, will
291 * be only used by JAXB
293 * @param typeStr string representing the type of the Node
294 * @param IDStr String representation of the ID
296 private void fillmeFromString(String typeStr, String IDStr) {
297 if (typeStr == null) {
305 this.nodeConnectorType = typeStr;
306 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
307 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
308 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
310 Short ID = Short.parseShort(IDStr);
311 this.nodeConnectorID = ID;
312 } catch (Exception ex) {
315 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
316 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
317 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
318 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
320 this.nodeConnectorID = IDStr;
321 } catch (Exception ex) {
324 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
325 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
326 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
328 Integer ID = Integer.parseInt(IDStr);
329 this.nodeConnectorID = ID;
330 } catch (Exception ex) {
334 // Lookup via OSGi service registry
339 * Private setter for nodeConnectorType to be called by JAXB not by anyone
340 * else, NodeConnector is immutable
342 * @param type of node to be set
344 @SuppressWarnings("unused")
345 private void setType(String type) {
346 this.nodeConnectorType = type;
347 if (this.nodeConnectorIDString != null) {
348 this.fillmeFromString(type, this.nodeConnectorIDString);
353 * getter method for NodeConnector
356 * @return the NodeConnector ID of this object
358 public Object getID() {
359 return this.nodeConnectorID;
363 * getter method for NodeConnector ID in string format.
366 * @return the NodeConnector ID of this object in String format
368 @XmlElement(name = "id")
369 public String getNodeConnectorIDString() {
370 return this.nodeConnectorID.toString();
374 * private setter to be used by JAXB
376 * @param nodeConnectorIDString String representation for NodeConnectorID
378 @SuppressWarnings("unused")
379 private void setNodeConnectorIDString(String IDStr) {
380 this.nodeConnectorIDString = IDStr;
381 if (this.nodeConnectorType != null) {
382 this.fillmeFromString(this.nodeConnectorType, IDStr);
387 * getter method for NodeConnector
390 * @return the Node of this object
392 public Node getNode() {
393 return this.nodeConnectorNode;
397 public int hashCode() {
398 final int prime = 31;
400 result = prime * result
401 + ((nodeConnectorID == null) ? 0 : nodeConnectorID.hashCode());
404 + ((nodeConnectorNode == null) ? 0 : nodeConnectorNode
408 + ((nodeConnectorType == null) ? 0 : nodeConnectorType
414 public boolean equals(Object obj) {
421 if (getClass() != obj.getClass()) {
424 NodeConnector other = (NodeConnector) obj;
425 if (nodeConnectorID == null) {
426 if (other.nodeConnectorID != null) {
429 } else if (!nodeConnectorID.equals(other.nodeConnectorID)) {
432 if (nodeConnectorNode == null) {
433 if (other.nodeConnectorNode != null) {
436 } else if (!nodeConnectorNode.equals(other.nodeConnectorNode)) {
439 if (nodeConnectorType == null) {
440 if (other.nodeConnectorType != null) {
443 } else if (!nodeConnectorType.equals(other.nodeConnectorType)) {
450 public String toString() {
451 return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
455 * A String representation of the NodeConnector without
458 * @return A String representation of the NodeConnector without
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;
472 return this.nodeConnectorType + "|"
473 + this.nodeConnectorID.toString();
478 * return a NodeConnector from a string
480 * @param str String to be parsed in a NodeConnector
482 * @return the NodeConnector if parse is successful, null otherwise
484 public static NodeConnector fromString(String str) {
488 String parts[] = str.split("\\@");
489 if (parts.length != 2) {
492 // Now get the Node from the Node portion
493 Node n = Node.fromString(parts[1]);
497 return fromStringNoNode(parts[0], n);
501 * return a set of NodeConnector from a collection of string
503 * @param stringCollection Collection of String object to be parsed as a NodeConnector
505 * @return the Set of unique NodeConnector objects if parse is successful, empty Set otherwise
507 public static Set<NodeConnector> fromString(Collection<String> stringCollection) {
508 Set<NodeConnector> set = new HashSet<NodeConnector>();
509 if (stringCollection != null) {
511 for (String str : stringCollection) {
512 NodeConnector nodeConnector = NodeConnector.fromString(str);
513 if (nodeConnector != null) {
514 set.add(nodeConnector);
522 * return a NodeConnector from a string not containing explicitly
523 * the Node portion which has to be supplied as parameter
525 * @param str String to be parsed in a NodeConnector
526 * @param n Node to which the NodeConnector is attached
528 * @return the NodeConnector if parse is successful, null otherwise
530 public static NodeConnector fromStringNoNode(String str, Node n) {
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();
541 Short ofPortID = null;
542 // Try as an decimal/hex number
544 ofPortID = Short.decode(numStr);
545 } catch (Exception ex) {
549 // Lets try the special ports we know about
550 if (ofPortID == null) {
552 if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
554 return new NodeConnector(
555 NodeConnectorIDType.CONTROLLER,
556 SPECIALNODECONNECTORID, n);
558 if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
560 return new NodeConnector(NodeConnectorIDType.HWPATH,
561 SPECIALNODECONNECTORID, n);
563 if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
565 return new NodeConnector(NodeConnectorIDType.SWSTACK,
566 SPECIALNODECONNECTORID, n);
569 .equalsIgnoreCase(NodeConnectorIDType.ALL
571 return new NodeConnector(NodeConnectorIDType.ALL,
572 SPECIALNODECONNECTORID, n);
574 } catch (ConstructionException ex) {
580 // Lets return the cooked up NodeID
582 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
584 } catch (ConstructionException ex) {
589 String typeStr = nodeConnectorParts[0];
590 String IDStr = nodeConnectorParts[1];
591 return fromStringNoNode(typeStr, IDStr, n);
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
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
603 * @return the NodeConnector if parse is successful, null otherwise
605 public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
607 if (typeStr == null) {
614 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
615 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
616 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
618 Short ID = Short.parseShort(IDStr);
619 return new NodeConnector(typeStr, ID, n);
620 } catch (Exception ex) {
623 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
624 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
625 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
626 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
628 return new NodeConnector(typeStr, IDStr, n);
629 } catch (Exception ex) {
632 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
633 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
634 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
636 Integer ID = Integer.parseInt(IDStr);
637 return new NodeConnector(typeStr, ID, n);
638 } catch (Exception ex) {
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+")");
649 return f.fromStringNoNode(typeStr, IDStr, n);