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/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;