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