2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.sal.binding.impl.connect.dom;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
13 import java.lang.ref.WeakReference;
14 import java.lang.reflect.InvocationHandler;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Proxy;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
22 import java.util.Map.Entry;
24 import java.util.WeakHashMap;
25 import java.util.concurrent.Callable;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentMap;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.Future;
31 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
32 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
33 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
34 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
35 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
36 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
37 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
38 import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
39 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
40 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
41 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
42 import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener;
43 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
44 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
45 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
46 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
47 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
48 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
49 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener;
50 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
51 import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions;
52 import org.opendaylight.controller.sal.common.util.Rpcs;
53 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
54 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
55 import org.opendaylight.controller.sal.core.api.Provider;
56 import org.opendaylight.controller.sal.core.api.RpcImplementation;
57 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
58 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
59 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
60 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
61 import org.opendaylight.yangtools.concepts.ListenerRegistration;
62 import org.opendaylight.yangtools.concepts.Registration;
63 import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
64 import org.opendaylight.yangtools.yang.binding.Augmentable;
65 import org.opendaylight.yangtools.yang.binding.Augmentation;
66 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
67 import org.opendaylight.yangtools.yang.binding.BindingMapping;
68 import org.opendaylight.yangtools.yang.binding.DataContainer;
69 import org.opendaylight.yangtools.yang.binding.DataObject;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.opendaylight.yangtools.yang.binding.Notification;
72 import org.opendaylight.yangtools.yang.binding.RpcService;
73 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
74 import org.opendaylight.yangtools.yang.common.QName;
75 import org.opendaylight.yangtools.yang.common.RpcError;
76 import org.opendaylight.yangtools.yang.common.RpcResult;
77 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
78 import org.opendaylight.yangtools.yang.data.api.Node;
79 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
80 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
81 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
85 import com.google.common.base.Function;
86 import com.google.common.base.Optional;
87 import com.google.common.collect.FluentIterable;
88 import com.google.common.collect.ImmutableList;
89 import com.google.common.collect.ImmutableSet;
90 import com.google.common.collect.ImmutableSet.Builder;
91 import com.google.common.util.concurrent.Futures;
93 public class BindingIndependentConnector implements //
94 RuntimeDataProvider, //
100 private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
102 @SuppressWarnings("deprecation")
103 private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
105 private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
106 .builder().toInstance();
108 private final static Method EQUALS_METHOD;
110 private BindingIndependentMappingService mappingService;
112 private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
114 private DataProviderService baDataService;
116 private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
117 private final ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
119 private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
120 private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
122 private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
124 private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
126 private RpcProvisionRegistry biRpcRegistry;
127 private RpcProviderRegistry baRpcRegistry;
129 private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
130 // private ListenerRegistration<BindingToDomRpcForwardingManager>
131 // bindingToDomRpcManager;
133 private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
136 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
137 return mappingService.toDataDom(input);
142 private Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> baDataReaderRegistration;
144 private boolean rpcForwarding = false;
146 private boolean dataForwarding = false;
148 private boolean notificationForwarding = false;
150 private RpcProviderRegistryImpl baRpcRegistryImpl;
152 private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
154 private NotificationProviderService baNotifyService;
156 private NotificationPublishService domNotificationService;
160 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
161 } catch (Exception e) {
162 throw new RuntimeException(e);
167 public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
169 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
170 CompositeNode result = biDataService.readOperationalData(biPath);
171 return potentialAugmentationRead(path, biPath, result);
172 } catch (DeserializationException e) {
173 throw new IllegalStateException(e);
177 private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
178 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result)
179 throws DeserializationException {
180 Class<? extends DataObject> targetType = path.getTargetType();
181 if (Augmentation.class.isAssignableFrom(targetType)) {
182 path = mappingService.fromDataDom(biPath);
183 Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
184 DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
185 if (parentTo instanceof Augmentable<?>) {
186 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
189 return mappingService.dataObjectFromDataDom(path, result);
193 public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
195 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
196 CompositeNode result = biDataService.readConfigurationData(biPath);
197 return potentialAugmentationRead(path, biPath, result);
198 } catch (DeserializationException e) {
199 throw new IllegalStateException(e);
203 private DataModificationTransaction createBindingToDomTransaction(
204 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
205 DataModificationTransaction target = biDataService.beginTransaction();
206 LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier());
207 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
209 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
211 target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
212 LOG.debug("Update of Binding Configuration Data {} is translated to {}",entry,biEntry);
214 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
216 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
218 target.putOperationalData(biEntry.getKey(), biEntry.getValue());
219 LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry);
221 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
222 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
223 target.removeConfigurationData(biEntry);
224 LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
226 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
227 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
228 target.removeOperationalData(biEntry);
229 LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
234 private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
235 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
236 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
238 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
239 .getUpdatedConfigurationData().entrySet()) {
241 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
242 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
243 target.putConfigurationData(baKey, baData);
244 } catch (DeserializationException e) {
245 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
248 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
249 .getUpdatedOperationalData().entrySet()) {
252 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
253 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
254 target.putOperationalData(baKey, baData);
255 } catch (DeserializationException e) {
256 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
259 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
262 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
263 target.removeConfigurationData(baEntry);
264 } catch (DeserializationException e) {
265 LOG.error("Ommiting from BA transaction: {}.", entry, e);
268 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
271 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
272 target.removeOperationalData(baEntry);
273 } catch (DeserializationException e) {
274 LOG.error("Ommiting from BA transaction: {}.", entry, e);
280 public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
281 return biDataService;
284 protected void setDomDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
285 this.biDataService = biDataService;
288 public DataProviderService getBaDataService() {
289 return baDataService;
292 protected void setBindingDataService(DataProviderService baDataService) {
293 this.baDataService = baDataService;
296 public RpcProviderRegistry getRpcRegistry() {
297 return baRpcRegistry;
300 protected void setBindingRpcRegistry(RpcProviderRegistry rpcRegistry) {
301 this.baRpcRegistry = rpcRegistry;
304 public void startDataForwarding() {
305 checkState(!dataForwarding, "Connector is already forwarding data.");
306 baDataReaderRegistration = baDataService.registerDataReader(ROOT, this);
307 baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
308 biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
309 baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
310 dataForwarding = true;
313 public void startRpcForwarding() {
314 if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
315 checkState(!rpcForwarding, "Connector is already forwarding RPCs");
316 domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
317 if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
318 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
319 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
320 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
322 if (biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
323 biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
325 rpcForwarding = true;
329 public void startNotificationForwarding() {
330 checkState(!notificationForwarding, "Connector is already forwarding notifications.");
331 if (baNotifyService != null && domNotificationService != null) {
332 baNotifyService.registerInterestListener(new DomToBindingNotificationForwarder());
334 notificationForwarding = true;
338 protected void setMappingService(BindingIndependentMappingService mappingService) {
339 this.mappingService = mappingService;
343 public Collection<ProviderFunctionality> getProviderFunctionality() {
344 return Collections.emptyList();
348 public void onSessionInitiated(ProviderSession session) {
349 setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
350 setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
354 public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
358 public void setDomRpcRegistry(RpcProvisionRegistry registry) {
359 biRpcRegistry = registry;
363 public void close() throws Exception {
364 if (baCommitHandlerRegistration != null) {
365 baCommitHandlerRegistration.close();
367 if (biCommitHandlerRegistration != null) {
368 biCommitHandlerRegistration.close();
373 private class DomToBindingTransaction implements
374 DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
376 private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
377 private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
379 public DomToBindingTransaction(
380 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
381 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
383 this.backing = backing;
384 this.modification = modification;
385 bindingOpenedTransactions.put(backing.getIdentifier(), this);
389 public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
394 public RpcResult<Void> rollback() throws IllegalStateException {
396 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
400 public RpcResult<Void> finish() throws IllegalStateException {
401 Future<RpcResult<TransactionStatus>> result = backing.commit();
403 RpcResult<TransactionStatus> baResult = result.get();
404 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
405 } catch (InterruptedException e) {
406 throw new IllegalStateException("", e);
407 } catch (ExecutionException e) {
408 throw new IllegalStateException("", e);
413 private class BindingToDomTransaction implements
414 DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
416 private final DataModificationTransaction backing;
417 private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
419 public BindingToDomTransaction(DataModificationTransaction backing,
420 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
421 this.backing = backing;
422 this.modification = modification;
423 domOpenedTransactions.put(backing.getIdentifier(), this);
427 public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
432 public RpcResult<Void> finish() throws IllegalStateException {
433 Future<RpcResult<TransactionStatus>> result = backing.commit();
435 RpcResult<TransactionStatus> biResult = result.get();
436 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
437 } catch (InterruptedException e) {
438 throw new IllegalStateException("", e);
439 } catch (ExecutionException e) {
440 throw new IllegalStateException("", e);
442 domOpenedTransactions.remove(backing.getIdentifier());
447 public RpcResult<Void> rollback() throws IllegalStateException {
448 domOpenedTransactions.remove(backing.getIdentifier());
449 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
453 private class BindingToDomCommitHandler implements
454 DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
457 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
458 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
461 * Transaction was created as DOM transaction, in that case we do
462 * not need to forward it back.
464 if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
466 return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction);
468 DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
469 BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
470 LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
471 domTransaction.getIdentifier());
476 private class DomToBindingCommitHandler implements //
477 RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject>>, //
478 DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
481 public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
483 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
489 public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
491 // FIXME: do registration based on only active commit handlers.
495 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
496 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
497 Object identifier = domTransaction.getIdentifier();
500 * We checks if the transcation was originated in this mapper. If it
501 * was originated in this mapper we are returing allways success
502 * commit hanlder to prevent creating loop in two-phase commit and
505 if (domOpenedTransactions.containsKey(identifier)) {
506 return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction);
509 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
510 DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
511 LOG.trace("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
512 baTransaction.getIdentifier());
513 return forwardedTransaction;
518 * Manager responsible for instantiating forwarders responsible for
519 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
522 private class DomToBindingRpcForwardingManager implements
523 RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
524 RouterInstantiationListener,
525 GlobalRpcRegistrationListener {
527 private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
528 private RpcProviderRegistryImpl registryImpl;
530 public RpcProviderRegistryImpl getRegistryImpl() {
534 public void setRegistryImpl(RpcProviderRegistryImpl registryImpl) {
535 this.registryImpl = registryImpl;
539 public void onGlobalRpcRegistered(Class<? extends RpcService> cls) {
540 getRpcForwarder(cls, null);
544 public void onGlobalRpcUnregistered(Class<? extends RpcService> cls) {
549 public void onRpcRouterCreated(RpcRouter<?> router) {
550 Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
551 getRpcForwarder(router.getServiceType(), ctx);
555 public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
556 for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
557 bindingRoutesAdded(entry);
561 private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
562 Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
563 Class<? extends RpcService> service = entry.getKey().getRpcService();
564 if (context != null) {
565 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
569 private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
570 Class<? extends BaseIdentity> context) {
571 DomToBindingRpcForwarder potential = forwarders.get(service);
572 if (potential != null) {
575 if (context == null) {
576 potential = new DomToBindingRpcForwarder(service);
578 potential = new DomToBindingRpcForwarder(service, context);
581 forwarders.put(service, potential);
587 private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
589 private final Set<QName> supportedRpcs;
590 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
591 private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
592 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
593 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
595 public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
596 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
597 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
599 for (QName rpc : supportedRpcs) {
600 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
601 strategiesByMethod.put(strategy.targetMethod, strategy);
602 strategiesByQName.put(rpc, strategy);
603 biRpcRegistry.addRpcImplementation(rpc, this);
606 } catch (Exception e) {
607 LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
609 registrations = ImmutableSet.of();
613 * Constructor for Routed RPC Forwareder.
618 public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
619 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
620 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
621 Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
622 .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
624 for (QName rpc : supportedRpcs) {
625 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
626 strategiesByMethod.put(strategy.targetMethod, strategy);
627 strategiesByQName.put(rpc, strategy);
628 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
630 createDefaultDomForwarder();
631 } catch (Exception e) {
632 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
634 registrations = registrationsBuilder.build();
637 public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
638 Set<InstanceIdentifier<?>> set) {
639 QName ctx = BindingReflections.findQName(context);
640 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
641 toDOMInstanceIdentifier)) {
642 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
643 reg.registerPath(ctx, path);
650 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
651 if (EQUALS_METHOD.equals(method)) {
654 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
655 checkState(strategy != null);
656 checkArgument(args.length <= 2);
657 if (args.length == 1) {
658 checkArgument(args[0] instanceof DataObject);
659 return strategy.forwardToDomBroker((DataObject) args[0]);
661 return strategy.forwardToDomBroker(null);
664 public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
665 Set<InstanceIdentifier<?>> set) {
666 QName ctx = BindingReflections.findQName(context);
667 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
668 toDOMInstanceIdentifier)) {
669 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
670 reg.unregisterPath(ctx, path);
676 public Set<QName> getSupportedRpcs() {
677 return supportedRpcs;
680 @SuppressWarnings({ "unchecked", "rawtypes" })
681 public void createDefaultDomForwarder() {
682 if (baRpcRegistryImpl != null) {
683 Class<?> cls = rpcServiceType.get();
684 ClassLoader clsLoader = cls.getClassLoader();
685 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
687 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
688 rpcRouter.registerDefaultService(proxy);
693 public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
694 checkArgument(rpc != null);
695 checkArgument(domInput != null);
697 Class<? extends RpcService> rpcType = rpcServiceType.get();
698 checkState(rpcType != null);
699 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
700 checkState(rpcService != null);
701 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
703 return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput);
704 } catch (Exception e) {
705 throw new IllegalStateException(e);
709 private RpcInvocationStrategy resolveInvocationStrategy(QName rpc) {
710 return strategiesByQName.get(rpc);
713 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
714 final Class<? extends RpcService> rpcType) throws Exception {
715 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
717 public RpcInvocationStrategy call() throws Exception {
718 String methodName = BindingMapping.getMethodName(rpc);
719 Method targetMethod = null;
720 for (Method possibleMethod : rpcType.getMethods()) {
721 if (possibleMethod.getName().equals(methodName)
722 && BindingReflections.isRpcMethod(possibleMethod)) {
723 targetMethod = possibleMethod;
727 checkState(targetMethod != null, "Rpc method not found");
728 Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
729 Optional<Class<? extends DataContainer>> inputClass = BindingReflections
730 .resolveRpcInputClass(targetMethod);
732 RpcInvocationStrategy strategy = null;
733 if (outputClass.isPresent()) {
734 if (inputClass.isPresent()) {
735 strategy = new DefaultInvocationStrategy(rpc, targetMethod, outputClass.get(), inputClass
738 strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
740 } else if(inputClass.isPresent()){
741 strategy = new NoOutputInvocationStrategy(rpc,targetMethod, inputClass.get());
743 strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
752 private abstract class RpcInvocationStrategy {
754 protected final Method targetMethod;
755 protected final QName rpc;
757 public RpcInvocationStrategy(QName rpc, Method targetMethod) {
758 this.targetMethod = targetMethod;
762 public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
764 public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
767 public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
768 return uncheckedInvoke(rpcService, domInput);
772 private class DefaultInvocationStrategy extends RpcInvocationStrategy {
774 @SuppressWarnings("rawtypes")
775 private final WeakReference<Class> inputClass;
777 @SuppressWarnings("rawtypes")
778 private final WeakReference<Class> outputClass;
780 @SuppressWarnings({ "rawtypes", "unchecked" })
781 public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
782 Class<? extends DataContainer> inputClass) {
783 super(rpc, targetMethod);
784 this.outputClass = new WeakReference(outputClass);
785 this.inputClass = new WeakReference(inputClass);
788 @SuppressWarnings("unchecked")
790 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
791 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
792 Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
793 if (futureResult == null) {
794 return Rpcs.getRpcResult(false);
796 RpcResult<?> bindingResult = futureResult.get();
797 final Object resultObj = bindingResult.getResult();
798 if (resultObj instanceof DataObject) {
799 final CompositeNode output = mappingService.toDataDom((DataObject)resultObj);
800 return Rpcs.getRpcResult(true, output, Collections.<RpcError>emptySet());
802 return Rpcs.getRpcResult(true);
806 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
807 if(biRouter != null) {
808 CompositeNode xml = mappingService.toDataDom(input);
809 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
810 RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
811 Object baResultValue = null;
812 if (result.getResult() != null) {
813 baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
815 RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
816 return Futures.<RpcResult<?>> immediateFuture(baResult);
818 return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
823 private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
825 public NoInputNoOutputInvocationStrategy(QName rpc, Method targetMethod) {
826 super(rpc, targetMethod);
830 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
831 @SuppressWarnings("unchecked")
832 Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
833 RpcResult<Void> bindingResult = result.get();
834 return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
838 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
839 return Futures.immediateFuture(null);
843 private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
846 @SuppressWarnings("rawtypes")
847 private final WeakReference<Class> inputClass;
849 @SuppressWarnings({ "rawtypes", "unchecked" })
850 public NoOutputInvocationStrategy(QName rpc, Method targetMethod,
851 Class<? extends DataContainer> inputClass) {
852 super(rpc,targetMethod);
853 this.inputClass = new WeakReference(inputClass);
858 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
859 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
860 Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
861 if (result == null) {
862 return Rpcs.getRpcResult(false);
864 RpcResult<?> bindingResult = result.get();
865 return Rpcs.getRpcResult(true);
869 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
870 if(biRouter != null) {
871 CompositeNode xml = mappingService.toDataDom(input);
872 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
873 RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
874 Object baResultValue = null;
875 RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
876 return Futures.<RpcResult<?>>immediateFuture(baResult);
878 return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
883 public boolean isRpcForwarding() {
884 return rpcForwarding;
887 public boolean isDataForwarding() {
888 return dataForwarding;
891 public boolean isNotificationForwarding() {
892 return notificationForwarding;
895 public BindingIndependentMappingService getMappingService() {
896 return mappingService;
899 public void setBindingNotificationService(NotificationProviderService baService) {
900 this.baNotifyService = baService;
904 public void setDomNotificationService(NotificationPublishService domService) {
905 this.domNotificationService = domService;
908 private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
910 private final ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
911 private final Set<QName> supportedNotifications = new HashSet<>();
914 public Set<QName> getSupportedNotifications() {
915 return Collections.unmodifiableSet(supportedNotifications);
919 public void onNotification(CompositeNode notification) {
920 QName qname = notification.getNodeType();
921 WeakReference<Class<? extends Notification>> potential = notifications.get(qname);
922 if (potential != null) {
923 Class<? extends Notification> potentialClass = potential.get();
924 if (potentialClass != null) {
925 final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
928 if (baNotification instanceof Notification) {
929 baNotifyService.publish((Notification) baNotification);
936 public void onNotificationSubscribtion(Class<? extends Notification> notificationType) {
937 QName qname = BindingReflections.findQName(notificationType);
939 WeakReference<Class<? extends Notification>> already = notifications.putIfAbsent(qname,
940 new WeakReference<Class<? extends Notification>>(notificationType));
941 if (already == null) {
942 domNotificationService.addNotificationListener(qname, this);
943 supportedNotifications.add(qname);