blob: 25ff4fe639f8170345c2882ba7078e8673d2f4bd [file] [log] [blame]
alshabib1d2bc402015-07-31 17:04:11 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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.incubator.net.meter.impl;
17
alshabib70aaa1b2015-09-25 14:30:59 -070018import com.google.common.collect.Maps;
alshabib1d2bc402015-07-31 17:04:11 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
alshabibeadfc8e2015-08-18 15:40:46 -070025import org.onlab.util.TriConsumer;
Jian Li1932b932016-01-03 00:35:40 -080026import org.onosproject.net.DeviceId;
alshabib10c810b2015-08-18 16:59:04 -070027import org.onosproject.net.meter.DefaultMeter;
28import org.onosproject.net.meter.Meter;
29import org.onosproject.net.meter.MeterEvent;
30import org.onosproject.net.meter.MeterFailReason;
31import org.onosproject.net.meter.MeterId;
alshabib70aaa1b2015-09-25 14:30:59 -070032import org.onosproject.net.meter.MeterKey;
alshabib10c810b2015-08-18 16:59:04 -070033import org.onosproject.net.meter.MeterListener;
34import org.onosproject.net.meter.MeterOperation;
35import org.onosproject.net.meter.MeterProvider;
36import org.onosproject.net.meter.MeterProviderRegistry;
37import org.onosproject.net.meter.MeterProviderService;
alshabibe1248b62015-08-20 17:21:55 -070038import org.onosproject.net.meter.MeterRequest;
alshabib10c810b2015-08-18 16:59:04 -070039import org.onosproject.net.meter.MeterService;
40import org.onosproject.net.meter.MeterState;
41import org.onosproject.net.meter.MeterStore;
42import org.onosproject.net.meter.MeterStoreDelegate;
43import org.onosproject.net.meter.MeterStoreResult;
alshabib1d2bc402015-07-31 17:04:11 -070044import org.onosproject.net.provider.AbstractListenerProviderRegistry;
45import org.onosproject.net.provider.AbstractProviderService;
46import org.onosproject.store.service.AtomicCounter;
47import org.onosproject.store.service.StorageService;
48import org.slf4j.Logger;
49
50import java.util.Collection;
alshabib5eb79392015-08-19 18:09:55 -070051import java.util.Map;
52import java.util.stream.Collectors;
alshabib1d2bc402015-07-31 17:04:11 -070053
54import static org.slf4j.LoggerFactory.getLogger;
55
alshabib1d2bc402015-07-31 17:04:11 -070056/**
57 * Provides implementation of the meter service APIs.
58 */
alshabib58fe6dc2015-08-19 17:16:13 -070059@Component(immediate = true, enabled = true)
alshabib1d2bc402015-07-31 17:04:11 -070060@Service
61public class MeterManager extends AbstractListenerProviderRegistry<MeterEvent, MeterListener,
62 MeterProvider, MeterProviderService>
63 implements MeterService, MeterProviderRegistry {
64
alshabib70aaa1b2015-09-25 14:30:59 -070065 private static final String METERCOUNTERIDENTIFIER = "meter-id-counter-%s";
alshabib1d2bc402015-07-31 17:04:11 -070066 private final Logger log = getLogger(getClass());
67 private final MeterStoreDelegate delegate = new InternalMeterStoreDelegate();
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected StorageService storageService;
71
alshabib7bb05012015-08-05 10:15:09 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib58fe6dc2015-08-19 17:16:13 -070073 protected MeterStore store;
alshabib7bb05012015-08-05 10:15:09 -070074
alshabib70aaa1b2015-09-25 14:30:59 -070075 private Map<DeviceId, AtomicCounter> meterIdCounters
76 = Maps.newConcurrentMap();
alshabib1d2bc402015-07-31 17:04:11 -070077
alshabibe1248b62015-08-20 17:21:55 -070078 private TriConsumer<MeterRequest, MeterStoreResult, Throwable> onComplete;
alshabibeadfc8e2015-08-18 15:40:46 -070079
alshabib1d2bc402015-07-31 17:04:11 -070080 @Activate
81 public void activate() {
alshabibeadfc8e2015-08-18 15:40:46 -070082
alshabib58fe6dc2015-08-19 17:16:13 -070083 store.setDelegate(delegate);
84
alshabibe1248b62015-08-20 17:21:55 -070085 onComplete = (request, result, error) ->
alshabibeadfc8e2015-08-18 15:40:46 -070086 {
alshabibe1248b62015-08-20 17:21:55 -070087 request.context().ifPresent(c -> {
alshabibeadfc8e2015-08-18 15:40:46 -070088 if (error != null) {
alshabibe1248b62015-08-20 17:21:55 -070089 c.onError(request, MeterFailReason.UNKNOWN);
alshabibeadfc8e2015-08-18 15:40:46 -070090 } else {
91 if (result.reason().isPresent()) {
alshabibe1248b62015-08-20 17:21:55 -070092 c.onError(request, result.reason().get());
alshabibeadfc8e2015-08-18 15:40:46 -070093 } else {
alshabibe1248b62015-08-20 17:21:55 -070094 c.onSuccess(request);
alshabibeadfc8e2015-08-18 15:40:46 -070095 }
96 }
97 });
98
99 };
alshabib1d2bc402015-07-31 17:04:11 -0700100 log.info("Started");
101 }
102
103 @Deactivate
104 public void deactivate() {
alshabib58fe6dc2015-08-19 17:16:13 -0700105 store.unsetDelegate(delegate);
alshabib1d2bc402015-07-31 17:04:11 -0700106 log.info("Stopped");
107 }
108
109 @Override
110 protected MeterProviderService createProviderService(MeterProvider provider) {
111 return new InternalMeterProviderService(provider);
112 }
113
114 @Override
alshabibe1248b62015-08-20 17:21:55 -0700115 public Meter submit(MeterRequest request) {
116
alshabib70aaa1b2015-09-25 14:30:59 -0700117 MeterId id = allocateMeterId(request.deviceId());
118
alshabibe1248b62015-08-20 17:21:55 -0700119 Meter.Builder mBuilder = DefaultMeter.builder()
120 .forDevice(request.deviceId())
121 .fromApp(request.appId())
122 .withBands(request.bands())
alshabib70aaa1b2015-09-25 14:30:59 -0700123 .withId(id)
alshabibe1248b62015-08-20 17:21:55 -0700124 .withUnit(request.unit());
125
126 if (request.isBurst()) {
127 mBuilder.burst();
128 }
129 DefaultMeter m = (DefaultMeter) mBuilder.build();
alshabib7bb05012015-08-05 10:15:09 -0700130 m.setState(MeterState.PENDING_ADD);
alshabibeadfc8e2015-08-18 15:40:46 -0700131 store.storeMeter(m).whenComplete((result, error) ->
alshabibe1248b62015-08-20 17:21:55 -0700132 onComplete.accept(request, result, error));
133 return m;
alshabib1d2bc402015-07-31 17:04:11 -0700134 }
135
136 @Override
alshabibe1248b62015-08-20 17:21:55 -0700137 public void withdraw(MeterRequest request, MeterId meterId) {
138 Meter.Builder mBuilder = DefaultMeter.builder()
139 .forDevice(request.deviceId())
140 .fromApp(request.appId())
141 .withBands(request.bands())
142 .withId(meterId)
143 .withUnit(request.unit());
alshabib1d2bc402015-07-31 17:04:11 -0700144
alshabibe1248b62015-08-20 17:21:55 -0700145 if (request.isBurst()) {
146 mBuilder.burst();
147 }
148
149 DefaultMeter m = (DefaultMeter) mBuilder.build();
alshabib7bb05012015-08-05 10:15:09 -0700150 m.setState(MeterState.PENDING_REMOVE);
alshabibeadfc8e2015-08-18 15:40:46 -0700151 store.deleteMeter(m).whenComplete((result, error) ->
alshabibe1248b62015-08-20 17:21:55 -0700152 onComplete.accept(request, result, error));
alshabib1d2bc402015-07-31 17:04:11 -0700153 }
154
155 @Override
alshabib70aaa1b2015-09-25 14:30:59 -0700156 public Meter getMeter(DeviceId deviceId, MeterId id) {
157 MeterKey key = MeterKey.key(deviceId, id);
158 return store.getMeter(key);
alshabib1d2bc402015-07-31 17:04:11 -0700159 }
160
161 @Override
Jian Li1932b932016-01-03 00:35:40 -0800162 public Collection<Meter> getMeters(DeviceId deviceId) {
163 return store.getAllMeters().stream().filter(m ->
164 m.deviceId().equals(deviceId)).collect(Collectors.toList());
165 }
166
167 @Override
alshabib58fe6dc2015-08-19 17:16:13 -0700168 public Collection<Meter> getAllMeters() {
169 return store.getAllMeters();
170 }
171
alshabib70aaa1b2015-09-25 14:30:59 -0700172 private MeterId allocateMeterId(DeviceId deviceId) {
173 long id = meterIdCounters.compute(deviceId, (k, v) -> {
174 if (v == null) {
175 return allocateCounter(k);
176 }
177 return v;
178 }).incrementAndGet();
179
180 return MeterId.meterId((int) id);
181 }
182
183 private AtomicCounter allocateCounter(DeviceId deviceId) {
184 return storageService.atomicCounterBuilder()
185 .withName(String.format(METERCOUNTERIDENTIFIER, deviceId))
Madan Jampanie17d3282016-02-03 15:30:57 -0800186 .build()
187 .asAtomicCounter();
alshabib1d2bc402015-07-31 17:04:11 -0700188 }
189
190 private class InternalMeterProviderService
191 extends AbstractProviderService<MeterProvider>
192 implements MeterProviderService {
193
194 /**
195 * Creates a provider service on behalf of the specified provider.
196 *
197 * @param provider provider to which this service is being issued
198 */
199 protected InternalMeterProviderService(MeterProvider provider) {
200 super(provider);
201 }
202
203 @Override
alshabib7bb05012015-08-05 10:15:09 -0700204 public void meterOperationFailed(MeterOperation operation,
205 MeterFailReason reason) {
206 store.failedMeter(operation, reason);
alshabib1d2bc402015-07-31 17:04:11 -0700207 }
208
209 @Override
210 public void pushMeterMetrics(DeviceId deviceId, Collection<Meter> meterEntries) {
alshabib5eb79392015-08-19 18:09:55 -0700211 //FIXME: FOLLOWING CODE CANNOT BE TESTED UNTIL SOMETHING THAT
212 //FIXME: IMPLEMENTS METERS EXISTS
213 Map<MeterId, Meter> storedMeterMap = store.getAllMeters().stream()
214 .collect(Collectors.toMap(Meter::id, m -> m));
215
216 meterEntries.stream()
217 .filter(m -> storedMeterMap.remove(m.id()) != null)
218 .forEach(m -> store.updateMeterState(m));
219
220 storedMeterMap.values().stream().forEach(m -> {
221 if (m.state() == MeterState.PENDING_ADD) {
222 provider().performMeterOperation(m.deviceId(),
223 new MeterOperation(m,
alshabibe1248b62015-08-20 17:21:55 -0700224 MeterOperation.Type.ADD));
alshabib5eb79392015-08-19 18:09:55 -0700225 } else {
226 store.deleteMeterNow(m);
227 }
228 });
alshabib1d2bc402015-07-31 17:04:11 -0700229 }
230 }
231
232 private class InternalMeterStoreDelegate implements MeterStoreDelegate {
233
234 @Override
235 public void notify(MeterEvent event) {
alshabibeadfc8e2015-08-18 15:40:46 -0700236 DeviceId deviceId = event.subject().deviceId();
237 MeterProvider p = getProvider(event.subject().deviceId());
alshabib7bb05012015-08-05 10:15:09 -0700238 switch (event.type()) {
alshabibeadfc8e2015-08-18 15:40:46 -0700239 case METER_ADD_REQ:
240 p.performMeterOperation(deviceId, new MeterOperation(event.subject(),
alshabibe1248b62015-08-20 17:21:55 -0700241 MeterOperation.Type.ADD));
alshabib7bb05012015-08-05 10:15:09 -0700242 break;
alshabibeadfc8e2015-08-18 15:40:46 -0700243 case METER_REM_REQ:
244 p.performMeterOperation(deviceId, new MeterOperation(event.subject(),
alshabibe1248b62015-08-20 17:21:55 -0700245 MeterOperation.Type.REMOVE));
alshabib7bb05012015-08-05 10:15:09 -0700246 break;
247 default:
248 log.warn("Unknown meter event {}", event.type());
249 }
alshabib1d2bc402015-07-31 17:04:11 -0700250
251 }
252 }
253
254}