sal中的Node类解读

       按照前面一篇文章的框架,sal层的Node这个类应该是和插件层的类有联系,但在这个类中,我没有看到引入了插件层的内容。我的猜想,它应该符合观察者的模式,它属于观察者,而插件层是主题,当插件层的内容发生变化时,它应该也有所变化,但这里并没有那个联系,反而我在插件层中的控制器中看到了Controller类引用了Node这个类,未完待续,之后慢慢理解再补充。

package org.opendaylight.controller.sal.core;


import java.io.Serializable;
import java.math.BigInteger;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.INodeFactory;
import org.opendaylight.controller.sal.utils.ServiceHelper;

/**
 * Describe a generic network element in multiple SDNs technologies. A
 * Node is identified by the pair (NodeType, NodeID), the nodetype are
 * needed in order to further specify the nodeID
 *
 */
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class Node implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * Enum-like static class created with the purpose of identifing
     * multiple type of nodes in the SDN network. The type is
     * necessary to figure out to later on correctly use the
     * nodeID. Using a static class instead of an Enum so we can add
     * dynamically new types without changing anything in the
     * surround.
     */
    public static final class NodeIDType {
        private static final ConcurrentHashMap<String, Class<? extends Object>> compatibleType =
            new ConcurrentHashMap<String, Class<? extends Object>>();
        /**
         * Identifier for an OpenFlow node
         */
        public static String OPENFLOW = "OF";
        /**
         * Identifier for a PCEP node
         */
        public static String PCEP = "PE";
        /**
         * Identifier for a ONEPK node
         */
        public static String ONEPK = "PK";
        /**
         * Identifier for a node in a non-SDN network
         */
        public static String PRODUCTION = "PR";

        // Pre-populated types, just here for convenience and ease of
        // unit-testing, but certainly those could live also outside.
        static {
            compatibleType.put(OPENFLOW, Long.class);
            compatibleType.put(PCEP, UUID.class);
            compatibleType.put(ONEPK, String.class);
            compatibleType.put(PRODUCTION, String.class);
        }

        /**
         * Return the type of the class expected for the
         * NodeID, it's used for validity check in the constructor
         *
         * @param nodeType the type of the node we want to check
         * compatibility for
         *
         * @return The Class which is supposed to instantiate the ID
         * for the NodeID
         */
        public static Class<?> getClassType(String nodeType) {
            return compatibleType.get(nodeType);
        }

        /**
         * Returns all the registered nodeIDTypes currently available
         *
         * @return The current registered NodeIDTypes
         */
        public static Set<String> values() {
            return compatibleType.keySet();
        }

        /**
         * Register a new ID for which Node can be created
         *
         * @param type, the new type being registered
         * @param compatibleID, the type of class to be accepted as ID
         *
         * @return true if registered, false otherwise
         */
        public static boolean registerIDType(String type,
                                             Class<? extends Object> compatibleID) {
            if (compatibleType.get(type) != null) {
                return false;
            }  else {
                compatibleType.put(type, compatibleID);
                return true;
            }
        }

        /**
         * UNRegister a new ID for which Node can be created
         *
         * @param type, the type being UN-registered
         *
         */
        public static void unRegisterIDType(String type) {
            compatibleType.remove(type);
        }
    }

    // This is the identity of the Node a (Type,ID) pair!, the full
    // essence of this class.
    private Object nodeID;
    private String nodeType;

    // Shadow value for unmarshalling
    private String nodeIDString;

    /**
     * Private constructor used for JAXB mapping
     */
    private Node() {
        this.nodeID = null;
        this.nodeType = null;
        this.nodeIDString = null;
    }

    /**
     * Constructor for the Node objects, it validate the input so if
     * the ID passed is not of the type expected accordingly to the
     * type an exception is raised.
     *
     * @param nodeType Type of the node we are building
     * @param id ID used by the SDN technology to identify the node
     *
     */
    public Node(String nodeType, Object id) throws ConstructionException {
        if (NodeIDType.getClassType(nodeType) != null &&
            NodeIDType.getClassType(nodeType).isInstance(id)) {
            this.nodeType = nodeType;
            this.nodeID = id;
        } else {
            throw new ConstructionException("Type of incoming object:"
                                            + id.getClass() + " not compatible with expected type:"
                                            + NodeIDType.getClassType(nodeType));
        }
    }

    /**
     * Copy Constructor for the Node objects.
     *
     * @param src type of nodes to copy from
     *
     */
    public Node(Node src) throws ConstructionException {
        if (src != null) {
            this.nodeType = src.getType();
            // Here we can reference the object because that is
            // supposed to be an immutable identifier as well like a
            // UUID/Integer and so on, hence no need to create a copy
            // of it
            this.nodeID = src.getID();
        } else {
            throw
                new ConstructionException("Null incoming object to copy from");
        }
    }

    /**
     * getter for node type
     *
     *
     * @return The node Type for this Node object
     */
    @XmlElement(name = "type")
    public String getType() {
        return this.nodeType;
    }

    /**
     * fill the current object from the string parameters passed, will
     * be only used by JAXB
     *
     * @param typeStr string representing the type of the Node
     * @param IDStr String representation of the ID
     */
    private void fillmeFromString(String typeStr, String IDStr) {
        if (typeStr == null) {
            return;
        }

        if (IDStr == null) {
            return;
        }

        this.nodeType = typeStr;
        if (typeStr.equals(NodeIDType.OPENFLOW)) {
            this.nodeID = Long.valueOf(HexEncode.stringToLong(IDStr));
        } else if (typeStr.equals(NodeIDType.ONEPK)) {
            this.nodeID = IDStr;
        } else if (typeStr.equals(NodeIDType.PCEP)) {
            this.nodeID = UUID.fromString(IDStr);
        } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
            this.nodeID = IDStr;
        } else {
            //Use plugin's method to get appropriate conversion from IDStr to nodeID
            INodeFactory f = (INodeFactory) ServiceHelper
                    .getGlobalInstance(INodeFactory.class, new Node(), "(protocolName="+typeStr+")");
            if(f!=null){
                Node n = f.fromString(typeStr, IDStr);
                this.nodeID = n.nodeID;
            }
        }
    }

    /**
     * Private setter for nodeType to be called by JAXB not by anyone
     * else, Node is immutable
     *
     * @param type of node to be set
     */
    private void setType(String type) {
        this.nodeType = type;
        if (this.nodeIDString != null) {
            this.fillmeFromString(type, this.nodeIDString);
        }
    }

    /**
     * getter for node ID
     *
     *
     * @return The node ID for this Node object
     */
    public Object getID() {
        return this.nodeID;
    }

    /**
     * Getter for the node ID in string format
     *
     * @return The nodeID in string format
     */
    @XmlElement(name = "id")
    public String getNodeIDString() {
        if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
            return HexEncode.longToHexString((Long) this.nodeID);
        } else {
            return this.nodeID.toString();
        }
    }

    /**
     * private setter to be used by JAXB
     *
     * @param nodeIDString String representation for NodeID
     */
    private void setNodeIDString(String nodeIDString) {
        this.nodeIDString = nodeIDString;
        if (this.nodeType != null) {
            this.fillmeFromString(this.nodeType, nodeIDString);
        }
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((nodeID == null) ? 0 : nodeID.hashCode());
        result = prime * result
                + ((nodeType == null) ? 0 : nodeType.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Node other = (Node) obj;
        if (nodeID == null) {
            if (other.nodeID != null)
                return false;
        } else if (!nodeID.equals(other.nodeID))
            return false;
        if (nodeType == null) {
            if (other.nodeType != null)
                return false;
        } else if (!nodeType.equals(other.nodeType))
            return false;
        return true;
    }

    @Override
    public String toString() {
        if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
            return this.nodeType + "|"
                + HexEncode.longToHexString((Long) this.nodeID);
        } else {
            return this.nodeType + "|" + this.nodeID.toString();
        }
    }

    /**
     * Static method to get back a Node from a string
     *
     * @param str string formatted in toString mode that can be
     * converted back to a Node format.
     *
     * @return a Node if succed or null if no
     */
    public static Node fromString(String str) {
        if (str == null) {
            return null;
        }

        String parts[] = str.split("\\|");
        if (parts.length != 2) {
            // Try to guess from a String formatted as a long because
            // for long time openflow has been prime citizen so lets
            // keep this legacy for now
            String numStr = str.toUpperCase();

            Long ofNodeID = null;
            if (numStr.startsWith("0X")) {
                // Try as an hex number
                try {
                    BigInteger b = new BigInteger(
                        numStr.replaceFirst("0X", ""), 16);
                    ofNodeID = Long.valueOf(b.longValue());
                } catch (Exception ex) {
                    ofNodeID = null;
                }
            } else {
                // Try as a decimal number
                try {
                    BigInteger b = new BigInteger(numStr);
                    ofNodeID = Long.valueOf(b.longValue());
                } catch (Exception ex) {
                    ofNodeID = null;
                }
            }

            // Startegy #3 parse as HexLong
            if (ofNodeID == null) {
                try {
                    ofNodeID = Long.valueOf(HexEncode.stringToLong(numStr));
                } catch (Exception ex) {
                    ofNodeID = null;
                }
            }

            // We ran out of ideas ... return null
            if (ofNodeID == null) {
                return null;
            }

            // Lets return the cooked up NodeID
            try {
                return new Node(NodeIDType.OPENFLOW, ofNodeID);
            } catch (ConstructionException ex) {
                return null;
            }
        }

        String typeStr = parts[0];
        String IDStr = parts[1];

        return fromString(typeStr, IDStr);
    }

    /**
     * Static method to get back a Node from a pair of strings, the
     * first one being the Type representation, the second one being
     * the ID string representation, expected to be heavily used in
     * northbound API.
     *
     * @param type, the type of the node we are parsing
     * @param id, the string representation of the node id
     *
     * @return a Node if succed or null if no
     */
    public static Node fromString(String typeStr, String IDStr) {
        if (typeStr == null) {
            return null;
        }

        if (IDStr == null) {
            return null;
        }

        if (typeStr.equals(NodeIDType.OPENFLOW)) {
            try {
                Long ID = Long.valueOf(HexEncode.stringToLong(IDStr));
                return new Node(typeStr, ID);
            } catch (Exception ex) {
                return null;
            }
        } else if (typeStr.equals(NodeIDType.ONEPK)) {
            try {
                return new Node(typeStr, IDStr);
            } catch (Exception ex) {
                return null;
            }
        } else if (typeStr.equals(NodeIDType.PCEP)) {
            try {
                UUID ID = UUID.fromString(IDStr);
                return new Node(typeStr, ID);
            } catch (Exception ex) {
                return null;
            }
        } else if (typeStr.equals(NodeIDType.PRODUCTION)) {
            try {
                return new Node(typeStr, IDStr);
            } catch (Exception ex) {
                return null;
            }
        } else {
            //Use INodeFactory to create a Node of registered Node type.
            //The protocol plugin being used depends on typeStr.
            INodeFactory f = (INodeFactory) ServiceHelper
                    .getGlobalInstance(INodeFactory.class, new Node(), "(protocolName="+typeStr+")");
            if(f==null)
                return null;
            return f.fromString(typeStr, IDStr);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值