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.concurrent.ConcurrentHashMap;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlAttribute;
27 import javax.xml.bind.annotation.XmlElement;
28 import javax.xml.bind.annotation.XmlRootElement;
30 import org.apache.commons.lang3.tuple.ImmutablePair;
31 import org.opendaylight.controller.sal.utils.INodeConnectorFactory;
32 import org.opendaylight.controller.sal.utils.INodeFactory;
33 import org.opendaylight.controller.sal.utils.ServiceHelper;
36 * Describe a generic network element attachment points,
37 * attached to one Node, the NodeConnector is formed by the pair
38 * (NodeConnectorType, NodeConnectorID) because each SDN technology can
39 * identify an attachment point on the Node in different way.
43 @XmlAccessorType(XmlAccessType.NONE)
44 public class NodeConnector implements Serializable {
45 private static final long serialVersionUID = 1L;
46 public static final Short SPECIALNODECONNECTORID = (short) 0;
49 * Enumerate the different types of NodeConnectors supported by the class
52 public static class NodeConnectorIDType {
54 ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>> compatibleType =
55 new ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>>();
57 * Represents the OFPP_CONTROLLER reserved port to forward a
58 * packet to the controller, this is to send data packets
59 * to the controller from the data plane triggering
62 public static String CONTROLLER = "CTRL";
64 * Represents the OFPP_ALL reserved OF port
65 * to forward to ALL the ports in the system ,
66 * should be used for flooding like mechanism to
67 * be used cautiously to avoid excessive flooding.
69 public static String ALL = "ALL";
71 * Represents the OFPP_LOCAL reserved OF port
72 * to access the local networking stack of the node
73 * of which the packet is destined. Typically used for
74 * inband OF communications channel.
76 public static String SWSTACK = "SW";
78 * Describes OFPP_Normal reserved port destination that invokes
79 * the traditional native L2/L3 HW normal forwarding functionality
80 * if supported on the forwarding element.
82 public static String HWPATH = "HW";
83 public static String OPENFLOW = "OF";
84 public static String PCEP = "PE";
85 public static String ONEPK = "PK";
86 public static String OPENFLOW2PCEP = "O2E";
87 public static String PCEP2OPENFLOW = "E2O";
88 public static String OPENFLOW2ONEPK = "O2K";
89 public static String ONEPK2OPENFLOW = "K2O";
90 public static String PCEP2ONEPK = "E2K";
91 public static String ONEPK2PCEP = "K2E";
92 public static String PRODUCTION = "PR";
94 // Initialize the map with some well known, even though all of
95 // them could be siting outside of here, but it's convenient
96 // for Unit Testing coverage
98 compatibleType.put(CONTROLLER,
99 new ImmutablePair(Short.class, null));
100 compatibleType.put(ALL,
101 new ImmutablePair(Short.class, null));
102 compatibleType.put(SWSTACK,
103 new ImmutablePair(Short.class, null));
104 compatibleType.put(HWPATH,
105 new ImmutablePair(Short.class, null));
106 compatibleType.put(OPENFLOW,
107 new ImmutablePair(Short.class,
108 Node.NodeIDType.OPENFLOW));
109 compatibleType.put(PCEP,
110 new ImmutablePair(Integer.class,
111 Node.NodeIDType.PCEP));
112 compatibleType.put(ONEPK,
113 new ImmutablePair(String.class,
114 Node.NodeIDType.ONEPK));
115 compatibleType.put(OPENFLOW2PCEP,
116 new ImmutablePair(Short.class,
117 Node.NodeIDType.OPENFLOW));
118 compatibleType.put(OPENFLOW2ONEPK,
119 new ImmutablePair(Short.class,
120 Node.NodeIDType.OPENFLOW));
121 compatibleType.put(PCEP2OPENFLOW,
122 new ImmutablePair(Integer.class,
123 Node.NodeIDType.PCEP));
124 compatibleType.put(PCEP2ONEPK,
125 new ImmutablePair(Integer.class,
126 Node.NodeIDType.PCEP));
127 compatibleType.put(ONEPK2OPENFLOW,
128 new ImmutablePair(String.class,
129 Node.NodeIDType.ONEPK));
130 compatibleType.put(ONEPK2PCEP,
131 new ImmutablePair(String.class,
132 Node.NodeIDType.ONEPK));
133 compatibleType.put(PRODUCTION,
134 new ImmutablePair(String.class,
135 Node.NodeIDType.PRODUCTION));
139 * Return the type of the class expected for the
140 * NodeConnectorID, it's used for validity check in the constructor
142 * @param type, the type of the NodeConnector for which we
143 * want to retrieve the compatible class to be used as ID.
145 * @return The Class which is supposed to instantiate the ID
146 * for the NodeConnectorID
148 public static Class<?> getClassType(String type) {
149 if (compatibleType.get(type) == null) {
152 return compatibleType.get(type).getLeft();
156 * Return the NodeIDType compatible with this NodeConnector,
157 * in fact you cannot attach for example a PCEP NodeConnector
158 * to an OpenFlow Node.
160 * @param type, the type of the NodeConnector for which we
161 * want to retrieve the compatible class to be used as ID.
163 * @return The ID of the compatible Node
165 public static String getCompatibleNode(String type) {
166 if (compatibleType.get(type) == null) {
169 return compatibleType.get(type).getRight();
173 * Register a new ID for which Node can be created
175 * @param type, the new type being registered
176 * @param compatibleID, the type of class to be accepted as ID
177 * @param compatibleNode, the type of Node with which this
178 * NodeConnector is compatible
180 * @return true if registered, false otherwise
182 public static boolean registerIDType(String type,
183 Class<? extends Object> compatibleID,
184 String compatibleNode) {
185 if (compatibleType.get(type) != null) {
188 compatibleType.put(type, new ImmutablePair(compatibleID,
195 * UNRegister a new ID for which Node can be created
197 * @param type, the type being UN-registered
200 public static void unRegisterIDType(String type) {
201 compatibleType.remove(type);
205 // Elements that constitute the NodeConnector
206 private Object nodeConnectorID;
207 private String nodeConnectorType;
208 @XmlElement(name = "node")
209 private Node nodeConnectorNode;
211 // Helper field for JAXB
212 private String nodeConnectorIDString;
215 * Private constructor used for JAXB mapping
217 private NodeConnector() {
218 this.nodeConnectorIDString = null;
219 this.nodeConnectorID = null;
220 this.nodeConnectorType = null;
221 this.nodeConnectorNode = null;
225 * Create a NodeConnector from the component element. The
226 * constructor make sure the NodeConnector type is congruent with
227 * the Node used and also the NodeConnector ID is of type expected
229 * @param nodeConnectorType Type of the NodeConnector
230 * @param id ID portion of the NodeConnector
231 * @param node Node to which the NodeConnector is attached too
234 public NodeConnector(String nodeConnectorType, Object id,
235 Node node) throws ConstructionException {
236 // In case of compatible type being null then assume that this
237 // port can be attached on any node.
238 String compatibleNode =
239 NodeConnectorIDType.getCompatibleNode(nodeConnectorType);
240 if (NodeConnectorIDType.getClassType(nodeConnectorType) != null &&
241 NodeConnectorIDType.getClassType(nodeConnectorType).isInstance(id) &&
242 (compatibleNode == null ||
243 node.getType().equals(compatibleNode))) {
244 this.nodeConnectorType = nodeConnectorType;
245 this.nodeConnectorID = id;
246 this.nodeConnectorNode = node;
248 throw new ConstructionException("Type of incoming object:"
249 + id.getClass() + " not compatible with expected type:"
250 + NodeConnectorIDType.getClassType(nodeConnectorType)
251 + " or Node type incompatible:" + node.getType());
256 * Copy constructor for NodeConnector
258 * @param src NodeConnector to copy from
261 public NodeConnector(NodeConnector src) throws ConstructionException {
263 this.nodeConnectorType = src.getType();
264 // Here we can reference the object because that is
265 // supposed to be an immutable identifier as well like a
266 // UUID/Integer and so on, hence no need to create a copy
268 this.nodeConnectorID = src.getID();
269 this.nodeConnectorNode = new Node(src.getNode());
272 new ConstructionException("Null incoming object to copy from");
277 * getter method for NodeConnector
280 * @return the NodeConnectorType of this object
282 @XmlAttribute(name = "type")
283 public String getType() {
284 return this.nodeConnectorType;
288 * fill the current object from the string parameters passed, will
289 * be only used by JAXB
291 * @param typeStr string representing the type of the Node
292 * @param IDStr String representation of the ID
294 private void fillmeFromString(String typeStr, String IDStr) {
295 if (typeStr == null) {
303 this.nodeConnectorType = typeStr;
304 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
305 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
306 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
308 Short ID = Short.parseShort(IDStr);
309 this.nodeConnectorID = ID;
310 } catch (Exception ex) {
313 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
314 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
315 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
316 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
318 this.nodeConnectorID = IDStr;
319 } catch (Exception ex) {
322 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
323 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
324 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
326 Integer ID = Integer.parseInt(IDStr);
327 this.nodeConnectorID = ID;
328 } catch (Exception ex) {
332 // Lookup via OSGi service registry
337 * Private setter for nodeConnectorType to be called by JAXB not by anyone
338 * else, NodeConnector is immutable
340 * @param type of node to be set
342 private void setType(String type) {
343 this.nodeConnectorType = type;
344 if (this.nodeConnectorIDString != null) {
345 this.fillmeFromString(type, this.nodeConnectorIDString);
350 * getter method for NodeConnector
353 * @return the NodeConnector ID of this object
355 public Object getID() {
356 return this.nodeConnectorID;
360 * getter method for NodeConnector ID in string format.
363 * @return the NodeConnector ID of this object in String format
365 @XmlAttribute(name = "id")
366 public String getNodeConnectorIDString() {
367 return this.nodeConnectorID.toString();
371 * private setter to be used by JAXB
373 * @param nodeConnectorIDString String representation for NodeConnectorID
375 private void setNodeConnectorIDString(String IDStr) {
376 this.nodeConnectorIDString = IDStr;
377 if (this.nodeConnectorType != null) {
378 this.fillmeFromString(this.nodeConnectorType, IDStr);
383 * getter method for NodeConnector
386 * @return the Node of this object
388 public Node getNode() {
389 return this.nodeConnectorNode;
393 public int hashCode() {
394 final int prime = 31;
396 result = prime * result
397 + ((nodeConnectorID == null) ? 0 : nodeConnectorID.hashCode());
400 + ((nodeConnectorNode == null) ? 0 : nodeConnectorNode
404 + ((nodeConnectorType == null) ? 0 : nodeConnectorType
410 public boolean equals(Object obj) {
415 if (getClass() != obj.getClass())
417 NodeConnector other = (NodeConnector) obj;
418 if (nodeConnectorID == null) {
419 if (other.nodeConnectorID != null)
421 } else if (!nodeConnectorID.equals(other.nodeConnectorID))
423 if (nodeConnectorNode == null) {
424 if (other.nodeConnectorNode != null)
426 } else if (!nodeConnectorNode.equals(other.nodeConnectorNode))
428 if (nodeConnectorType == null) {
429 if (other.nodeConnectorType != null)
431 } else if (!nodeConnectorType.equals(other.nodeConnectorType))
437 public String toString() {
438 return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
442 * A String representation of the NodeConnector without
445 * @return A String representation of the NodeConnector without
448 public String getNodeConnectorIdAsString() {
449 if (this.nodeConnectorType
450 .equals(NodeConnectorIDType.CONTROLLER) ||
451 this.nodeConnectorType
452 .equals(NodeConnectorIDType.ALL) ||
453 this.nodeConnectorType
454 .equals(NodeConnectorIDType.SWSTACK) ||
455 this.nodeConnectorType
456 .equals(NodeConnectorIDType.HWPATH)) {
457 return this.nodeConnectorType.toString();
459 return this.nodeConnectorType.toString() + "|"
460 + this.nodeConnectorID.toString();
465 * return a NodeConnector from a string
467 * @param str String to be parsed in a NodeConnector
469 * @return the NodeConnector if parse is successful, null otherwise
471 public static NodeConnector fromString(String str) {
475 String parts[] = str.split("\\@");
476 if (parts.length != 2) {
479 // Now get the Node from the Node portion
480 Node n = Node.fromString(parts[1]);
484 return fromStringNoNode(parts[0], n);
488 * return a NodeConnector from a string not containing explicitly
489 * the Node portion which has to be supplied as parameter
491 * @param str String to be parsed in a NodeConnector
492 * @param n Node to which the NodeConnector is attached
494 * @return the NodeConnector if parse is successful, null otherwise
496 public static NodeConnector fromStringNoNode(String str, Node n) {
500 String nodeConnectorParts[] = str.split("\\|");
501 if (nodeConnectorParts.length != 2) {
502 // Try to guess from a String formatted as a short because
503 // for long time openflow has been prime citizen so lets
504 // keep this legacy for now
505 String numStr = str.toUpperCase();
507 Short ofPortID = null;
508 // Try as an decimal/hex number
510 ofPortID = Short.decode(numStr);
511 } catch (Exception ex) {
515 // Lets try the special ports we know about
516 if (ofPortID == null) {
518 if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
520 return new NodeConnector(
521 NodeConnectorIDType.CONTROLLER,
522 SPECIALNODECONNECTORID, n);
524 if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
526 return new NodeConnector(NodeConnectorIDType.HWPATH,
527 SPECIALNODECONNECTORID, n);
529 if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
531 return new NodeConnector(NodeConnectorIDType.SWSTACK,
532 SPECIALNODECONNECTORID, n);
535 .equalsIgnoreCase(NodeConnectorIDType.ALL
537 return new NodeConnector(NodeConnectorIDType.ALL,
538 SPECIALNODECONNECTORID, n);
540 } catch (ConstructionException ex) {
546 // Lets return the cooked up NodeID
548 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
550 } catch (ConstructionException ex) {
555 String typeStr = nodeConnectorParts[0];
556 String IDStr = nodeConnectorParts[1];
557 return fromStringNoNode(typeStr, IDStr, n);
561 * return a NodeConnector from a pair (type, ID) in string format
562 * not containing explicitly the Node portion which has to be
563 * supplied as parameter
565 * @param typeStr type String to be parsed in a NodeConnector
566 * @param IDStr ID String portion to be parsed in a NodeConnector
567 * @param n Node to which the NodeConnector is attached
569 * @return the NodeConnector if parse is successful, null otherwise
571 public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
573 if (typeStr == null) {
580 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
581 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
582 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
584 Short ID = Short.parseShort(IDStr);
585 return new NodeConnector(typeStr, ID, n);
586 } catch (Exception ex) {
589 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
590 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
591 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
592 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
594 return new NodeConnector(typeStr, IDStr, n);
595 } catch (Exception ex) {
598 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
599 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
600 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
602 Integer ID = Integer.parseInt(IDStr);
603 return new NodeConnector(typeStr, ID, n);
604 } catch (Exception ex) {
608 //Use INodeConnectorFactory to create a NodeConnector of registered type.
609 //The protocol plugin being used depends on typeStr.
610 INodeConnectorFactory f = (INodeConnectorFactory) ServiceHelper
611 .getGlobalInstance(INodeConnectorFactory.class, new NodeConnector(), "(protocolName="+typeStr+")");
614 return f.fromStringNoNode(typeStr, IDStr, n);