Add string attributes to self-containd objects.

- Add common super class to *Event classes, which handles attributes.
- Add string attributes to *Event classes (ONOS-1564)
- Populate string attributes.
  Picked random attribute obtained from OF, just to initially populate attrs.
  Attributes to be used for each elements should be revisited later.
- *Impl class to use/reference self-contained objects
   prep-work for snapshot in mind.
- unified equals implementations
- Add unfrozen Copy constructor.
- Add freeze check to fixed attributes.
- Remove get*Impl which was not really adding value.

Change-Id: I10f9538f87d133a22237bd8ab97b8de421d3930b
diff --git a/src/main/java/net/onrc/onos/core/topology/PortImpl.java b/src/main/java/net/onrc/onos/core/topology/PortImpl.java
index 9332764..8a5e783 100644
--- a/src/main/java/net/onrc/onos/core/topology/PortImpl.java
+++ b/src/main/java/net/onrc/onos/core/topology/PortImpl.java
@@ -1,7 +1,9 @@
 package net.onrc.onos.core.topology;
 
 import java.util.Map;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import org.apache.commons.lang.Validate;
+
 import net.onrc.onos.core.util.Dpid;
 import net.onrc.onos.core.util.PortNumber;
 import net.onrc.onos.core.util.SwitchPort;
@@ -14,86 +16,166 @@
  */
 public class PortImpl extends TopologyObject implements Port {
 
-    private Switch sw;
+    //////////////////////////////////////////////////////
+    /// Topology element attributes
+    ///  - any changes made here needs to be replicated.
+    //////////////////////////////////////////////////////
+    private PortEvent portObj;
 
-    private PortNumber number;
-    private String description;
+    ///////////////////
+    /// In-memory index
+    ///////////////////
 
-    private final SwitchPort switchPort;
 
-    public PortImpl(Topology topology, Switch parentSwitch, PortNumber number) {
+    /**
+     * Creates a Port object based on {@link PortEvent}.
+     *
+     * @param topology Topology instance this object belongs to
+     * @param scPort self contained {@link PortEvent}
+     */
+    public PortImpl(Topology topology, PortEvent scPort) {
         super(topology);
-        this.sw = parentSwitch;
-        this.number = number;
+        Validate.notNull(scPort);
 
-        switchPort = new SwitchPort(parentSwitch.getDpid(),
-                                    number);
+        // TODO should we assume portObj is already frozen before this call
+        //      or expect attribute update will happen after .
+        if (scPort.isFrozen()) {
+            this.portObj = scPort;
+        } else {
+            this.portObj = new PortEvent(scPort);
+            this.portObj.freeze();
+        }
     }
 
+    /**
+     * Creates a Port object with empty attributes.
+     *
+     * @param topology Topology instance this object belongs to
+     * @param switchPort SwitchPort
+     */
+    public PortImpl(Topology topology, SwitchPort switchPort) {
+        this(topology, new PortEvent(switchPort).freeze());
+    }
+
+    /**
+     * Creates a Port object with empty attributes.
+     *
+     * @param topology Topology instance this object belongs to
+     * @param dpid DPID
+     * @param number PortNumber
+     */
+    public PortImpl(Topology topology, Dpid dpid, PortNumber number) {
+        this(topology, new SwitchPort(dpid, number));
+        Validate.notNull(dpid);
+        Validate.notNull(number);
+    }
+
+    public PortImpl(Topology topology, Long dpid, Long number) {
+        this(topology, new SwitchPort(dpid, number));
+        Validate.notNull(dpid);
+        Validate.notNull(number);
+    }
+
+    @Deprecated
+    public PortImpl(Topology topology, Switch parentSwitch, PortNumber number) {
+        this(topology, new SwitchPort(parentSwitch.getDpid(), number));
+    }
+
+    @Deprecated
     public PortImpl(Topology topology, Switch parentSwitch, Long number) {
         this(topology, parentSwitch, new PortNumber(number.shortValue()));
     }
 
     @Override
     public Dpid getDpid() {
-        return sw.getDpid();
+        return asSwitchPort().getDpid();
     }
 
     @Override
     public PortNumber getNumber() {
-        return number;
+        return asSwitchPort().getPortNumber();
     }
 
     @Override
     public SwitchPort asSwitchPort() {
-        return switchPort;
+        return portObj.getSwitchPort();
     }
 
     @Override
     public String getDescription() {
-        return description;
+        return getStringAttribute(PortEvent.DESCRIPTION, "");
     }
 
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    @Override
-    public Long getHardwareAddress() {
-        // TODO Auto-generated method stub
-        return 0L;
-    }
-
-    @Override
-    public Switch getSwitch() {
-        return sw;
-    }
-
-    @Override
-    public Link getOutgoingLink() {
-        return topology.getOutgoingLink(switchPort.dpid(),
-                                        switchPort.port());
-    }
-
-    @Override
-    public Link getIncomingLink() {
-        return topology.getIncomingLink(switchPort.dpid(),
-                                        switchPort.port());
-    }
-
-    @Override
-    public Iterable<Device> getDevices() {
-        return topology.getDevices(this.asSwitchPort());
-    }
-
-    @Override
-    public String getStringAttribute(String attr) {
+    void setDescription(String description) {
+//        portObj.createStringAttribute(attr, value);
+        // TODO implement using attributes
         throw new UnsupportedOperationException("Not implemented yet");
     }
 
     @Override
-    @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE",
-       justification = "getStringAttribute might return null once implemented")
+    public Long getHardwareAddress() {
+        // TODO implement using attributes?
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public Switch getSwitch() {
+        topology.acquireReadLock();
+        try {
+            return topology.getSwitch(getDpid());
+        } finally {
+            topology.releaseReadLock();
+        }
+    }
+
+    @Override
+    public Link getOutgoingLink() {
+        topology.acquireReadLock();
+        try {
+            return topology.getOutgoingLink(asSwitchPort());
+        } finally {
+            topology.releaseReadLock();
+        }
+    }
+
+    @Override
+    public Link getIncomingLink() {
+        topology.acquireReadLock();
+        try {
+            return topology.getIncomingLink(asSwitchPort());
+        } finally {
+            topology.releaseReadLock();
+        }
+    }
+
+    @Override
+    public Iterable<Device> getDevices() {
+        topology.acquireReadLock();
+        try {
+            return topology.getDevices(this.asSwitchPort());
+        } finally {
+            topology.releaseReadLock();
+        }
+    }
+
+    void replaceStringAttributes(PortEvent updated) {
+        Validate.isTrue(this.asSwitchPort().equals(updated.getSwitchPort()),
+                "Wrong PortEvent given.");
+
+        // XXX simply replacing whole self-contained object for now
+        if (updated.isFrozen()) {
+            this.portObj = updated;
+        } else {
+            this.portObj = new PortEvent(updated).freeze();
+        }
+    }
+
+    @Override
+    public String getStringAttribute(String attr) {
+        return portObj.getStringAttribute(attr);
+    }
+
+    @Override
     public String getStringAttribute(String attr, String def) {
         final String v = getStringAttribute(attr);
         if (v == null) {
@@ -105,7 +187,7 @@
 
     @Override
     public Map<String, String> getAllStringAttributes() {
-        throw new UnsupportedOperationException("Not implemented yet");
+        return portObj.getAllStringAttributes();
     }
 
     @Override