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)
45 public class NodeConnector implements Serializable {
46 private static final long serialVersionUID = 1L;
47 public static final Short SPECIALNODECONNECTORID = (short) 0;
50 * Enumerate the different types of NodeConnectors supported by the class
53 public static class NodeConnectorIDType {
55 ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>> compatibleType =
56 new ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>>();
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
63 public static String CONTROLLER = "CTRL";
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.
70 public static String ALL = "ALL";
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.
77 public static String SWSTACK = "SW";
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.
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";
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
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));
140 * Return the type of the class expected for the
141 * NodeConnectorID, it's used for validity check in the constructor
143 * @param type, the type of the NodeConnector for which we
144 * want to retrieve the compatible class to be used as ID.
146 * @return The Class which is supposed to instantiate the ID
147 * for the NodeConnectorID
149 public static Class<?> getClassType(String type) {
150 if (compatibleType.get(type) == null) {
153 return compatibleType.get(type).getLeft();
157 * Return the NodeIDType compatible with this NodeConnector,
158 * in fact you cannot attach for example a PCEP NodeConnector
159 * to an OpenFlow Node.
161 * @param type, the type of the NodeConnector for which we
162 * want to retrieve the compatible class to be used as ID.
164 * @return The ID of the compatible Node
166 public static String getCompatibleNode(String type) {
167 if (compatibleType.get(type) == null) {
170 return compatibleType.get(type).getRight();
174 * Register a new ID for which Node can be created
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
181 * @return true if registered, false otherwise
183 public static boolean registerIDType(String type,
184 Class<? extends Object> compatibleID,
185 String compatibleNode) {
186 if (compatibleType.get(type) != null) {
189 compatibleType.put(type, new ImmutablePair<Class<? extends Object>, String>(compatibleID,
196 * UNRegister a new ID for which Node can be created
198 * @param type, the type being UN-registered
201 public static void unRegisterIDType(String type) {
202 compatibleType.remove(type);
206 // Elements that constitute the NodeConnector
207 private Object nodeConnectorID;
208 private String nodeConnectorType;
209 @XmlElement(name = "node")
210 private Node nodeConnectorNode;
212 // Helper field for JAXB
213 private String nodeConnectorIDString;
216 * Private constructor used for JAXB mapping
218 private NodeConnector() {
219 this.nodeConnectorIDString = null;
220 this.nodeConnectorID = null;
221 this.nodeConnectorType = null;
222 this.nodeConnectorNode = null;
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
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
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;
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());
257 * Copy constructor for NodeConnector
259 * @param src NodeConnector to copy from
262 public NodeConnector(NodeConnector src) throws ConstructionException {
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
269 this.nodeConnectorID = src.getID();
270 this.nodeConnectorNode = new Node(src.getNode());
273 new ConstructionException("Null incoming object to copy from");
278 * getter method for NodeConnector
281 * @return the NodeConnectorType of this object
283 @XmlElement(name = "type")
284 public String getType() {
285 return this.nodeConnectorType;
289 * fill the current object from the string parameters passed, will
290 * be only used by JAXB
292 * @param typeStr string representing the type of the Node
293 * @param IDStr String representation of the ID
295 private void fillmeFromString(String typeStr, String IDStr) {
296 if (typeStr == null) {
304 this.nodeConnectorType = typeStr;
305 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
306 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
307 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
309 Short ID = Short.parseShort(IDStr);
310 this.nodeConnectorID = ID;
311 } catch (Exception ex) {
314 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
315 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
316 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
317 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
319 this.nodeConnectorID = IDStr;
320 } catch (Exception ex) {
323 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
324 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
325 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
327 Integer ID = Integer.parseInt(IDStr);
328 this.nodeConnectorID = ID;
329 } catch (Exception ex) {
333 // Lookup via OSGi service registry
338 * Private setter for nodeConnectorType to be called by JAXB not by anyone
339 * else, NodeConnector is immutable
341 * @param type of node to be set
343 @SuppressWarnings("unused")
344 private void setType(String type) {
345 this.nodeConnectorType = type;
346 if (this.nodeConnectorIDString != null) {
347 this.fillmeFromString(type, this.nodeConnectorIDString);
352 * getter method for NodeConnector
355 * @return the NodeConnector ID of this object
357 public Object getID() {
358 return this.nodeConnectorID;
362 * getter method for NodeConnector ID in string format.
365 * @return the NodeConnector ID of this object in String format
367 @XmlElement(name = "id")
368 public String getNodeConnectorIDString() {
369 return this.nodeConnectorID.toString();
373 * private setter to be used by JAXB
375 * @param nodeConnectorIDString String representation for NodeConnectorID
377 @SuppressWarnings("unused")
378 private void setNodeConnectorIDString(String IDStr) {
379 this.nodeConnectorIDString = IDStr;
380 if (this.nodeConnectorType != null) {
381 this.fillmeFromString(this.nodeConnectorType, IDStr);
386 * getter method for NodeConnector
389 * @return the Node of this object
391 public Node getNode() {
392 return this.nodeConnectorNode;
396 public int hashCode() {
397 final int prime = 31;
399 result = prime * result
400 + ((nodeConnectorID == null) ? 0 : nodeConnectorID.hashCode());
403 + ((nodeConnectorNode == null) ? 0 : nodeConnectorNode
407 + ((nodeConnectorType == null) ? 0 : nodeConnectorType
413 public boolean equals(Object obj) {
420 if (getClass() != obj.getClass()) {
423 NodeConnector other = (NodeConnector) obj;
424 if (nodeConnectorID == null) {
425 if (other.nodeConnectorID != null) {
428 } else if (!nodeConnectorID.equals(other.nodeConnectorID)) {
431 if (nodeConnectorNode == null) {
432 if (other.nodeConnectorNode != null) {
435 } else if (!nodeConnectorNode.equals(other.nodeConnectorNode)) {
438 if (nodeConnectorType == null) {
439 if (other.nodeConnectorType != null) {
442 } else if (!nodeConnectorType.equals(other.nodeConnectorType)) {
449 public String toString() {
450 return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
454 * A String representation of the NodeConnector without
457 * @return A String representation of the NodeConnector without
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;
471 return this.nodeConnectorType + "|"
472 + this.nodeConnectorID.toString();
477 * return a NodeConnector from a string
479 * @param str String to be parsed in a NodeConnector
481 * @return the NodeConnector if parse is successful, null otherwise
483 public static NodeConnector fromString(String str) {
487 String parts[] = str.split("\\@");
488 if (parts.length != 2) {
491 // Now get the Node from the Node portion
492 Node n = Node.fromString(parts[1]);
496 return fromStringNoNode(parts[0], n);
500 * return a set of NodeConnector from a collection of string
502 * @param stringCollection Collection of String object to be parsed as a NodeConnector
504 * @return the Set of unique NodeConnector objects if parse is successful, empty Set otherwise
506 public static Set<NodeConnector> fromString(Collection<String> stringCollection) {
507 Set<NodeConnector> set = new HashSet<NodeConnector>();
508 if (stringCollection != null) {
510 for (String str : stringCollection) {
511 NodeConnector nodeConnector = NodeConnector.fromString(str);
512 if (nodeConnector != null) {
513 set.add(nodeConnector);
521 * return a NodeConnector from a string not containing explicitly
522 * the Node portion which has to be supplied as parameter
524 * @param str String to be parsed in a NodeConnector
525 * @param n Node to which the NodeConnector is attached
527 * @return the NodeConnector if parse is successful, null otherwise
529 public static NodeConnector fromStringNoNode(String str, Node n) {
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();
540 Short ofPortID = null;
541 // Try as an decimal/hex number
543 ofPortID = Short.decode(numStr);
544 } catch (Exception ex) {
548 // Lets try the special ports we know about
549 if (ofPortID == null) {
551 if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
553 return new NodeConnector(
554 NodeConnectorIDType.CONTROLLER,
555 SPECIALNODECONNECTORID, n);
557 if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
559 return new NodeConnector(NodeConnectorIDType.HWPATH,
560 SPECIALNODECONNECTORID, n);
562 if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
564 return new NodeConnector(NodeConnectorIDType.SWSTACK,
565 SPECIALNODECONNECTORID, n);
568 .equalsIgnoreCase(NodeConnectorIDType.ALL
570 return new NodeConnector(NodeConnectorIDType.ALL,
571 SPECIALNODECONNECTORID, n);
573 } catch (ConstructionException ex) {
579 // Lets return the cooked up NodeID
581 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
583 } catch (ConstructionException ex) {
588 String typeStr = nodeConnectorParts[0];
589 String IDStr = nodeConnectorParts[1];
590 return fromStringNoNode(typeStr, IDStr, n);
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
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
602 * @return the NodeConnector if parse is successful, null otherwise
604 public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
606 if (typeStr == null) {
613 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
614 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
615 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
617 Short ID = Short.parseShort(IDStr);
618 return new NodeConnector(typeStr, ID, n);
619 } catch (Exception ex) {
622 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
623 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
624 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
625 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
627 return new NodeConnector(typeStr, IDStr, n);
628 } catch (Exception ex) {
631 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
632 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
633 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
635 Integer ID = Integer.parseInt(IDStr);
636 return new NodeConnector(typeStr, ID, n);
637 } catch (Exception ex) {
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+")");
648 return f.fromStringNoNode(typeStr, IDStr, n);