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/DeviceImpl.java b/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java
index 19fe0a7..61de0d2 100644
--- a/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java
+++ b/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java
@@ -1,47 +1,99 @@
 package net.onrc.onos.core.topology;
 
-import java.util.Collections;
-import java.util.LinkedList;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
 
 import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.core.util.SwitchPort;
 
 /**
  * Device Object stored in In-memory Topology.
  */
 public class DeviceImpl extends TopologyObject implements Device {
 
-    private final MACAddress macAddr;
-    protected LinkedList<Port> attachmentPoints;
-    private long lastSeenTime;
+    //////////////////////////////////////////////////////
+    /// Topology element attributes
+    ///  - any changes made here needs to be replicated.
+    //////////////////////////////////////////////////////
+    private DeviceEvent deviceObj;
 
-    public DeviceImpl(Topology topology, MACAddress mac) {
+    ///////////////////
+    /// In-memory index
+    ///////////////////
+
+    // none
+
+    /**
+     * Creates a Device object based on {@link DeviceEvent}.
+     *
+     * @param topology Topology instance this object belongs to
+     * @param scHost self contained {@link DeviceEvent}
+     */
+    public DeviceImpl(Topology topology, DeviceEvent scHost) {
         super(topology);
-        this.macAddr = mac;
-        this.attachmentPoints = new LinkedList<>();
+        Validate.notNull(scHost);
+
+        // TODO should we assume deviceObj is already frozen before this call
+        //      or expect attribute update will happen after .
+        if (scHost.isFrozen()) {
+            this.deviceObj = scHost;
+        } else {
+            this.deviceObj = new DeviceEvent(scHost);
+            this.deviceObj.freeze();
+        }
+    }
+
+    /**
+     * Creates a Device object with empty attributes.
+     *
+     * @param topology Topology instance this object belongs to
+     * @param mac MAC address of the host
+     */
+    public DeviceImpl(Topology topology, MACAddress mac) {
+        this(topology, new DeviceEvent(mac).freeze());
     }
 
     @Override
     public MACAddress getMacAddress() {
-        return this.macAddr;
+        return this.deviceObj.getMac();
     }
 
     @Override
     public Iterable<Port> getAttachmentPoints() {
-        return Collections.unmodifiableList(this.attachmentPoints);
+        List<Port> ports = new ArrayList<>();
+        topology.acquireReadLock();
+        try {
+            for (SwitchPort swp : this.deviceObj.getAttachmentPoints()) {
+                Port p = this.topology.getPort(swp);
+                if (p != null) {
+                    ports.add(p);
+                }
+            }
+        } finally {
+            topology.releaseReadLock();
+        }
+        return ports;
     }
 
     @Override
     public long getLastSeenTime() {
-        return lastSeenTime;
+        return deviceObj.getLastSeenTime();
     }
 
     @Override
     public String toString() {
-        return macAddr.toString();
+        return getMacAddress().toString();
     }
 
+    // TODO we may no longer need this. confirm and delete later.
     void setLastSeenTime(long lastSeenTime) {
-        this.lastSeenTime = lastSeenTime;
+        // XXX Following will make this instance thread unsafe. Need to use AtomicRef.
+        DeviceEvent updated = new DeviceEvent(this.deviceObj);
+        updated.setLastSeenTime(lastSeenTime);
+        updated.freeze();
+        this.deviceObj = updated;
     }
 
     /**
@@ -50,8 +102,12 @@
      * @param port the port that the device is attached to
      */
     void addAttachmentPoint(Port port) {
-        this.attachmentPoints.remove(port);
-        this.attachmentPoints.addFirst(port);
+        // XXX Following will make this instance thread unsafe. Need to use AtomicRef.
+        DeviceEvent updated = new DeviceEvent(this.deviceObj);
+        updated.removeAttachmentPoint(port.asSwitchPort());
+        updated.addAttachmentPoint(port.asSwitchPort());
+        updated.freeze();
+        this.deviceObj = updated;
     }
 
     /**
@@ -60,7 +116,12 @@
      * @param port the port that the device is attached to
      */
     boolean removeAttachmentPoint(Port port) {
-        return this.attachmentPoints.remove(port);
+        // XXX Following will make this instance thread unsafe. Need to use AtomicRef.
+        DeviceEvent updated = new DeviceEvent(this.deviceObj);
+        final boolean result = updated.removeAttachmentPoint(port.asSwitchPort());
+        updated.freeze();
+        this.deviceObj = updated;
+        return result;
     }