making service for PolicyResolver and EndpointRpcRegistry
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / endpoint / EndpointRpcRegistry.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.endpoint;
10
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.ConcurrentMap;
15 import java.util.concurrent.Future;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentation;
24 import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentationRegistry;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointsBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.SetEndpointGroupConditionsInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnsetEndpointGroupConditionsInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.ConditionMapping;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.ConditionMappingKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.has.endpoint.group.conditions.EndpointGroupCondition;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.has.endpoint.group.conditions.EndpointGroupConditionKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
49 import org.opendaylight.yangtools.yang.binding.Augmentation;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.google.common.base.Function;
58 import com.google.common.util.concurrent.CheckedFuture;
59 import com.google.common.util.concurrent.FutureCallback;
60 import com.google.common.util.concurrent.Futures;
61 import com.google.common.util.concurrent.ListenableFuture;
62
63 /**
64  * Endpoint registry provides a scalable store for accessing and updating
65  * information about endpoints.
66  */
67 public class EndpointRpcRegistry implements EndpointService, EpRendererAugmentationRegistry, AutoCloseable {
68     private static final Logger LOG =
69             LoggerFactory.getLogger(EndpointRpcRegistry.class);
70
71     private final DataBroker dataProvider;
72     private final RpcProviderRegistry rpcRegistry;
73
74     private final BindingAwareBroker.RpcRegistration<EndpointService> rpcRegistration;
75
76     final static ConcurrentMap<String, EpRendererAugmentation> registeredRenderers = new ConcurrentHashMap<String, EpRendererAugmentation>();
77
78     /**
79      * This method registers a renderer for endpoint RPC API. This method
80      * ensures single RPC registration for all renderers since a single RPC
81      * registration is only allowed.
82      *
83      * @param epRendererAugmentation
84      *            - specific implementation RPC augmentation, if any. Otherwise
85      *            NULL
86      */
87     @Override
88     public void register(EpRendererAugmentation epRendererAugmentation) {
89         if (epRendererAugmentation != null) {
90             registeredRenderers.putIfAbsent(epRendererAugmentation.getClass().getName(), epRendererAugmentation);
91             LOG.info("Registered {}", epRendererAugmentation.getClass().getName());
92         }
93     }
94
95     /**
96      *
97      * @param regImp the endpoint augmentation
98      */
99     @Override
100     public void unregister(EpRendererAugmentation regImp) {
101         if (regImp == null || !registeredRenderers.containsKey(regImp.getClass().getName())) {
102             return;
103         }
104         registeredRenderers.remove(regImp.getClass().getName());
105         LOG.info("Unregistered {}", regImp.getClass().getName());
106     }
107
108     /**
109      * Constructor
110      *
111      * @param dataProvider the {@link DataBroker}
112      * @param rpcRegistry  the {@link RpcProviderRegistry}
113      */
114     public EndpointRpcRegistry(DataBroker dataProvider, RpcProviderRegistry rpcRegistry) {
115         this.dataProvider = dataProvider;
116         this.rpcRegistry = rpcRegistry;
117         if (this.rpcRegistry != null) {
118             rpcRegistration =
119                     this.rpcRegistry.addRpcImplementation(EndpointService.class, this);
120             LOG.debug("Added RPC Implementation Correctly");
121         } else {
122             rpcRegistration = null;
123         }
124
125         if (dataProvider != null) {
126             InstanceIdentifier<Endpoints> iid =
127                     InstanceIdentifier.builder(Endpoints.class).build();
128             WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
129             t.put(LogicalDatastoreType.OPERATIONAL,
130                     iid, new EndpointsBuilder().build());
131             CheckedFuture<Void, TransactionCommitFailedException> f = t.submit();
132             Futures.addCallback(f, new FutureCallback<Void>() {
133                 @Override
134                 public void onFailure(Throwable t) {
135                     LOG.error("Could not write endpoint base container", t);
136                 }
137
138                 @Override
139                 public void onSuccess(Void result) {
140
141                 }
142             });
143         }
144
145         // TODO Be alagalah - age out endpoint data and remove
146         // endpoint group/condition mappings with no conditions
147     }
148
149     @Override
150     public void close() throws Exception {
151         if (rpcRegistration != null) {
152             rpcRegistration.close();
153         }
154     }
155
156     /**
157      * Construct an endpoint with the appropriate augmentations from the
158      * endpoint input. Each concrete implementation can provides its specifics
159      * earlier.
160      *
161      * @param input
162      *            the input object
163      */
164     private EndpointBuilder buildEndpoint(RegisterEndpointInput input) {
165         EndpointBuilder eb = new EndpointBuilder(input);
166         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
167                 .entrySet()) {
168             try {
169                 Map.Entry<Class<? extends Augmentation<Endpoint>>, Augmentation<Endpoint>> augmentationEntry =
170                         entry.getValue().buildEndpointAugmentation(input);
171                 if (augmentationEntry != null) {
172                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
173                 }
174             } catch (Exception e) {
175                 LOG.warn("Endpoint Augmentation error while processing "
176                         + entry.getKey() + ". Reason: ", e);
177             }
178         }
179         return eb;
180     }
181
182     /**
183      * Construct an L3 endpoint with the appropriate augmentations from the
184      * endpoint input. Each concrete implementation can provides its specifics
185      * earlier.
186      *
187      * @param input
188      *            the input object
189      */
190     private EndpointL3Builder buildEndpointL3(RegisterEndpointInput input) {
191         EndpointL3Builder eb = new EndpointL3Builder(input);
192         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
193                 .entrySet()) {
194             try {
195                 Map.Entry<Class<? extends Augmentation<EndpointL3>>, Augmentation<EndpointL3>> augmentationEntry =
196                         entry.getValue().buildEndpointL3Augmentation(input);
197                 if (augmentationEntry != null) {
198                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
199                 }
200             } catch (Exception e) {
201                 LOG.warn("L3 endpoint Augmentation error while processing "
202                         + entry.getKey() + ". Reason: ", e);
203             }
204         }
205         return eb;
206     }
207
208     /**
209      * Construct an L3 endpoint with the appropriate augmentations from the
210      * endpoint input. Each concrete implementation can provides its specifics
211      * earlier.
212      *
213      * @param input
214      *            the input object
215      */
216     private EndpointL3PrefixBuilder buildL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
217         EndpointL3PrefixBuilder eb = new EndpointL3PrefixBuilder(input);
218         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
219                 .entrySet()) {
220             try {
221                 Map.Entry<Class<? extends Augmentation<EndpointL3Prefix>>, Augmentation<EndpointL3Prefix>> augmentationEntry =
222                         entry.getValue().buildL3PrefixEndpointAugmentation(input);
223                 if (augmentationEntry != null) {
224                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
225                 }
226             } catch (Exception e) {
227                 LOG.warn("L3 endpoint Augmentation error while processing "
228                         + entry.getKey() + ". Reason: ", e);
229             }
230         }
231         return eb;
232     }
233
234     @Override
235     public Future<RpcResult<Void>>
236             registerEndpoint(RegisterEndpointInput input) {
237         long timestamp = System.currentTimeMillis();
238
239         // TODO: Replicate RPC feedback implemented in L3Prefix register for
240         // unmet requirements.
241         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
242
243         if (input.getL2Context() != null &&
244                 input.getMacAddress() != null) {
245             Endpoint ep = buildEndpoint(input)
246                     .setTimestamp(timestamp)
247                     .build();
248
249             EndpointKey key =
250                     new EndpointKey(ep.getL2Context(), ep.getMacAddress());
251             InstanceIdentifier<Endpoint> iid =
252                     InstanceIdentifier.builder(Endpoints.class)
253                             .child(Endpoint.class, key)
254                             .build();
255             t.put(LogicalDatastoreType.OPERATIONAL, iid, ep, true);
256         }
257         if (input.getL3Address() != null) {
258             for (L3Address l3addr : input.getL3Address()) {
259                 EndpointL3Key key3 = new EndpointL3Key(l3addr.getIpAddress(),
260                         l3addr.getL3Context());
261                 EndpointL3 ep3 = buildEndpointL3(input)
262                         .setIpAddress(key3.getIpAddress())
263                         .setL3Context(key3.getL3Context())
264                         .setTimestamp(timestamp)
265                         .build();
266                 InstanceIdentifier<EndpointL3> iid_l3 =
267                         InstanceIdentifier.builder(Endpoints.class)
268                                 .child(EndpointL3.class, key3)
269                                 .build();
270                 t.put(LogicalDatastoreType.OPERATIONAL, iid_l3, ep3, true);
271             }
272         }
273         ListenableFuture<Void> r = t.submit();
274         return Futures.transform(r, futureTrans);
275     }
276
277     @Override
278     public Future<RpcResult<Void>> registerL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
279
280         if (input.getL3Context() == null) {
281             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
282                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have L3Context.").build());
283         }
284         if (input.getIpPrefix() == null) {
285             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
286                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have ip-prefix.").build());
287         }
288
289         if (input.getTenant() == null) {
290             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
291                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have tenant.").build());
292         }
293
294         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
295
296         long timestamp = System.currentTimeMillis();
297
298         // TODO: Convert IPPrefix into it's IPv4/IPv6 canonical form.
299         // See org.apache.commons.net.util.SubnetUtils.SubnetInfo
300
301         EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey(input.getIpPrefix(), input.getL3Context());
302
303         EndpointL3Prefix epL3Prefix = buildL3PrefixEndpoint(input).setTimestamp(timestamp).build();
304         InstanceIdentifier<EndpointL3Prefix> iid_l3prefix =
305                 InstanceIdentifier.builder(Endpoints.class)
306                         .child(EndpointL3Prefix.class, epL3PrefixKey)
307                         .build();
308         t.put(LogicalDatastoreType.OPERATIONAL, iid_l3prefix, epL3Prefix);
309
310         ListenableFuture<Void> r = t.submit();
311         return Futures.transform(r, futureTrans);
312     }
313
314     @Override
315     public Future<RpcResult<Void>>
316             unregisterEndpoint(UnregisterEndpointInput input) {
317         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
318         if (input.getL2() != null) {
319             for (L2 l2a : input.getL2()) {
320                 EndpointKey key =
321                         new EndpointKey(l2a.getL2Context(),
322                                 l2a.getMacAddress());
323                 InstanceIdentifier<Endpoint> iid =
324                         InstanceIdentifier.builder(Endpoints.class)
325                                 .child(Endpoint.class, key).build();
326                 t.delete(LogicalDatastoreType.OPERATIONAL, iid);
327             }
328         }
329         if (input.getL3() != null) {
330             for (L3 l3addr : input.getL3()) {
331                 EndpointL3Key key3 =
332                         new EndpointL3Key(l3addr.getIpAddress(),
333                                 l3addr.getL3Context());
334                 InstanceIdentifier<EndpointL3> iid_l3 =
335                         InstanceIdentifier.builder(Endpoints.class)
336                                 .child(EndpointL3.class, key3)
337                                 .build();
338                 t.delete(LogicalDatastoreType.OPERATIONAL, iid_l3);
339             }
340         }
341         // TODO: Implement L3Prefix
342
343         ListenableFuture<Void> r = t.submit();
344         return Futures.transform(r, futureTrans);
345     }
346
347     @Override
348     public Future<RpcResult<Void>>
349             setEndpointGroupConditions(SetEndpointGroupConditionsInput input) {
350         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
351
352         ConditionMappingKey key =
353                 new ConditionMappingKey(input.getEndpointGroup());
354
355         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
356             EndpointGroupConditionKey ckey =
357                     new EndpointGroupConditionKey(condition.getCondition());
358             InstanceIdentifier<EndpointGroupCondition> iid =
359                     InstanceIdentifier.builder(Endpoints.class)
360                             .child(ConditionMapping.class, key)
361                             .child(EndpointGroupCondition.class, ckey)
362                             .build();
363             t.put(LogicalDatastoreType.OPERATIONAL, iid, condition);
364         }
365
366         ListenableFuture<Void> r = t.submit();
367         return Futures.transform(r, futureTrans);
368     }
369
370     @Override
371     public Future<RpcResult<Void>>
372             unsetEndpointGroupConditions(UnsetEndpointGroupConditionsInput input) {
373         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
374
375         ConditionMappingKey key =
376                 new ConditionMappingKey(input.getEndpointGroup());
377
378         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
379             EndpointGroupConditionKey ckey =
380                     new EndpointGroupConditionKey(condition.getCondition());
381             InstanceIdentifier<EndpointGroupCondition> iid =
382                     InstanceIdentifier.builder(Endpoints.class)
383                             .child(ConditionMapping.class, key)
384                             .child(EndpointGroupCondition.class, ckey)
385                             .build();
386
387             t.delete(LogicalDatastoreType.OPERATIONAL, iid);
388         }
389
390         ListenableFuture<Void> r = t.submit();
391         return Futures.transform(r, futureTrans);
392     }
393
394     Function<Void, RpcResult<Void>> futureTrans =
395             new Function<Void, RpcResult<Void>>() {
396                 @Override
397                 public RpcResult<Void> apply(Void input) {
398                     return RpcResultBuilder.<Void> success().build();
399                 }
400             };
401 }