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.builder.EqualsBuilder;
31 import org.apache.commons.lang3.builder.HashCodeBuilder;
32 import org.apache.commons.lang3.tuple.ImmutablePair;
35 * Describe a generic network element attachment points,
36 * attached to one Node, the NodeConnector is formed by the pair
37 * (NodeConnectorType, NodeConnectorID) because each SDN technology can
38 * identify an attachment point on the Node in different way.
42 @XmlAccessorType(XmlAccessType.NONE)
43 public class NodeConnector implements Serializable {
44 private static final long serialVersionUID = 1L;
45 public static final Short SPECIALNODECONNECTORID = (short) 0;
48 * Enumerate the different types of NodeConnectors supported by the class
51 public static class NodeConnectorIDType {
53 ConcurrentHashMap<String, ImmutablePair<Class, String>> compatibleType =
54 new ConcurrentHashMap<String, ImmutablePair<Class, String>>();
56 * Represent a special port pointing toward the controller,
57 * this is to send data packets toward the controller from
60 public static String CONTROLLER = "CTRL";
62 * Special port describing ALL the ports in the system,
63 * should be used for flooding like mechanism but better
64 * to be careful with it
66 public static String ALL = "ALL";
68 * Describe the local networking stack of the node
69 * on which the packet is destined. Yet another special port
71 public static String SWSTACK = "SW";
73 * Describe a special destination that invoke the
74 * traditional HW forwarding on platforms that has this
77 public static String HWPATH = "HW";
78 public static String OPENFLOW = "OF";
79 public static String PCEP = "PE";
80 public static String ONEPK = "PK";
81 public static String OPENFLOW2PCEP = "O2E";
82 public static String PCEP2OPENFLOW = "E2O";
83 public static String OPENFLOW2ONEPK = "O2K";
84 public static String ONEPK2OPENFLOW = "K2O";
85 public static String PCEP2ONEPK = "E2K";
86 public static String ONEPK2PCEP = "K2E";
87 public static String PRODUCTION = "PR";
89 // Initialize the map with some well known, even though all of
90 // them could be siting outside of here, but it's convenient
91 // for Unit Testing coverage
93 compatibleType.put(CONTROLLER,
94 new ImmutablePair(Short.class, null));
95 compatibleType.put(ALL,
96 new ImmutablePair(Short.class, null));
97 compatibleType.put(SWSTACK,
98 new ImmutablePair(Short.class, null));
99 compatibleType.put(HWPATH,
100 new ImmutablePair(Short.class, null));
101 compatibleType.put(OPENFLOW,
102 new ImmutablePair(Short.class,
103 Node.NodeIDType.OPENFLOW));
104 compatibleType.put(PCEP,
105 new ImmutablePair(Integer.class,
106 Node.NodeIDType.PCEP));
107 compatibleType.put(ONEPK,
108 new ImmutablePair(String.class,
109 Node.NodeIDType.ONEPK));
110 compatibleType.put(OPENFLOW2PCEP,
111 new ImmutablePair(Short.class,
112 Node.NodeIDType.OPENFLOW));
113 compatibleType.put(OPENFLOW2ONEPK,
114 new ImmutablePair(Short.class,
115 Node.NodeIDType.OPENFLOW));
116 compatibleType.put(PCEP2OPENFLOW,
117 new ImmutablePair(Integer.class,
118 Node.NodeIDType.PCEP));
119 compatibleType.put(PCEP2ONEPK,
120 new ImmutablePair(Integer.class,
121 Node.NodeIDType.PCEP));
122 compatibleType.put(ONEPK2OPENFLOW,
123 new ImmutablePair(String.class,
124 Node.NodeIDType.ONEPK));
125 compatibleType.put(ONEPK2PCEP,
126 new ImmutablePair(String.class,
127 Node.NodeIDType.ONEPK));
128 compatibleType.put(PRODUCTION,
129 new ImmutablePair(String.class,
130 Node.NodeIDType.PRODUCTION));
134 * Return the type of the class expected for the
135 * NodeConnectorID, it's used for validity check in the constructor
137 * @param type, the type of the NodeConnector for which we
138 * want to retrieve the compatible class to be used as ID.
140 * @return The Class which is supposed to instantiate the ID
141 * for the NodeConnectorID
143 public static Class<?> getClassType(String type) {
144 if (compatibleType.get(type) == null) {
147 return compatibleType.get(type).getLeft();
151 * Return the NodeIDType compatible with this NodeConnector,
152 * in fact you cannot attach for example a PCEP NodeConnector
153 * to an OpenFlow Node.
155 * @param type, the type of the NodeConnector for which we
156 * want to retrieve the compatible class to be used as ID.
158 * @return The ID of the compatible Node
160 public static String getCompatibleNode(String type) {
161 if (compatibleType.get(type) == null) {
164 return compatibleType.get(type).getRight();
168 * Register a new ID for which Node can be created
170 * @param type, the new type being registered
171 * @param compatibleID, the type of class to be accepted as ID
172 * @param compatibleNode, the type of Node with which this
173 * NodeConnector is compatible
175 * @return true if registered, false otherwise
177 public static boolean registerIDType(String type,
179 String compatibleNode) {
180 if (compatibleType.get(type) != null) {
183 compatibleType.put(type, new ImmutablePair(compatibleID,
190 * UNRegister a new ID for which Node can be created
192 * @param type, the type being UN-registered
195 public static void unRegisterIDType(String type) {
196 compatibleType.remove(type);
200 // Elements that constitute the NodeConnector
201 private Object nodeConnectorID;
202 private String nodeConnectorType;
203 @XmlElement(name = "node")
204 private Node nodeConnectorNode;
206 // Helper field for JAXB
207 private String nodeConnectorIDString;
210 * Private constructor used for JAXB mapping
212 private NodeConnector() {
213 this.nodeConnectorIDString = null;
214 this.nodeConnectorID = null;
215 this.nodeConnectorType = null;
216 this.nodeConnectorNode = null;
220 * Create a NodeConnector from the component element. The
221 * constructor make sure the NodeConnector type is congruent with
222 * the Node used and also the NodeConnector ID is of type expected
224 * @param nodeConnectorType Type of the NodeConnector
225 * @param id ID portion of the NodeConnector
226 * @param node Node to which the NodeConnector is attached too
229 public NodeConnector(String nodeConnectorType, Object id,
230 Node node) throws ConstructionException {
231 // In case of compatible type being null then assume that this
232 // port can be attached on any node.
233 String compatibleNode =
234 NodeConnectorIDType.getCompatibleNode(nodeConnectorType);
235 if (NodeConnectorIDType.getClassType(nodeConnectorType) != null &&
236 NodeConnectorIDType.getClassType(nodeConnectorType).isInstance(id) &&
237 (compatibleNode == null ||
238 node.getType().equals(compatibleNode))) {
239 this.nodeConnectorType = nodeConnectorType;
240 this.nodeConnectorID = id;
241 this.nodeConnectorNode = node;
243 throw new ConstructionException("Type of incoming object:"
244 + id.getClass() + " not compatible with expected type:"
245 + NodeConnectorIDType.getClassType(nodeConnectorType)
246 + " or Node type incompatible:" + node.getType());
251 * Copy constructor for NodeConnector
253 * @param src NodeConnector to copy from
256 public NodeConnector(NodeConnector src) throws ConstructionException {
258 this.nodeConnectorType = src.getType();
259 // Here we can reference the object because that is
260 // supposed to be an immutable identifier as well like a
261 // UUID/Integer and so on, hence no need to create a copy
263 this.nodeConnectorID = src.getID();
264 this.nodeConnectorNode = new Node(src.getNode());
267 new ConstructionException("Null incoming object to copy from");
272 * getter method for NodeConnector
275 * @return the NodeConnectorType of this object
277 @XmlAttribute(name = "type")
278 public String getType() {
279 return this.nodeConnectorType;
283 * fill the current object from the string parameters passed, will
284 * be only used by JAXB
286 * @param typeStr string representing the type of the Node
287 * @param IDStr String representation of the ID
289 private void fillmeFromString(String typeStr, String IDStr) {
290 if (typeStr == null) {
298 this.nodeConnectorType = typeStr;
299 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
300 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
301 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
303 Short ID = Short.parseShort(IDStr);
304 this.nodeConnectorID = ID;
305 } catch (Exception ex) {
308 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
309 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
310 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
311 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
313 this.nodeConnectorID = IDStr;
314 } catch (Exception ex) {
317 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
318 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
319 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
321 Integer ID = Integer.parseInt(IDStr);
322 this.nodeConnectorID = ID;
323 } catch (Exception ex) {
327 // Lookup via OSGi service registry
332 * Private setter for nodeConnectorType to be called by JAXB not by anyone
333 * else, NodeConnector is immutable
335 * @param type of node to be set
337 private void setType(String type) {
338 this.nodeConnectorType = type;
339 if (this.nodeConnectorIDString != null) {
340 this.fillmeFromString(type, this.nodeConnectorIDString);
345 * getter method for NodeConnector
348 * @return the NodeConnector ID of this object
350 public Object getID() {
351 return this.nodeConnectorID;
355 * getter method for NodeConnector ID in string format.
358 * @return the NodeConnector ID of this object in String format
360 @XmlAttribute(name = "id")
361 public String getNodeConnectorIDString() {
362 return this.nodeConnectorID.toString();
366 * private setter to be used by JAXB
368 * @param nodeConnectorIDString String representation for NodeConnectorID
370 private void setNodeConnectorIDString(String IDStr) {
371 this.nodeConnectorIDString = IDStr;
372 if (this.nodeConnectorType != null) {
373 this.fillmeFromString(this.nodeConnectorType, IDStr);
378 * getter method for NodeConnector
381 * @return the Node of this object
383 public Node getNode() {
384 return this.nodeConnectorNode;
388 public int hashCode() {
389 return new HashCodeBuilder(63389, 4951)
390 .append(nodeConnectorType)
391 .append(nodeConnectorID)
392 .append(nodeConnectorNode)
397 public boolean equals(Object obj) {
398 if (obj == null) { return false; }
399 if (obj == this) { return true; }
400 if (obj.getClass() != getClass()) {
403 NodeConnector rhs = (NodeConnector)obj;
404 return new EqualsBuilder()
405 .append(this.getType(), rhs.getType())
406 .append(this.getID(), rhs.getID())
407 .append(this.getNode(), rhs.getNode())
412 public String toString() {
413 return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
417 * A String representation of the NodeConnector without
420 * @return A String representation of the NodeConnector without
423 public String getNodeConnectorIdAsString() {
424 if (this.nodeConnectorType
425 .equals(NodeConnectorIDType.CONTROLLER) ||
426 this.nodeConnectorType
427 .equals(NodeConnectorIDType.ALL) ||
428 this.nodeConnectorType
429 .equals(NodeConnectorIDType.SWSTACK) ||
430 this.nodeConnectorType
431 .equals(NodeConnectorIDType.HWPATH)) {
432 return this.nodeConnectorType.toString();
434 return this.nodeConnectorType.toString() + "|"
435 + this.nodeConnectorID.toString();
440 * return a NodeConnector from a string
442 * @param str String to be parsed in a NodeConnector
444 * @return the NodeConnector if parse is succesfull, null otherwise
446 public static NodeConnector fromString(String str) {
450 String parts[] = str.split("\\@");
451 if (parts.length != 2) {
454 // Now get the Node from the Node portion
455 Node n = Node.fromString(parts[1]);
459 return fromStringNoNode(parts[0], n);
463 * return a NodeConnector from a string not containing explicitly
464 * the Node portion which has to be supplied as parameter
466 * @param str String to be parsed in a NodeConnector
467 * @param n Node to which the NodeConnector is attached
469 * @return the NodeConnector if parse is successful, null otherwise
471 public static NodeConnector fromStringNoNode(String str, Node n) {
475 String nodeConnectorParts[] = str.split("\\|");
476 if (nodeConnectorParts.length != 2) {
477 // Try to guess from a String formatted as a short because
478 // for long time openflow has been prime citizen so lets
479 // keep this legacy for now
480 String numStr = str.toUpperCase();
482 Short ofPortID = null;
483 // Try as an decimal/hex number
485 ofPortID = Short.decode(numStr);
486 } catch (Exception ex) {
490 // Lets try the special ports we know about
491 if (ofPortID == null) {
493 if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
495 return new NodeConnector(
496 NodeConnectorIDType.CONTROLLER,
497 SPECIALNODECONNECTORID, n);
499 if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
501 return new NodeConnector(NodeConnectorIDType.HWPATH,
502 SPECIALNODECONNECTORID, n);
504 if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
506 return new NodeConnector(NodeConnectorIDType.SWSTACK,
507 SPECIALNODECONNECTORID, n);
510 .equalsIgnoreCase(NodeConnectorIDType.ALL
512 return new NodeConnector(NodeConnectorIDType.ALL,
513 SPECIALNODECONNECTORID, n);
515 } catch (ConstructionException ex) {
521 // Lets return the cooked up NodeID
523 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
525 } catch (ConstructionException ex) {
530 String typeStr = nodeConnectorParts[0];
531 String IDStr = nodeConnectorParts[1];
532 return fromStringNoNode(typeStr, IDStr, n);
536 * return a NodeConnector from a pair (type, ID) in string format
537 * not containing explicitely the Node portion which has to be
538 * supplied as parameter
540 * @param typeStr type String to be parsed in a NodeConnector
541 * @param IDStr ID String portion to be parsed in a NodeConnector
542 * @param n Node to which the NodeConnector is attached
544 * @return the NodeConnector if parse is succesfull, null otherwise
546 public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
548 if (typeStr == null) {
555 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
556 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
557 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
559 Short ID = Short.parseShort(IDStr);
560 return new NodeConnector(typeStr, ID, n);
561 } catch (Exception ex) {
564 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
565 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
566 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
567 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
569 return new NodeConnector(typeStr, IDStr, n);
570 } catch (Exception ex) {
573 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
574 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
575 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
577 Integer ID = Integer.parseInt(IDStr);
578 return new NodeConnector(typeStr, ID, n);
579 } catch (Exception ex) {
583 // Lookup via OSGi service registry