ONOS-3503 Remove OchPort out of core.

- Implementation of a Behavior OpticalDevice has the knowledge of
  translating annotations into optical specific port.
- OpticalDeviceServiceView checks if the Device is a OpticalDevice
  and translate all the Ports to optical specific port before returning.

- This commit contains feedbacks, issues, and fixes by Michele Santuari.

- Note: 3 more Port types to go (OduClt, Oms, Otu)

Change-Id: I4cbda8bc1922fbdd4dac8de8d02294bad74b8058
diff --git a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
index bde5dfa..273e0bb 100644
--- a/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
+++ b/apps/optical/src/main/java/org/onosproject/optical/OpticalPathProvisioner.java
@@ -30,7 +30,6 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.Host;
 import org.onosproject.net.Link;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.Path;
@@ -46,6 +45,7 @@
 import org.onosproject.net.intent.OpticalCircuitIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.optical.OchPort;
 import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.net.topology.TopologyEdge;
@@ -60,6 +60,7 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
 
 /**
  * OpticalPathProvisioner listens for event notifications from the Intent F/W.
@@ -100,6 +101,7 @@
 
     @Activate
     protected void activate() {
+        deviceService = opticalView(deviceService);
         intentService.addListener(pathProvisioner);
         appId = coreService.registerApplication("org.onosproject.optical");
         initOpticalPorts();
diff --git a/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java b/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
index 3d3bca4..001c273 100644
--- a/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java
@@ -21,7 +21,6 @@
 import org.onosproject.net.CltSignalType;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.OduSignalType;
@@ -32,10 +31,12 @@
 import org.onosproject.net.intent.OpticalCircuitIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalOduIntent;
+import org.onosproject.net.optical.OchPort;
 
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
 
 /**
  * Installs optical connectivity or circuit intents, depending on given port types.
@@ -93,7 +94,8 @@
             return;
         }
 
-        DeviceService deviceService = get(DeviceService.class);
+        DeviceService deviceService = opticalView(get(DeviceService.class));
+
         Port srcPort = deviceService.getPort(ingress.deviceId(), ingress.port());
         Port dstPort = deviceService.getPort(egress.deviceId(), egress.port());
 
@@ -142,6 +144,19 @@
                     .signalType(signalType)
                     .bidirectional(bidirectional)
                     .build();
+        } else if (srcPort instanceof org.onosproject.net.OchPort &&
+                   dstPort instanceof org.onosproject.net.OchPort) {
+            print("WARN: encountered old OchPort model");
+            // old OchPort model can be removed when ready
+            OduSignalType signalType = ((org.onosproject.net.OchPort) srcPort).signalType();
+            intent = OpticalConnectivityIntent.builder()
+                    .appId(appId())
+                    .key(key())
+                    .src(ingress)
+                    .dst(egress)
+                    .signalType(signalType)
+                    .bidirectional(bidirectional)
+                    .build();
         } else {
             print("Unable to create optical intent between connect points %s and %s", ingress, egress);
             return;
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
index 6549b07..e8413f2 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
@@ -25,19 +25,20 @@
 import org.onlab.util.Frequency;
 import org.onosproject.utils.Comparators;
 import org.onosproject.net.Device;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OmsPort;
 import org.onosproject.net.OtuPort;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
-
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.OpticalDevice;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
 
 /**
  * Lists all ports or all ports of a device.
@@ -65,7 +66,7 @@
 
     @Override
     protected void execute() {
-        DeviceService service = get(DeviceService.class);
+        DeviceService service = opticalView(get(DeviceService.class));
         if (uri == null) {
             if (outputJson()) {
                 print("%s", jsonPorts(service, getSortedDevices(service)));
@@ -154,10 +155,37 @@
             String annotations = annotations(port.annotations());
             switch (port.type()) {
                 case OCH:
-                     print(FMT_OCH, portName, portIsEnabled, portType,
-                             ((OchPort) port).signalType().toString(),
-                             ((OchPort) port).isTunable() ? "yes" : "no", annotations);
-                     break;
+                    if (port instanceof org.onosproject.net.OchPort) {
+                        // old OchPort model
+                        org.onosproject.net.OchPort oPort = (org.onosproject.net.OchPort) port;
+                        print("WARN: OchPort in old model");
+                        print(FMT_OCH, portName, portIsEnabled, portType,
+                              oPort.signalType().toString(),
+                              oPort.isTunable() ? "yes" : "no", annotations);
+                        break;
+                    }
+                    if (port instanceof OchPort) {
+                        OchPort och = (OchPort) port;
+                        print(FMT_OCH, portName, portIsEnabled, portType,
+                              och.signalType().toString(),
+                              och.isTunable() ? "yes" : "no", annotations);
+                       break;
+                    } else if (port.element().is(OpticalDevice.class)) {
+                        // Note: should never reach here, but
+                        // leaving it here as an example to
+                        // manually translate to specific port.
+                        OpticalDevice optDevice = port.element().as(OpticalDevice.class);
+                        if (optDevice.portIs(port, OchPort.class)) {
+                            OchPort och = optDevice.portAs(port, OchPort.class).get();
+                            print(FMT_OCH, portName, portIsEnabled, portType,
+                                  och.signalType().toString(),
+                                  och.isTunable() ? "yes" : "no", annotations);
+                            break;
+                        }
+                    }
+                    print("WARN: OchPort but not on OpticalDevice or ill-formed");
+                    print(FMT, portName, portIsEnabled, portType, port.portSpeed(), annotations);
+                    break;
                 case ODUCLT:
                      print(FMT_ODUCLT_OTU, portName, portIsEnabled, portType,
                             ((OduCltPort) port).signalType().toString(), annotations);
diff --git a/core/api/src/main/java/org/onosproject/net/OchPort.java b/core/api/src/main/java/org/onosproject/net/OchPort.java
index 1997a88..1b544e6 100644
--- a/core/api/src/main/java/org/onosproject/net/OchPort.java
+++ b/core/api/src/main/java/org/onosproject/net/OchPort.java
@@ -24,7 +24,10 @@
  * Implementation of OCh port (Optical Channel).
  * Also referred to as a line side port (L-port) or narrow band port.
  * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)"
+ *
+ * @deprecated in Goldeneye (1.6.0)
  */
+@Deprecated
 public class OchPort extends DefaultPort {
 
     private final OduSignalType signalType;
diff --git a/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java b/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java
index 1b2fd34..a507e49 100644
--- a/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java
@@ -37,7 +37,7 @@
     private final long portSpeed;
 
     /**
-     * Creates a port description using the supplied information.
+     * Creates a DEFAULT_SPEED COPPER port description using the supplied information.
      *
      * @param number      port number
      * @param isEnabled   port enabled state
diff --git a/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java b/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
index b6398f4..6397764 100644
--- a/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.device;
 
 import com.google.common.base.MoreObjects;
+
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.Port;
@@ -26,7 +27,10 @@
 
 /**
  * Default implementation of immutable OCh port description.
+ *
+ * @deprecated in Goldeneye (1.6.0)
  */
+@Deprecated
 public class OchPortDescription extends DefaultPortDescription {
 
     private final OduSignalType signalType;
@@ -42,7 +46,10 @@
      * @param isTunable   tunable wavelength capability
      * @param lambda      OCh signal
      * @param annotations optional key/value annotations map
+     *
+     * @deprecated in Goldeneye (1.6.0)
      */
+    @Deprecated
     public OchPortDescription(PortNumber number, boolean isEnabled, OduSignalType signalType,
                               boolean isTunable, OchSignal lambda, SparseAnnotations... annotations) {
         super(number, isEnabled, Port.Type.OCH, 0, annotations);
@@ -59,7 +66,10 @@
      * @param isTunable   tunable wavelength capability
      * @param lambda      OCh signal
      * @param annotations optional key/value annotations map
+     *
+     * @deprecated in Goldeneye (1.6.0)
      */
+    @Deprecated
     public OchPortDescription(PortDescription base, OduSignalType signalType, boolean isTunable,
                               OchSignal lambda, SparseAnnotations annotations) {
         super(base, annotations);
diff --git a/core/api/src/main/java/org/onosproject/net/optical/OchPort.java b/core/api/src/main/java/org/onosproject/net/optical/OchPort.java
new file mode 100644
index 0000000..8d19889
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/OchPort.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical;
+
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * OCh port (Optical Channel).
+ * Also referred to as a line side port (L-port) or narrow band port.
+ * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)"
+ */
+@Beta
+public interface OchPort extends Port {
+
+    /**
+     * Returns ODU signal type.
+     *
+     * @return ODU signal type
+     */
+    public OduSignalType signalType();
+
+    /**
+     * Returns true if port is wavelength tunable.
+     *
+     * @return tunable wavelength capability
+     */
+    public boolean isTunable();
+
+    /**
+     * Returns OCh signal.
+     *
+     * @return OCh signal
+     */
+    public OchSignal lambda();
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/OpticalDevice.java b/core/api/src/main/java/org/onosproject/net/optical/OpticalDevice.java
new file mode 100644
index 0000000..a1498ab
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/OpticalDevice.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical;
+
+import java.util.Optional;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.driver.Behaviour;
+
+import com.google.common.annotations.Beta;
+
+
+// TODO consider more fine grained device type. e.g., Transponder, WSS, ROADM
+/**
+ * Representation of a optical network infrastructure device.
+ */
+@Beta
+public interface OpticalDevice extends Device, Behaviour {
+
+    /**
+     * Returns true if {@code port} is capable of being projected as the
+     * specified class.
+     *
+     * @param port Port instance to test
+     * @param portClass requested projection class
+     * @param <T> type of Port
+     * @return true if the requested projection is supported
+     */
+    <T extends Port> boolean portIs(Port port, Class<T> portClass);
+
+    /**
+     * Returns the specified projection of the {@code port} if such projection
+     * is supported.
+     *
+     * @param port Port instance to project
+     * @param portClass requested projection class
+     * @param <T> type of Port
+     * @return projection instance or empty if not supported.
+     */
+    <T extends Port> Optional<T> portAs(Port port, Class<T> portClass);
+
+    /**
+     * Returns most specific projection of the {@code port} or the {@code port}
+     * itself.
+     *
+     * @param port Port instance
+     * @return projection instance or {@code port} itself
+     */
+    Port port(Port port);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/DefaultOpticalDevice.java b/core/api/src/main/java/org/onosproject/net/optical/device/DefaultOpticalDevice.java
new file mode 100644
index 0000000..5a30cf7
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/DefaultOpticalDevice.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Map;
+import java.util.Optional;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onosproject.net.Device;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.AbstractBehaviour;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.OpticalDevice;
+import org.onosproject.net.optical.device.port.OchPortMapper;
+import org.onosproject.net.optical.device.port.PortMapper;
+import org.onosproject.net.optical.utils.ForwardingDevice;
+import org.slf4j.Logger;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+
+// FIXME This needs to be moved back to org.onosproject.net.optical.impl
+// after optical driver package separation process is complete.
+/**
+ * Implementation of {@link OpticalDevice}.
+ * <p>
+ * Currently supports
+ * <ul>
+ *  <li> {@link OchPort}
+ * </ul>
+ */
+@Beta
+public class DefaultOpticalDevice
+        extends AbstractBehaviour
+        implements OpticalDevice, ForwardingDevice {
+
+    private static final Logger log = getLogger(DefaultOpticalDevice.class);
+
+    // shared Port type handler map.
+    // TODO Is there a use case, where we need to differentiate this map per Device?
+    private static final Map<Class<? extends Port>, PortMapper<? extends Port>> MAPPERS
+        = ImmutableMap.<Class<? extends Port>, PortMapper<? extends Port>>builder()
+            .put(OchPort.class, new OchPortMapper())
+            // TODO add other optical port type here
+            .build();
+
+
+
+    // effectively final
+    private Device delegate;
+
+    // Default constructor required as a Behaviour.
+    public DefaultOpticalDevice() {}
+
+    @Override
+    public Device delegate() {
+        if (delegate == null) {
+            // dirty work around.
+            // wanted to pass delegate Device at construction,
+            // but was not possible. A Behaviour requires no-arg constructor.
+            checkState(data() != null, "DriverData must exist");
+            DriverData data = data();
+            DeviceService service = DefaultServiceDirectory.getService(DeviceService.class);
+            delegate = checkNotNull(service.getDevice(data.deviceId()),
+                                    "No Device found for %s", data.deviceId());
+        }
+        return delegate;
+    }
+
+    @Override
+    public <T extends Port> boolean portIs(Port port, Class<T> portClass) {
+
+        PortMapper<? extends Port> mapper = MAPPERS.get(portClass);
+        if (mapper != null) {
+            return mapper.is(port);
+        }
+        return false;
+    }
+
+    @Override
+    public <T extends Port> Optional<T> portAs(Port port, Class<T> portClass) {
+        PortMapper<? extends Port> mapper = MAPPERS.get(portClass);
+        if (mapper != null) {
+            return (Optional<T>) (mapper.as(port));
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Port port(Port port) {
+        for (PortMapper<? extends Port> mapper : MAPPERS.values()) {
+            if (mapper.is(port)) {
+                return mapper.as(port).map(Port.class::cast).orElse(port);
+            }
+        }
+        return port;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return delegate().equals(obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return delegate().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("delegate", delegate)
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/OchPortHelper.java b/core/api/src/main/java/org/onosproject/net/optical/device/OchPortHelper.java
new file mode 100644
index 0000000..50dc98c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/OchPortHelper.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultAnnotations.Builder;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.impl.DefaultOchPort;
+import org.onosproject.net.optical.json.OchSignalCodec;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.annotations.Beta;
+
+/**
+ * OCh port related helpers.
+ */
+@Beta
+public final class OchPortHelper {
+
+    private static final Logger log = getLogger(OchPortHelper.class);
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    // Annotation keys
+    private static final String SIGNAL_TYPE = "signalType";
+    private static final String TUNABLE = "tunable";
+    private static final String LAMBDA = "lambda";
+
+    /**
+     * Creates OCh port DefaultPortDescription based on the supplied information.
+     *
+     * @param number      port number
+     * @param isEnabled   port enabled state
+     * @param signalType  ODU signal type
+     * @param isTunable   tunable wavelength capability
+     * @param lambda      OCh signal
+     * @return OCh port DefaultPortDescription with OCh annotations
+     */
+    public static PortDescription ochPortDescription(PortNumber number,
+                                                     boolean isEnabled,
+                                                     OduSignalType signalType,
+                                                     boolean isTunable,
+                                                     OchSignal lambda) {
+        return ochPortDescription(number, isEnabled, signalType, isTunable, lambda, DefaultAnnotations.EMPTY);
+    }
+
+    /**
+     * Creates OCh port DefaultPortDescription based on the supplied information.
+     *
+     * @param number      port number
+     * @param isEnabled   port enabled state
+     * @param signalType  ODU signal type
+     * @param isTunable   tunable wavelength capability
+     * @param lambda      OCh signal
+     * @param annotationsIn key/value annotations map
+     * @return OCh port DefaultPortDescription with OCh annotations
+     */
+    public static PortDescription ochPortDescription(PortNumber number,
+                                                     boolean isEnabled,
+                                                     OduSignalType signalType,
+                                                     boolean isTunable,
+                                                     OchSignal lambda,
+                                                     SparseAnnotations annotationsIn) {
+
+        Builder builder = DefaultAnnotations.builder();
+        builder.putAll(annotationsIn);
+
+        builder.set(TUNABLE, String.valueOf(isTunable));
+        builder.set(LAMBDA, OchSignalCodec.encode(lambda).toString());
+        builder.set(SIGNAL_TYPE, signalType.toString());
+
+        DefaultAnnotations annotations = builder.build();
+        long portSpeed = 0; // FIXME assign appropriate value
+        return new DefaultPortDescription(number, isEnabled, Port.Type.OCH, portSpeed, annotations);
+    }
+
+    /**
+     * Creates OCh port DefaultPortDescription based on the supplied information.
+     *
+     * @param base        PortDescription to get basic information from
+     * @param signalType  ODU signal type
+     * @param isTunable   tunable wavelength capability
+     * @param lambda      OCh signal
+     * @param annotations key/value annotations map
+     * @return OCh port DefaultPortDescription with OCh annotations
+     */
+    public static PortDescription ochPortDescription(PortDescription base,
+                                                     OduSignalType signalType,
+                                                     boolean isTunable,
+                                                     OchSignal lambda,
+                                                     SparseAnnotations annotations) {
+        return ochPortDescription(base.portNumber(), base.isEnabled(), signalType, isTunable, lambda, annotations);
+    }
+
+
+    public static Optional<OchPort> asOchPort(Port port) {
+        if (port instanceof OchPort) {
+            return Optional.of((OchPort) port);
+        }
+
+        try {
+            Annotations an = port.annotations();
+
+            OduSignalType signalType = Enum.valueOf(OduSignalType.class,
+                                                    an.value(SIGNAL_TYPE));
+
+            boolean isTunable = Boolean.valueOf(an.value(TUNABLE));
+
+            ObjectNode obj = (ObjectNode) MAPPER.readTree(an.value(LAMBDA));
+            OchSignal lambda = OchSignalCodec.decode(obj);
+
+            // Note: OCh specific annotations is not filtered-out here.
+            //       DefaultOchPort should filter them, if necessary.
+            return Optional.of(new DefaultOchPort(port, signalType, isTunable, lambda));
+
+            // TODO: it'll be better to verify each inputs properly
+            // instead of catching all these Exceptions.
+        } catch (IOException | NullPointerException
+                | IllegalArgumentException | ClassCastException e) {
+
+            log.warn("{} was not well-formed OCh port.", port, e);
+            return Optional.empty();
+        }
+    }
+
+    // not meant to be instantiated
+    private OchPortHelper() {}
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/OpticalDeviceServiceView.java b/core/api/src/main/java/org/onosproject/net/optical/device/OpticalDeviceServiceView.java
new file mode 100644
index 0000000..c898f70
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/OpticalDeviceServiceView.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.optical.OpticalDevice;
+import org.onosproject.net.optical.utils.ForwardingDeviceService;
+import org.slf4j.Logger;
+
+import com.google.common.annotations.Beta;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Element;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+
+
+// TODO replace places using DeviceService expecting Optical specific ports.
+// with this
+
+/**
+ * Decorator, which provides a DeviceService view, which returns
+ * Ports in optical specific ports.
+ */
+@Beta
+public class OpticalDeviceServiceView
+    extends ForwardingDeviceService
+    implements DeviceService {
+
+    private static final Logger log = getLogger(OpticalDeviceServiceView.class);
+
+    /**
+     * DeviceListener to wrapped DeviceListener map.
+     * <p>
+     * {@literal original listener -> wrapped listener}
+     */
+    private final Map<DeviceListener, DeviceListener> wrapped = Maps.newIdentityHashMap();
+
+    // May need a way to monitor Drivers loaded on ONOS and
+    // invalidate this Cache if a driver was added/updated
+    /**
+     * Device to {@link OpticalDevice} map cache.
+     */
+    private final LoadingCache<Element, Optional<OpticalDevice>> optdev
+        = CacheBuilder.newBuilder()
+            .weakKeys() // == for Key comparison
+            .maximumSize(100)
+            .build(CacheLoader.from(elm -> {
+                if (elm.is(OpticalDevice.class)) {
+                    return Optional.of(elm.as(OpticalDevice.class));
+                } else {
+                    return Optional.empty();
+                }
+            }));
+
+    // Not intended to be instantiated directly
+    protected OpticalDeviceServiceView(DeviceService base) {
+        super(base);
+    }
+
+    /**
+     * Wraps the given DeviceService to provide a view,
+     * which returns port as optical specific Port class.
+     *
+     * @param base {@link DeviceService} view to use as baseline.
+     * @return Decorated view of {@code base}
+     */
+    public static OpticalDeviceServiceView opticalView(DeviceService base) {
+        // TODO might make sense to track and assign an instance for each `base`
+        return new OpticalDeviceServiceView(base);
+    }
+
+    /**
+     * Transform Port instance on the event to Optical specific port, if it is well-formed.
+     *
+     * @param event original event to transform
+     * @return transformed {@link DeviceEvent}
+     */
+    public DeviceEvent augment(DeviceEvent event) {
+        final Port port = augment(event.port());
+        if (port == event.port()) {
+            // If the Port not changed, pass through
+            return event;
+        }
+        return new DeviceEvent(event.type(), event.subject(), port, event.time());
+    }
+
+    /**
+     * Transform Port instance to Optical specific port, if it is well-formed.
+     *
+     * @param port Port instance to translate
+     * @return Optical specific port instance or original {@code port}.
+     */
+    public Port augment(Port port) {
+        if (port == null) {
+            return null;
+        }
+        return optdev.getUnchecked(port.element())
+            .map(odev -> odev.port(port))
+            .orElse(port);
+    }
+
+    @Override
+    public void addListener(DeviceListener listener) {
+        super.addListener(wrapped.computeIfAbsent(listener, OpticalDeviceListener::new));
+    }
+
+    @Override
+    public void removeListener(DeviceListener listener) {
+        DeviceListener wrappedListener = wrapped.remove(listener);
+        if (wrappedListener != null) {
+            super.removeListener(wrappedListener);
+        }
+    }
+
+
+    @Override
+    public List<Port> getPorts(DeviceId deviceId) {
+        return Lists.transform(super.getPorts(deviceId),
+                               this::augment);
+    }
+
+    @Override
+    public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+        return augment(super.getPort(deviceId, portNumber));
+    }
+
+
+    /**
+     * DeviceListener, which translates generic Port to optical specific Port
+     * before passing.
+     */
+    class OpticalDeviceListener implements DeviceListener {
+
+        private final DeviceListener listener;
+
+        // shallow cache to reuse transformed event in isRelevant and event call
+        private Pair<DeviceEvent, DeviceEvent> cache;
+
+        public OpticalDeviceListener(DeviceListener listener) {
+            this.listener = listener;
+        }
+
+        private DeviceEvent opticalEvent(DeviceEvent event) {
+
+            Pair<DeviceEvent, DeviceEvent> entry = cache;
+            if (entry != null && entry.getLeft() == event) {
+                return entry.getRight();
+            }
+
+            DeviceEvent opticalEvent = augment(event);
+            cache = Pair.of(event, opticalEvent);
+            return opticalEvent;
+        }
+
+        @Override
+        public boolean isRelevant(DeviceEvent event) {
+            return listener.isRelevant(opticalEvent(event));
+        }
+
+        @Override
+        public void event(DeviceEvent event) {
+            listener.event(opticalEvent(event));
+        }
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/package-info.java b/core/api/src/main/java/org/onosproject/net/optical/device/package-info.java
new file mode 100644
index 0000000..20b6d33
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Optical device models.
+ */
+package org.onosproject.net.optical.device;
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/port/AbstractPortMapper.java b/core/api/src/main/java/org/onosproject/net/optical/device/port/AbstractPortMapper.java
new file mode 100644
index 0000000..8162dd3
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/port/AbstractPortMapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device.port;
+
+import java.util.Optional;
+
+import org.onosproject.net.Port;
+
+import com.google.common.annotations.Beta;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+/**
+ * PortMapper which caches mapped Port instance.
+ */
+@Beta
+public abstract class AbstractPortMapper<P extends Port> implements PortMapper<P> {
+
+    private final LoadingCache<Port, Optional<P>> cache
+            = CacheBuilder.newBuilder()
+                .weakKeys() // use == to compare keys
+                .maximumSize(100)
+                .build(CacheLoader.from(this::mapPort));
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * Note: Subclasses should override and implement short-cut conditions
+     * and call {@code super.is(port)}.
+     */
+    @Override
+    public boolean is(Port port) {
+        return as(port).isPresent();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * Note: Subclasses should override and check if {@code port} is
+     * already of type {@code P} and directly return {@code Optional.of((P) port)},
+     * if not call {@code super.as(port)}.
+     */
+    @Override
+    public Optional<P> as(Port port) {
+        if (port == null) {
+            return Optional.empty();
+        }
+        return cache.getUnchecked(port);
+    }
+
+    /**
+     * Returns {@code port} mapped to {@code <P>}.
+     *
+     * @param port Port to map
+     * @return {@code port} mapped to {@code <P>}
+     */
+    protected abstract Optional<P> mapPort(Port port);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/port/IdentityMapper.java b/core/api/src/main/java/org/onosproject/net/optical/device/port/IdentityMapper.java
new file mode 100644
index 0000000..40c25af
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/port/IdentityMapper.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device.port;
+
+import java.util.Optional;
+
+import org.onosproject.net.Port;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * {@link PortMapper} which simply return given input.
+ */
+@Beta
+public class IdentityMapper implements PortMapper<Port> {
+
+    @Override
+    public boolean is(Port port) {
+        return true;
+    }
+
+    @Override
+    public Optional<Port> as(Port port) {
+        return Optional.of(port);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/port/OchPortMapper.java b/core/api/src/main/java/org/onosproject/net/optical/device/port/OchPortMapper.java
new file mode 100644
index 0000000..badca9d
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/port/OchPortMapper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device.port;
+
+import java.util.Optional;
+
+import org.onosproject.net.Port;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.device.OchPortHelper;
+import org.onosproject.net.optical.impl.DefaultOchPort;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * {@link PortMapper} to handler {@link OchPort} translation.
+ */
+@Beta
+public class OchPortMapper extends AbstractPortMapper<OchPort> {
+
+    @Override
+    public boolean is(Port port) {
+        return port != null &&
+               port.type() == Port.Type.OCH &&
+               super.is(port);
+    }
+
+    @Override
+    public Optional<OchPort> as(Port port) {
+        if (port instanceof OchPort) {
+            return Optional.of((OchPort) port);
+        }
+        return super.as(port);
+    }
+
+    @Override
+    protected Optional<OchPort> mapPort(Port port) {
+        if (port instanceof OchPort) {
+            return Optional.of((OchPort) port);
+        } else if (port instanceof org.onosproject.net.OchPort) {
+            // TODO remove after deprecation of old OchPort is complete
+
+            // translate to new OchPort
+            org.onosproject.net.OchPort old = (org.onosproject.net.OchPort) port;
+            return Optional.of(new DefaultOchPort(old,
+                                                  old.signalType(),
+                                                  old.isTunable(),
+                                                  old.lambda()));
+        }
+
+        return OchPortHelper.asOchPort(port);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/port/PortMapper.java b/core/api/src/main/java/org/onosproject/net/optical/device/port/PortMapper.java
new file mode 100644
index 0000000..90da7ae
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/port/PortMapper.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.device.port;
+
+import java.util.Optional;
+
+import org.onosproject.net.Port;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Abstraction of a class capable of  translating generic-Port object
+ * as another domain-specific Port of type {@code P}.
+ *
+ * @param <P> Port type to map generic Port to
+ */
+@Beta
+public interface PortMapper<P extends Port> {
+
+    /**
+     * Returns true if this port is capable of being projected as {@code <P>}.
+     */
+    boolean is(Port port);
+
+    /**
+     * Returns {@code port} mapped to {@code <P>}.
+     *
+     * @param port Port to map
+     * @return {@code port} mapped to {@code <P>}
+     */
+    Optional<P> as(Port port);
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/device/port/package-info.java b/core/api/src/main/java/org/onosproject/net/optical/device/port/package-info.java
new file mode 100644
index 0000000..4b53003
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/device/port/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Optical device port related utilities.
+ */
+package org.onosproject.net.optical.device.port;
diff --git a/core/api/src/main/java/org/onosproject/net/optical/impl/DefaultOchPort.java b/core/api/src/main/java/org/onosproject/net/optical/impl/DefaultOchPort.java
new file mode 100644
index 0000000..019f8c9
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/impl/DefaultOchPort.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.impl;
+
+import org.onosproject.net.Annotations;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalType;
+import org.onosproject.net.Port;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.utils.ForwardingPort;
+
+import com.google.common.annotations.Beta;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+/**
+ * Implementation of OCh port (Optical Channel).
+ * Also referred to as a line side port (L-port) or narrow band port.
+ * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)"
+ */
+@Beta
+public class DefaultOchPort extends ForwardingPort implements OchPort {
+
+    // Note: try to avoid direct access to the field, use accessor.
+    // We might want to lazily parse annotation in the future
+    private final OduSignalType signalType;
+    private final boolean isTunable;
+    private final OchSignal lambda;
+
+    /**
+     * Creates an OCh port in the specified network element.
+     *
+     * @param base Port
+     * @param signalType  ODU signal type
+     * @param isTunable   tunable wavelength capability
+     * @param lambda      OCh signal
+     */
+    public DefaultOchPort(Port base,
+                          OduSignalType signalType,
+                          boolean isTunable,
+                          OchSignal lambda) {
+        super(base);
+        // TODO should this class be parsing annotation to instantiate signalType?
+        this.signalType = checkNotNull(signalType);
+        this.isTunable = isTunable;
+        this.lambda = checkNotNull(lambda);
+    }
+
+    @Override
+    public Type type() {
+        return Type.OCH;
+    }
+
+    @Override
+    public long portSpeed() {
+        return signalType.bitRate();
+    }
+
+
+    @Override
+    public Annotations annotations() {
+        // FIXME Filter OCh annotations, after confirming that
+        // it'll not result in information-loss
+        return super.annotations();
+    }
+
+    /**
+     * Returns ODU signal type.
+     *
+     * @return ODU signal type
+     */
+    @Override
+    public OduSignalType signalType() {
+        return signalType;
+    }
+
+    /**
+     * Returns true if port is wavelength tunable.
+     *
+     * @return tunable wavelength capability
+     */
+    @Override
+    public boolean isTunable() {
+        return isTunable;
+    }
+
+    /**
+     * Returns OCh signal.
+     *
+     * @return OCh signal
+     */
+    @Override
+    public OchSignal lambda() {
+        return lambda;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(),
+                            signalType(),
+                            isTunable(),
+                            lambda());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj != null && getClass() == obj.getClass()) {
+            final DefaultOchPort that = (DefaultOchPort) obj;
+            return super.toEqualsBuilder(that)
+                    .append(this.signalType(), that.signalType())
+                    .append(this.isTunable(), that.isTunable())
+                    .append(this.lambda(), that.lambda())
+                    .isEquals();
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return super.toStringHelper()
+                .add("signalType", signalType())
+                .add("isTunable", isTunable())
+                .add("lambda", lambda())
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/impl/package-info.java b/core/api/src/main/java/org/onosproject/net/optical/impl/package-info.java
new file mode 100644
index 0000000..8542c62
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/impl/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Note: All classes in this package is expected to be instance local, and
+// are not expected to be serialized (by Kryo, etc.)
+/**
+ * Implementation of Optical augmentation classes.
+ */
+package org.onosproject.net.optical.impl;
diff --git a/core/api/src/main/java/org/onosproject/net/optical/json/OchSignalCodec.java b/core/api/src/main/java/org/onosproject/net/optical/json/OchSignalCodec.java
new file mode 100644
index 0000000..0fba4fa
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/json/OchSignalCodec.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.json;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.GridType;
+import org.onosproject.net.OchSignal;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.annotations.Beta;
+
+// TODO define common interface for JsonCodec for annotation?
+// unlike existing JsonCodec, this use-case requires that encode/decode is
+// reversible.  (e.g., obj.equals(decode(encode(obj))))
+/**
+ * JSON codec for OchSignal.
+ */
+@Beta
+public abstract class OchSignalCodec {
+
+    // TODO should probably use shared mapper across optical codecs.
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /**
+     * Creates an instance of {@link OchSignal} from JSON representation.
+     *
+     * @param obj JSON Object representing OchSignal
+     * @return OchSignal
+     * @throws IllegalArgumentException - if JSON object is ill-formed
+     * @see OchSignalCodec#encode(OchSignal)
+     */
+    public static OchSignal decode(ObjectNode obj) {
+        final GridType gridType;
+        final ChannelSpacing channelSpacing;
+        final int spacingMultiplier;
+        final int slotGranularity;
+
+        String s;
+        s = obj.get("channelSpacing").textValue();
+        checkArgument(s != null, "ill-formed channelSpacing");
+        channelSpacing = Enum.valueOf(ChannelSpacing.class, s);
+
+        s = obj.get("gridType").textValue();
+        checkArgument(s != null, "ill-formed gridType");
+        gridType = Enum.valueOf(GridType.class, s);
+
+        JsonNode node;
+        node = obj.get("spacingMultiplier");
+        checkArgument(node.canConvertToInt(), "ill-formed spacingMultiplier");
+        spacingMultiplier = node.asInt();
+
+        node = obj.get("slotGranularity");
+        checkArgument(node.canConvertToInt(), "ill-formed slotGranularity");
+        slotGranularity = node.asInt();
+
+        return new OchSignal(gridType, channelSpacing, spacingMultiplier, slotGranularity);
+    }
+
+    /**
+     * Returns a JSON Object representation of this instance.
+     *
+     * @return JSON Object representing OchSignal
+     */
+    public static ObjectNode encode(OchSignal j) {
+        ObjectNode obj = MAPPER.createObjectNode();
+        obj.put("channelSpacing", j.channelSpacing().toString());
+        obj.put("gridType", j.gridType().toString());
+        obj.put("slotGranularity", j.slotGranularity());
+        obj.put("spacingMultiplier", j.spacingMultiplier());
+        return obj;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/json/package-info.java b/core/api/src/main/java/org/onosproject/net/optical/json/package-info.java
new file mode 100644
index 0000000..93f2ed3
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/json/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * JSON related utilities.
+ */
+package org.onosproject.net.optical.json;
diff --git a/core/api/src/main/java/org/onosproject/net/optical/package-info.java b/core/api/src/main/java/org/onosproject/net/optical/package-info.java
new file mode 100644
index 0000000..fbb4d4e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Note: this package sub-tree will be moved out from onos-api bundle soon.
+/**
+ * Optical augmentation classes.
+ */
+package org.onosproject.net.optical;
diff --git a/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingDevice.java b/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingDevice.java
new file mode 100644
index 0000000..389f42b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingDevice.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.utils;
+
+import org.onlab.packet.ChassisId;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.provider.ProviderId;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * A Device which forwards all its method calls to another Device.
+ */
+@Beta
+public interface ForwardingDevice extends Device {
+
+    Device delegate();
+
+    @Override
+    default Annotations annotations() {
+        return delegate().annotations();
+    }
+
+    @Override
+    default ProviderId providerId() {
+        return delegate().providerId();
+    }
+
+    @Override
+    default <B extends Behaviour> B as(Class<B> projectionClass) {
+        return delegate().as(projectionClass);
+    }
+
+    @Override
+    default DeviceId id() {
+        return delegate().id();
+    }
+
+    @Override
+    default Type type() {
+        return delegate().type();
+    }
+
+    @Override
+    default <B extends Behaviour> boolean is(Class<B> projectionClass) {
+        return delegate().is(projectionClass);
+    }
+
+    @Override
+    default String manufacturer() {
+        return delegate().manufacturer();
+    }
+
+    @Override
+    default String hwVersion() {
+        return delegate().hwVersion();
+    }
+
+    @Override
+    default String swVersion() {
+        return delegate().swVersion();
+    }
+
+    @Override
+    default String serialNumber() {
+        return delegate().serialNumber();
+    }
+
+    @Override
+    default ChassisId chassisId() {
+        return delegate().chassisId();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingDeviceService.java b/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingDeviceService.java
new file mode 100644
index 0000000..7bcec14
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingDeviceService.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.utils;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.Device.Type;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortStatistics;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * A DeviceService which forwards all its method calls to another DeviceService.
+ */
+@Beta
+public abstract class ForwardingDeviceService implements DeviceService {
+
+    private final DeviceService delegate;
+
+    protected ForwardingDeviceService(DeviceService delegate) {
+        this.delegate = checkNotNull(delegate);
+    }
+
+    protected final DeviceService delegate() {
+        return delegate;
+    }
+
+    @Override
+    public void addListener(DeviceListener listener) {
+        delegate.addListener(listener);
+    }
+
+    @Override
+    public void removeListener(DeviceListener listener) {
+        delegate.removeListener(listener);
+    }
+
+    @Override
+    public int getDeviceCount() {
+        return delegate.getDeviceCount();
+    }
+
+    @Override
+    public Iterable<Device> getDevices() {
+        return delegate.getDevices();
+    }
+
+    @Override
+    public Iterable<Device> getDevices(Type type) {
+        return delegate.getDevices(type);
+    }
+
+    @Override
+    public Iterable<Device> getAvailableDevices() {
+        return delegate.getAvailableDevices();
+    }
+
+    @Override
+    public Iterable<Device> getAvailableDevices(Type type) {
+        return delegate.getAvailableDevices(type);
+    }
+
+    @Override
+    public Device getDevice(DeviceId deviceId) {
+        return delegate.getDevice(deviceId);
+    }
+
+    @Override
+    public MastershipRole getRole(DeviceId deviceId) {
+        return delegate.getRole(deviceId);
+    }
+
+    @Override
+    public List<Port> getPorts(DeviceId deviceId) {
+        return delegate.getPorts(deviceId);
+    }
+
+    @Override
+    public List<PortStatistics> getPortStatistics(DeviceId deviceId) {
+        return delegate.getPortStatistics(deviceId);
+    }
+
+    @Override
+    public List<PortStatistics> getPortDeltaStatistics(DeviceId deviceId) {
+        return delegate.getPortDeltaStatistics(deviceId);
+    }
+
+    @Override
+    public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+        return delegate.getPort(deviceId, portNumber);
+    }
+
+    @Override
+    public boolean isAvailable(DeviceId deviceId) {
+        return delegate.isAvailable(deviceId);
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingPort.java b/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingPort.java
new file mode 100644
index 0000000..f241625
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/utils/ForwardingPort.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.optical.utils;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.Element;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+/**
+ * A Port which forwards all its method calls to another Port.
+ */
+@Beta
+public abstract class ForwardingPort implements Port {
+
+    private final Port delegate;
+
+    protected ForwardingPort(Port delegate) {
+        this.delegate = checkNotNull(delegate);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(element().id(),
+                            number(),
+                            isEnabled(),
+                            type(),
+                            portSpeed(),
+                            annotations());
+    }
+
+    /**
+     * Returns {@link EqualsBuilder} comparing all Port attributes
+     * including annotations.
+     * <p>
+     * To add extra fields to equality,
+     * call {@code super.toEqualsBuilder(..)} and append fields.
+     * To remove field from comparison, override this method
+     * or manually implement equals().
+     */
+    protected EqualsBuilder toEqualsBuilder(Port that) {
+        if (that == null) {
+            return new EqualsBuilder().appendSuper(false);
+        }
+        return new EqualsBuilder()
+                .append(this.element().id(), that.element().id())
+                .append(this.number(), that.number())
+                .append(this.isEnabled(), that.isEnabled())
+                .append(this.type(), that.type())
+                .append(this.portSpeed(), that.portSpeed())
+                .append(this.annotations(), that.annotations());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj != null && getClass() == obj.getClass()) {
+            final ForwardingPort that = (ForwardingPort) obj;
+            return toEqualsBuilder(that)
+                    .isEquals();
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@link ToStringHelper} with Port attributes excluding annotations.
+     *
+     * @return {@link ToStringHelper}
+     */
+    protected ToStringHelper toStringHelper() {
+        return MoreObjects.toStringHelper(this)
+                .add("element", element().id())
+                .add("number", number())
+                .add("isEnabled", isEnabled())
+                .add("type", type())
+                .add("portSpeed", portSpeed());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper()
+                .toString();
+    }
+
+    @Override
+    public Annotations annotations() {
+        return delegate.annotations();
+    }
+
+    @Override
+    public Element element() {
+        return delegate.element();
+    }
+
+    @Override
+    public PortNumber number() {
+        return delegate.number();
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return delegate.isEnabled();
+    }
+
+    @Override
+    public Port.Type type() {
+        return delegate.type();
+    }
+
+    @Override
+    public long portSpeed() {
+        return delegate.portSpeed();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/optical/utils/package-info.java b/core/api/src/main/java/org/onosproject/net/optical/utils/package-info.java
new file mode 100644
index 0000000..ae8d0b5
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/optical/utils/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Utility classes.
+ */
+package org.onosproject.net.optical.utils;
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java b/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
index 25bc848..fdd1f5d 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.device.impl;
 
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
 import static org.slf4j.LoggerFactory.getLogger;
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -22,7 +23,6 @@
 import org.onosproject.net.config.basics.OpticalPortConfig;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OtuPort;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OmsPort;
@@ -35,6 +35,8 @@
 import org.onosproject.net.device.OmsPortDescription;
 import org.onosproject.net.device.OtuPortDescription;
 import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.OpticalDevice;
 import org.slf4j.Logger;
 
 /**
@@ -105,16 +107,21 @@
                 return new OmsPortDescription(port, oms.isEnabled(), oms.minFrequency(),
                         oms.maxFrequency(), oms.grid(), sa);
             case OCH:
-            // We might need to update lambda below with STATIC_LAMBDA.
-                OchPortDescription och = (OchPortDescription) descr;
-                return new OchPortDescription(port, och.isEnabled(), och.signalType(),
-                        och.isTunable(), och.lambda(), sa);
+                // We might need to update lambda below with STATIC_LAMBDA.
+                if (descr instanceof OchPortDescription) {
+                    // TODO This block can go away once deprecation is complete.
+                    OchPortDescription och = (OchPortDescription) descr;
+                    return ochPortDescription(port, och.isEnabled(), och.signalType(),
+                            och.isTunable(), och.lambda(), sa);
+                }
+                return descr;
             case ODUCLT:
                 OduCltPortDescription odu = (OduCltPortDescription) descr;
                 return new OduCltPortDescription(port, odu.isEnabled(), odu.signalType(), sa);
             case PACKET:
             case FIBER:
             case COPPER:
+                // TODO: it should be safe to just return descr. confirm and fix
                 return new DefaultPortDescription(port, descr.isEnabled(), descr.type(),
                         descr.portSpeed(), sa);
             case OTU:
@@ -182,9 +189,22 @@
                 return new OmsPortDescription(ptn, isup, oms.minFrequency(),
                         oms.maxFrequency(), oms.grid(), an);
             case OCH:
-                OchPort och = (OchPort) port;
-                return new OchPortDescription(ptn, isup, och.signalType(),
-                        och.isTunable(), och.lambda(), an);
+                if (port instanceof org.onosproject.net.OchPort) {
+                    // remove if-block once old OchPort deprecation is complete
+                    org.onosproject.net.OchPort och = (org.onosproject.net.OchPort) port;
+                    return ochPortDescription(ptn, isup, och.signalType(),
+                                              och.isTunable(), och.lambda(), an);
+                }
+                if (port.element().is(OpticalDevice.class)) {
+                    OpticalDevice optDevice = port.element().as(OpticalDevice.class);
+                    if (optDevice.portIs(port, OchPort.class)) {
+                        OchPort och = optDevice.portAs(port, OchPort.class).get();
+                        return ochPortDescription(ptn, isup, och.signalType(),
+                                                  och.isTunable(), och.lambda(), an);
+                    }
+                }
+                return new DefaultPortDescription(ptn, isup, port.type(), port.portSpeed(), an);
+
             case ODUCLT:
                 OduCltPort odu = (OduCltPort) port;
                 return new OduCltPortDescription(ptn, isup, odu.signalType(), an);
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
index 9e31234..bf8152e 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java
@@ -32,7 +32,6 @@
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.CltSignalType;
 import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OduSignalId;
 import org.onosproject.net.OduSignalType;
@@ -60,6 +59,7 @@
 import org.onosproject.net.intent.OpticalCircuitIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.impl.IntentCompilationException;
+import org.onosproject.net.optical.OchPort;
 import org.onosproject.net.intent.IntentSetMultimap;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.Resource;
@@ -82,6 +82,7 @@
 import java.util.stream.Stream;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
 
 /**
  * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
@@ -156,6 +157,7 @@
 
     @Activate
     public void activate(ComponentContext context) {
+        deviceService = opticalView(deviceService);
         appId = coreService.registerApplication("org.onosproject.net.intent");
         intentManager.registerCompiler(OpticalCircuitIntent.class, this);
         cfgService.registerProperties(getClass());
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index d1b5925..b1ca006 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -31,7 +31,6 @@
 import org.onosproject.net.DefaultOchSignalComparator;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OchSignalType;
 import org.onosproject.net.Path;
@@ -43,6 +42,7 @@
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalPathIntent;
 import org.onosproject.net.intent.impl.IntentCompilationException;
+import org.onosproject.net.optical.OchPort;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.Resource;
 import org.onosproject.net.resource.ResourceService;
@@ -63,6 +63,7 @@
 import java.util.stream.Stream;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
 
 /**
  * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
@@ -88,6 +89,7 @@
 
     @Activate
     public void activate() {
+        deviceService = opticalView(deviceService);
         intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
     }
 
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompilerTest.java
index 0cdadb5..9d72cd0 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompilerTest.java
@@ -31,9 +31,9 @@
 import org.onosproject.net.CltSignalType;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DefaultPort;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OduSignalId;
@@ -57,6 +57,8 @@
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MockIdGenerator;
 import org.onosproject.net.intent.OpticalCircuitIntent;
+import org.onosproject.net.optical.OchPort;
+import org.onosproject.net.optical.impl.DefaultOchPort;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.intent.IntentSetMultimap;
 import org.onosproject.net.behaviour.TributarySlotQuery;
@@ -128,11 +130,13 @@
 
     // Och ports with signalType=ODU2
     private static final OchPort D1P2 =
-            new OchPort(device1, PortNumber.portNumber(2), true, OduSignalType.ODU2,
-                    true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1), annotations2);
+            new DefaultOchPort(new DefaultPort(device1, PortNumber.portNumber(2), true, annotations2),
+                               OduSignalType.ODU2,
+                    true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1));
     private static final OchPort D2P2 =
-            new OchPort(device2, PortNumber.portNumber(2), true, OduSignalType.ODU2,
-                    true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1), annotations2);
+            new DefaultOchPort(new DefaultPort(device2, PortNumber.portNumber(2), true, annotations2),
+                               OduSignalType.ODU2,
+                    true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1));
 
     // OduClt ports with signalType=10GBE
     private static final OduCltPort D1P3 =
@@ -169,11 +173,11 @@
             if (deviceId.equals(deviceId(DEV1))) {
                 switch (portNumber.toString()) {
                     case "1":
-                        return (Port) D1P1;
+                        return D1P1;
                     case "2":
-                        return (Port) D1P2;
+                        return D1P2;
                     case "3":
-                        return (Port) D1P3;
+                        return D1P3;
                     default:
                         return null;
                 }
@@ -181,11 +185,11 @@
             if (deviceId.equals(deviceId(DEV2))) {
                 switch (portNumber.toString()) {
                     case "1":
-                        return (Port) D2P1;
+                        return D2P1;
                     case "2":
-                        return (Port) D2P2;
+                        return D2P2;
                     case "3":
-                        return (Port) D2P3;
+                        return D2P3;
                     default:
                         return null;
                 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceDescriptions.java b/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceDescriptions.java
index 4c391ce..2eea2c2 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceDescriptions.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceDescriptions.java
@@ -17,6 +17,7 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.net.DefaultAnnotations.union;
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
 
 import java.util.Collections;
 import java.util.Map;
@@ -111,11 +112,21 @@
                             newDesc.timestamp());
                     break;
                 case OCH:
-                    OchPortDescription ochDesc = (OchPortDescription) (newDesc.value());
-                    newOne = new Timestamped<>(
-                            new OchPortDescription(
-                                    ochDesc, ochDesc.signalType(), ochDesc.isTunable(), ochDesc.lambda(), merged),
-                            newDesc.timestamp());
+                    if (newDesc.value() instanceof OchPortDescription) {
+                        // remove if-block after Och related deprecation is complete
+                        OchPortDescription ochDesc = (OchPortDescription) (newDesc.value());
+                        newOne = new Timestamped<>(
+                                ochPortDescription(ochDesc,
+                                                   ochDesc.signalType(),
+                                                   ochDesc.isTunable(),
+                                                   ochDesc.lambda(), merged),
+                                newDesc.timestamp());
+                    } else {
+                        // same as default case
+                        newOne = new Timestamped<>(
+                                new DefaultPortDescription(newDesc.value(), merged),
+                                newDesc.timestamp());
+                    }
                     break;
                 case ODUCLT:
                     OduCltPortDescription ocDesc = (OduCltPortDescription) (newDesc.value());
diff --git a/core/store/dist/src/main/java/org/onosproject/store/device/impl/ECDeviceStore.java b/core/store/dist/src/main/java/org/onosproject/store/device/impl/ECDeviceStore.java
index 0780859..480e973 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/device/impl/ECDeviceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/device/impl/ECDeviceStore.java
@@ -527,15 +527,21 @@
 
     private Port buildTypedPort(Device device, PortNumber number, boolean isEnabled,
             PortDescription description, Annotations annotations) {
+        // FIXME this switch need to go away once all ports are done.
         switch (description.type()) {
         case OMS:
             OmsPortDescription omsDesc = (OmsPortDescription) description;
             return new OmsPort(device, number, isEnabled, omsDesc.minFrequency(),
                     omsDesc.maxFrequency(), omsDesc.grid(), annotations);
         case OCH:
-            OchPortDescription ochDesc = (OchPortDescription) description;
-            return new OchPort(device, number, isEnabled, ochDesc.signalType(),
-                    ochDesc.isTunable(), ochDesc.lambda(), annotations);
+            if (description instanceof OchPortDescription) {
+                // remove if-block once Och deprecation is complete
+                OchPortDescription ochDesc = (OchPortDescription) description;
+                return new OchPort(device, number, isEnabled, ochDesc.signalType(),
+                                   ochDesc.isTunable(), ochDesc.lambda(), annotations);
+            }
+            return new DefaultPort(device, number, isEnabled, description.type(),
+                                   description.portSpeed(), annotations);
         case ODUCLT:
             OduCltPortDescription oduDesc = (OduCltPortDescription) description;
             return new OduCltPort(device, number, isEnabled, oduDesc.signalType(), annotations);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java b/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
index 5437186..d29b72a 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java
@@ -1085,15 +1085,21 @@
 
     private Port buildTypedPort(Device device, PortNumber number, boolean isEnabled,
                                  PortDescription description, Annotations annotations) {
+        // FIXME this switch need to go away once all ports are done.
         switch (description.type()) {
             case OMS:
                 OmsPortDescription omsDesc = (OmsPortDescription) description;
                 return new OmsPort(device, number, isEnabled, omsDesc.minFrequency(),
                         omsDesc.maxFrequency(), omsDesc.grid(), annotations);
             case OCH:
-                OchPortDescription ochDesc = (OchPortDescription) description;
-                return new OchPort(device, number, isEnabled, ochDesc.signalType(),
-                        ochDesc.isTunable(), ochDesc.lambda(), annotations);
+                if (description instanceof OchPortDescription) {
+                    // remove if-block once Och deprecation is complete
+                    OchPortDescription ochDesc = (OchPortDescription) description;
+                    return new OchPort(device, number, isEnabled, ochDesc.signalType(),
+                                       ochDesc.isTunable(), ochDesc.lambda(), annotations);
+                }
+                return new DefaultPort(device, number, isEnabled, description.type(),
+                                       description.portSpeed(), annotations);
             case ODUCLT:
                 OduCltPortDescription oduDesc = (OduCltPortDescription) description;
                 return new OduCltPort(device, number, isEnabled, oduDesc.signalType(), annotations);
diff --git a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaDriversLoader.java b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaDriversLoader.java
index 60fe881..a1071be 100644
--- a/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaDriversLoader.java
+++ b/drivers/ciena/src/main/java/org/onosproject/drivers/ciena/CienaDriversLoader.java
@@ -18,12 +18,21 @@
 
 import org.apache.felix.scr.annotations.Component;
 import org.onosproject.net.driver.AbstractDriverLoader;
+import org.onosproject.net.optical.OpticalDevice;
+import org.onosproject.net.optical.device.DefaultOpticalDevice;
 
 /**
  * Loader for Ciena device drivers.
  */
 @Component(immediate = true)
 public class CienaDriversLoader extends AbstractDriverLoader {
+
+    // OSGI: help bundle plugin discover runtime package dependency.
+    @SuppressWarnings("unused")
+    private OpticalDevice optical;
+    @SuppressWarnings("unused")
+    private DefaultOpticalDevice driver;
+
     public CienaDriversLoader() {
         super("/ciena-drivers.xml");
     }
diff --git a/drivers/ciena/src/main/resources/ciena-drivers.xml b/drivers/ciena/src/main/resources/ciena-drivers.xml
index f17e01e..f1ab48a 100644
--- a/drivers/ciena/src/main/resources/ciena-drivers.xml
+++ b/drivers/ciena/src/main/resources/ciena-drivers.xml
@@ -18,6 +18,8 @@
     <driver name="restCiena" manufacturer="Ciena" hwVersion="1.0.0" swVersion="1.0.0">
         <behaviour api="org.onosproject.net.behaviour.PortDiscovery"
                    impl="org.onosproject.drivers.ciena.PortDiscoveryCienaWaveserverImpl"/>
+        <behaviour api="org.onosproject.net.optical.OpticalDevice"
+                   impl="org.onosproject.net.optical.device.DefaultOpticalDevice"/>
     </driver>
 </drivers>
 
diff --git a/drivers/default/pom.xml b/drivers/default/pom.xml
index b5b4e4f..844289a 100644
--- a/drivers/default/pom.xml
+++ b/drivers/default/pom.xml
@@ -47,4 +47,23 @@
             <artifactId>openflowj</artifactId>
         </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <niceManifest>true</niceManifest>
+                    <instructions>
+                        <!-- TODO this can be removed once optical package
+                             has been separated out from the default drivers -->
+                        <Import-Package>
+                            *,org.onosproject.net.optical.device
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/drivers/default/src/main/java/org/onosproject/driver/query/DefaultTributarySlotQuery.java b/drivers/default/src/main/java/org/onosproject/driver/query/DefaultTributarySlotQuery.java
index c547bbd..4129fd5 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/query/DefaultTributarySlotQuery.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/query/DefaultTributarySlotQuery.java
@@ -16,7 +16,6 @@
 package org.onosproject.driver.query;
 
 import org.onlab.util.GuavaCollectors;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OduSignalType;
 import org.onosproject.net.OtuPort;
 import org.onosproject.net.OtuSignalType;
@@ -25,10 +24,13 @@
 import org.onosproject.net.TributarySlot;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.optical.OchPort;
 import org.onosproject.net.behaviour.TributarySlotQuery;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
+
 import java.util.Collections;
 import java.util.Set;
 import java.util.stream.IntStream;
@@ -61,12 +63,12 @@
     @Override
     public Set<TributarySlot> queryTributarySlots(PortNumber port) {
         // currently return all slots by default.
-        DeviceService deviceService = this.handler().get(DeviceService.class);
+        DeviceService deviceService = opticalView(this.handler().get(DeviceService.class));
         Port p = deviceService.getPort(this.data().deviceId(), port);
 
         switch (p.type()) {
             case OCH:
-                return queryOchTributarySlots((OchPort) p);
+                return queryOchTributarySlots(p);
             case OTU:
                 return queryOtuTributarySlots((OtuPort) p);
             default:
@@ -74,8 +76,21 @@
         }
     }
 
-    private Set<TributarySlot> queryOchTributarySlots(OchPort ochPort) {
-        OduSignalType signalType = ochPort.signalType();
+    private Set<TributarySlot> queryOchTributarySlots(Port ochPort) {
+        OduSignalType signalType = null;
+        if (ochPort instanceof org.onosproject.net.OchPort) {
+            // remove once deprecation of old OchPort model is done
+            signalType = ((org.onosproject.net.OchPort) ochPort).signalType();
+        }
+        if (ochPort instanceof OchPort) {
+            signalType = ((OchPort) ochPort).signalType();
+        }
+
+        if (signalType == null) {
+            log.warn("{} was not an OchPort", ochPort);
+            return Collections.emptySet();
+        }
+
         switch (signalType) {
             case ODU2:
                 return ENTIRE_ODU2_TRIBUTARY_SLOTS;
diff --git a/drivers/default/src/main/resources/onos-drivers.xml b/drivers/default/src/main/resources/onos-drivers.xml
index 1503a16..a8e72ca 100644
--- a/drivers/default/src/main/resources/onos-drivers.xml
+++ b/drivers/default/src/main/resources/onos-drivers.xml
@@ -61,6 +61,8 @@
                    impl="org.onosproject.driver.handshaker.OfOpticalSwitchImplLinc13"/>
         <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
                    impl="org.onosproject.driver.query.LincOELambdaQuery"/>
+        <behaviour api="org.onosproject.net.optical.OpticalDevice"
+                   impl="org.onosproject.net.optical.device.DefaultOpticalDevice"/>
     </driver>
     <driver name="ofdpa" extends="default"
             manufacturer="Broadcom Corp." hwVersion="OF-DPA.*" swVersion="OF-DPA.*">
@@ -165,6 +167,8 @@
                    impl="org.onosproject.driver.query.DefaultTributarySlotQuery" />
         <behaviour api="org.onosproject.net.behaviour.LambdaQuery"
                    impl="org.onosproject.driver.query.OFOpticalSwitch13LambdaQuery"/>
+        <behaviour api="org.onosproject.net.optical.OpticalDevice"
+                   impl="org.onosproject.net.optical.device.DefaultOpticalDevice"/>
     </driver>
     <driver name="aos" extends="ofdpa"
             manufacturer="Accton" hwVersion=".*" swVersion="1.*">
@@ -179,6 +183,8 @@
             swVersion="of-agent">
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
                    impl="org.onosproject.driver.handshaker.OplinkRoadmHandshaker"/>
+        <behaviour api="org.onosproject.net.optical.OpticalDevice"
+                   impl="org.onosproject.net.optical.device.DefaultOpticalDevice"/>
     </driver>
     <driver name="hp" extends="default"
             manufacturer="HP" hwVersion="Switch 3500yl-48G" swVersion="K.16.01.0004">
diff --git a/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuDriversLoader.java b/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuDriversLoader.java
index b444eca..3ec1d20 100644
--- a/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuDriversLoader.java
+++ b/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuDriversLoader.java
@@ -18,12 +18,21 @@
 
 import org.apache.felix.scr.annotations.Component;
 import org.onosproject.net.driver.AbstractDriverLoader;
+import org.onosproject.net.optical.OpticalDevice;
+import org.onosproject.net.optical.device.DefaultOpticalDevice;
 
 /**
  * Loader for Fujitsu device drivers.
  */
 @Component(immediate = true)
 public class FujitsuDriversLoader extends AbstractDriverLoader {
+
+    // OSGI: help bundle plugin discover runtime package dependency.
+    @SuppressWarnings("unused")
+    private OpticalDevice optical;
+    @SuppressWarnings("unused")
+    private DefaultOpticalDevice driver;
+
     public FujitsuDriversLoader() {
         super("/fujitsu-drivers.xml");
     }
diff --git a/drivers/fujitsu/src/main/resources/fujitsu-drivers.xml b/drivers/fujitsu/src/main/resources/fujitsu-drivers.xml
index 66c8458..c328cf2 100644
--- a/drivers/fujitsu/src/main/resources/fujitsu-drivers.xml
+++ b/drivers/fujitsu/src/main/resources/fujitsu-drivers.xml
@@ -18,6 +18,8 @@
     <driver name="fujitsu-netconf" manufacturer="Fujitsu" hwVersion="T100" swVersion="01-01-X">
         <behaviour api="org.onosproject.net.behaviour.PortDiscovery"
                    impl="org.onosproject.drivers.fujitsu.PortGetterFujitsuImpl"/>
+        <behaviour api="org.onosproject.net.optical.OpticalDevice"
+                   impl="org.onosproject.net.optical.device.DefaultOpticalDevice"/>
     </driver>
 </drivers>
 
diff --git a/drivers/utilities/src/main/java/org/onosproject/drivers/utilities/XmlConfigParser.java b/drivers/utilities/src/main/java/org/onosproject/drivers/utilities/XmlConfigParser.java
index ff9631e..dd46629 100644
--- a/drivers/utilities/src/main/java/org/onosproject/drivers/utilities/XmlConfigParser.java
+++ b/drivers/utilities/src/main/java/org/onosproject/drivers/utilities/XmlConfigParser.java
@@ -32,12 +32,13 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.SparseAnnotations;
 import org.onosproject.net.behaviour.ControllerInfo;
-import org.onosproject.net.device.OchPortDescription;
 import org.onosproject.net.device.OduCltPortDescription;
 import org.onosproject.net.device.PortDescription;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
+
 import java.io.InputStream;
 import java.io.StringWriter;
 import java.util.ArrayList;
@@ -104,7 +105,7 @@
         return portDescriptions;
     }
 
-    private static OchPortDescription parseT100OchPort(HierarchicalConfiguration cfg, long count) {
+    private static PortDescription parseT100OchPort(HierarchicalConfiguration cfg, long count) {
         PortNumber portNumber = PortNumber.portNumber(count);
         HierarchicalConfiguration otuConfig = cfg.configurationAt("otu");
         boolean enabled = otuConfig.getString("administrative-state").equals("up");
@@ -115,7 +116,7 @@
         DefaultAnnotations annotations = DefaultAnnotations.builder().
                 set(AnnotationKeys.PORT_NAME, cfg.getString("name")).
                 build();
-        return new OchPortDescription(portNumber, enabled, signalType, isTunable, lambda, annotations);
+        return ochPortDescription(portNumber, enabled, signalType, isTunable, lambda, annotations);
     }
 
     private static OduCltPortDescription parseT100OduPort(HierarchicalConfiguration cfg, long count) {
@@ -213,7 +214,7 @@
         int spacingMult = (int) (toGbps((Integer.parseInt(config.getString(frequencyPath)) -
                 baseFrequency)) / toGbpsFromHz(chSpacing.frequency().asHz())); //FIXME is there a better way ?
 
-        return new OchPortDescription(PortNumber.portNumber(portNumber), isEnabled, oduSignalType, isTunable,
+        return ochPortDescription(PortNumber.portNumber(portNumber), isEnabled, oduSignalType, isTunable,
                                       new OchSignal(gridType, chSpacing, spacingMult, 1), annotations);
     }
 
diff --git a/pom.xml b/pom.xml
index 8ed1665..6e83f13 100644
--- a/pom.xml
+++ b/pom.xml
@@ -650,6 +650,9 @@
                     <artifactId>maven-bundle-plugin</artifactId>
                     <version>3.0.1</version>
                     <extensions>true</extensions>
+                    <configuration>
+                        <niceManifest>true</niceManifest>
+                    </configuration>
                 </plugin>
 
                 <plugin>
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index bdff790..d92d540 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -15,10 +15,24 @@
  */
 package org.onosproject.provider.of.device.impl;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Port.Type.COPPER;
+import static org.onosproject.net.Port.Type.FIBER;
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
+import static org.onosproject.openflow.controller.Dpid.dpid;
+import static org.onosproject.openflow.controller.Dpid.uri;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -52,7 +66,6 @@
 import org.onosproject.net.device.DeviceProvider;
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
-import org.onosproject.net.device.OchPortDescription;
 import org.onosproject.net.device.OduCltPortDescription;
 import org.onosproject.net.device.OmsPortDescription;
 import org.onosproject.net.device.OtuPortDescription;
@@ -101,23 +114,10 @@
 import org.projectfloodlight.openflow.types.PortSpeed;
 import org.slf4j.Logger;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onlab.util.Tools.get;
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.Port.Type.COPPER;
-import static org.onosproject.net.Port.Type.FIBER;
-import static org.onosproject.openflow.controller.Dpid.dpid;
-import static org.onosproject.openflow.controller.Dpid.uri;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 /**
  * Provider which uses an OpenFlow controller to detect network
@@ -579,7 +579,7 @@
             OFExpPortDescPropOpticalTransport firstProp = port.getProperties().get(0);
             OFPortOpticalTransportSignalType sigType = firstProp.getPortSignalType();
 
-            DefaultPortDescription portDes = null;
+            PortDescription portDes = null;
             switch (sigType) {
             case OMSN:
                 portDes =  new OmsPortDescription(portNo, enabled,
@@ -600,8 +600,9 @@
                 //yet not relevant for tunable OCH port, creating with default parameters
                 OchSignal signalId = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 1, 1);
 
-                portDes = new OchPortDescription(portNo, enabled,
-                        oduSignalType, true, signalId, annotations);
+                portDes = ochPortDescription(portNo, enabled,
+                                             oduSignalType, true,
+                                             signalId, annotations);
 
                 break;
             case OTU2:
@@ -706,7 +707,7 @@
                             Spectrum.U_BAND_MIN, Spectrum.O_BAND_MAX, Frequency.ofGHz(50), annotations);
                 case 5:     // OCH port
                     OchSignal signal = new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 0, 4);
-                    return new OchPortDescription(portNo, enabled, OduSignalType.ODU4,
+                    return ochPortDescription(portNo, enabled, OduSignalType.ODU4,
                             true, signal, annotations);
                 default:
                     break;
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java b/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java
index 5ecf225..46e546f 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/ConfigProvider.java
@@ -38,7 +38,6 @@
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.Link;
 import org.onosproject.net.MastershipRole;
-import org.onosproject.net.OchPort;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OduCltPort;
 import org.onosproject.net.OduSignalType;
@@ -55,7 +54,6 @@
 import org.onosproject.net.device.DeviceProviderRegistry;
 import org.onosproject.net.device.DeviceProviderService;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.device.OchPortDescription;
 import org.onosproject.net.device.OduCltPortDescription;
 import org.onosproject.net.device.OmsPortDescription;
 import org.onosproject.net.device.PortDescription;
@@ -67,6 +65,7 @@
 import org.onosproject.net.link.LinkProvider;
 import org.onosproject.net.link.LinkProviderRegistry;
 import org.onosproject.net.link.LinkProviderService;
+import org.onosproject.net.optical.OchPort;
 import org.onosproject.net.provider.ProviderId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -88,6 +87,8 @@
 import static org.onosproject.net.PortNumber.portNumber;
 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
+import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
 
 /**
  * Provider of devices and links parsed from a JSON configuration structure.
@@ -139,7 +140,7 @@
                    LinkProviderRegistry linkProviderRegistry,
                    HostProviderRegistry hostProviderRegistry) {
         this.cfg = checkNotNull(cfg, "Configuration cannot be null");
-        this.deviceService = checkNotNull(deviceService, "Device service cannot be null");
+        this.deviceService = opticalView(checkNotNull(deviceService, "Device service cannot be null"));
         this.deviceProviderRegistry = checkNotNull(deviceProviderRegistry, "Device provider registry cannot be null");
         this.linkProviderRegistry = checkNotNull(linkProviderRegistry, "Link provider registry cannot be null");
         this.hostProviderRegistry = checkNotNull(hostProviderRegistry, "Host provider registry cannot be null");
@@ -269,7 +270,7 @@
             case OCH:
                 annotations = annotations(node.get("annotations"));
                 OchPort ochPort = (OchPort) deviceService.getPort(deviceId, port);
-                return new OchPortDescription(port, node.path("enabled").asBoolean(true),
+                return ochPortDescription(port, node.path("enabled").asBoolean(true),
                         ochPort.signalType(), ochPort.isTunable(),
                         ochPort.lambda(), annotations);
             case OMS:
@@ -363,13 +364,13 @@
         }
         OchSignal signal = new OchSignal(GridType.DWDM, chsp, 1, 1);
         if (src.type() == Device.Type.ROADM) {
-            PortDescription portDesc = new OchPortDescription(srcCp.port(), true,
+            PortDescription portDesc = ochPortDescription(srcCp.port(), true,
                     OduSignalType.ODU4, true, signal);
             descriptions.put(srcCp, portDesc);
             deviceProviderService.portStatusChanged(srcCp.deviceId(), portDesc);
         }
         if (dst.type() == Device.Type.ROADM) {
-            PortDescription portDesc = new OchPortDescription(dstCp.port(), true,
+            PortDescription portDesc = ochPortDescription(dstCp.port(), true,
                     OduSignalType.ODU4, true, signal);
             descriptions.put(dstCp, portDesc);
             deviceProviderService.portStatusChanged(dstCp.deviceId(), portDesc);
@@ -482,7 +483,7 @@
                         op.number(), op.isEnabled(), op.minFrequency(), op.maxFrequency(), op.grid());
             case OCH:
                 OchPort ochp = (OchPort) p;
-                return new OchPortDescription(
+                return ochPortDescription(
                         ochp.number(), ochp.isEnabled(), ochp.signalType(), ochp.isTunable(), ochp.lambda());
             case ODUCLT:
                 OduCltPort odup = (OduCltPort) p;