blob: 88ef950058db87a69fa83c163c963f095c7ff1c0 [file] [log] [blame]
HIGUCHI Yuta34a3f692016-01-09 21:08:57 -08001/*
Brian O'Connor0a4e6742016-09-15 23:03:10 -07002 * Copyright 2016-present Open Networking Laboratory
HIGUCHI Yuta34a3f692016-01-09 21:08:57 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net.optical.device;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.List;
21import java.util.Map;
22import java.util.Optional;
23
24import org.onosproject.net.device.DeviceEvent;
25import org.onosproject.net.device.DeviceListener;
26import org.onosproject.net.device.DeviceService;
Viswanath KSP22774cd2016-08-20 20:06:30 +053027import org.onosproject.net.device.PortStatistics;
HIGUCHI Yuta34a3f692016-01-09 21:08:57 -080028import org.onosproject.net.optical.OpticalDevice;
HIGUCHI Yutaf46dc4f2016-05-13 11:24:13 -070029import org.onosproject.net.utils.ForwardingDeviceService;
HIGUCHI Yuta34a3f692016-01-09 21:08:57 -080030import org.slf4j.Logger;
31
32import com.google.common.annotations.Beta;
33import com.google.common.cache.CacheBuilder;
34import com.google.common.cache.CacheLoader;
35import com.google.common.cache.LoadingCache;
36import com.google.common.collect.Lists;
37import com.google.common.collect.Maps;
38
39import org.apache.commons.lang3.tuple.Pair;
40import org.onosproject.net.DeviceId;
41import org.onosproject.net.Element;
42import org.onosproject.net.Port;
43import org.onosproject.net.PortNumber;
44
45
46// TODO replace places using DeviceService expecting Optical specific ports.
47// with this
48
49/**
50 * Decorator, which provides a DeviceService view, which returns
51 * Ports in optical specific ports.
52 */
53@Beta
54public class OpticalDeviceServiceView
55 extends ForwardingDeviceService
56 implements DeviceService {
57
58 private static final Logger log = getLogger(OpticalDeviceServiceView.class);
59
60 /**
61 * DeviceListener to wrapped DeviceListener map.
62 * <p>
63 * {@literal original listener -> wrapped listener}
64 */
65 private final Map<DeviceListener, DeviceListener> wrapped = Maps.newIdentityHashMap();
66
67 // May need a way to monitor Drivers loaded on ONOS and
68 // invalidate this Cache if a driver was added/updated
69 /**
70 * Device to {@link OpticalDevice} map cache.
71 */
72 private final LoadingCache<Element, Optional<OpticalDevice>> optdev
73 = CacheBuilder.newBuilder()
74 .weakKeys() // == for Key comparison
75 .maximumSize(100)
76 .build(CacheLoader.from(elm -> {
77 if (elm.is(OpticalDevice.class)) {
78 return Optional.of(elm.as(OpticalDevice.class));
79 } else {
80 return Optional.empty();
81 }
82 }));
83
84 // Not intended to be instantiated directly
85 protected OpticalDeviceServiceView(DeviceService base) {
86 super(base);
87 }
88
89 /**
90 * Wraps the given DeviceService to provide a view,
91 * which returns port as optical specific Port class.
92 *
93 * @param base {@link DeviceService} view to use as baseline.
94 * @return Decorated view of {@code base}
95 */
96 public static OpticalDeviceServiceView opticalView(DeviceService base) {
97 // TODO might make sense to track and assign an instance for each `base`
98 return new OpticalDeviceServiceView(base);
99 }
100
101 /**
102 * Transform Port instance on the event to Optical specific port, if it is well-formed.
103 *
104 * @param event original event to transform
105 * @return transformed {@link DeviceEvent}
106 */
107 public DeviceEvent augment(DeviceEvent event) {
108 final Port port = augment(event.port());
109 if (port == event.port()) {
110 // If the Port not changed, pass through
111 return event;
112 }
113 return new DeviceEvent(event.type(), event.subject(), port, event.time());
114 }
115
116 /**
117 * Transform Port instance to Optical specific port, if it is well-formed.
118 *
119 * @param port Port instance to translate
120 * @return Optical specific port instance or original {@code port}.
121 */
122 public Port augment(Port port) {
123 if (port == null) {
124 return null;
125 }
126 return optdev.getUnchecked(port.element())
127 .map(odev -> odev.port(port))
128 .orElse(port);
129 }
130
131 @Override
132 public void addListener(DeviceListener listener) {
133 super.addListener(wrapped.computeIfAbsent(listener, OpticalDeviceListener::new));
134 }
135
136 @Override
137 public void removeListener(DeviceListener listener) {
138 DeviceListener wrappedListener = wrapped.remove(listener);
139 if (wrappedListener != null) {
140 super.removeListener(wrappedListener);
141 }
142 }
143
144
145 @Override
146 public List<Port> getPorts(DeviceId deviceId) {
147 return Lists.transform(super.getPorts(deviceId),
148 this::augment);
149 }
150
151 @Override
Viswanath KSP22774cd2016-08-20 20:06:30 +0530152 public PortStatistics getStatisticsForPort(DeviceId deviceId, PortNumber portNumber) {
153 return null;
154 }
155
156 @Override
157 public PortStatistics getDeltaStatisticsForPort(DeviceId deviceId, PortNumber portNumber) {
158 return null;
159 }
160
161 @Override
HIGUCHI Yuta34a3f692016-01-09 21:08:57 -0800162 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
163 return augment(super.getPort(deviceId, portNumber));
164 }
165
166
167 /**
168 * DeviceListener, which translates generic Port to optical specific Port
169 * before passing.
170 */
171 class OpticalDeviceListener implements DeviceListener {
172
173 private final DeviceListener listener;
174
175 // shallow cache to reuse transformed event in isRelevant and event call
176 private Pair<DeviceEvent, DeviceEvent> cache;
177
178 public OpticalDeviceListener(DeviceListener listener) {
179 this.listener = listener;
180 }
181
182 private DeviceEvent opticalEvent(DeviceEvent event) {
183
184 Pair<DeviceEvent, DeviceEvent> entry = cache;
185 if (entry != null && entry.getLeft() == event) {
186 return entry.getRight();
187 }
188
189 DeviceEvent opticalEvent = augment(event);
190 cache = Pair.of(event, opticalEvent);
191 return opticalEvent;
192 }
193
194 @Override
195 public boolean isRelevant(DeviceEvent event) {
196 return listener.isRelevant(opticalEvent(event));
197 }
198
199 @Override
200 public void event(DeviceEvent event) {
201 listener.event(opticalEvent(event));
202 }
203 }
204
205}