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.binding.impl.AbstractForwardedDataBroker;
32 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
33 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
34 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
35 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
37 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
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.DataBrokerImpl;
49 import org.opendaylight.controller.sal.binding.impl.MountPointManagerImpl.BindingMountPointImpl;
50 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
51 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener;
52 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
53 import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions;
54 import org.opendaylight.controller.sal.common.util.Rpcs;
55 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
56 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
57 import org.opendaylight.controller.sal.core.api.Provider;
58 import org.opendaylight.controller.sal.core.api.RpcImplementation;
59 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
60 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
61 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
62 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
63 import org.opendaylight.yangtools.concepts.ListenerRegistration;
64 import org.opendaylight.yangtools.concepts.Registration;
65 import org.opendaylight.yangtools.yang.binding.Augmentable;
66 import org.opendaylight.yangtools.yang.binding.Augmentation;
67 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
68 import org.opendaylight.yangtools.yang.binding.BindingMapping;
69 import org.opendaylight.yangtools.yang.binding.DataContainer;
70 import org.opendaylight.yangtools.yang.binding.DataObject;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 import org.opendaylight.yangtools.yang.binding.Notification;
73 import org.opendaylight.yangtools.yang.binding.RpcService;
74 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
75 import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
76 import org.opendaylight.yangtools.yang.common.QName;
77 import org.opendaylight.yangtools.yang.common.RpcError;
78 import org.opendaylight.yangtools.yang.common.RpcResult;
79 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
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.ImmutableSet;
89 import com.google.common.collect.ImmutableSet.Builder;
90 import com.google.common.util.concurrent.Futures;
91 import com.google.common.util.concurrent.ListenableFuture;
93 public class BindingIndependentConnector implements //
94 RuntimeDataProvider, //
98 private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
100 private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
101 .builder().toInstance();
103 private final static Method EQUALS_METHOD;
105 private BindingIndependentMappingService mappingService;
107 private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
109 private DataProviderService baDataService;
111 private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
112 private final ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
114 private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
115 private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
117 private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
119 private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
121 private RpcProvisionRegistry biRpcRegistry;
122 private RpcProviderRegistry baRpcRegistry;
124 private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
125 // private ListenerRegistration<BindingToDomRpcForwardingManager>
126 // bindingToDomRpcManager;
128 private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
131 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(final InstanceIdentifier<?> input) {
132 return mappingService.toDataDom(input);
137 private boolean rpcForwarding = false;
139 private boolean dataForwarding = false;
141 private boolean notificationForwarding = false;
143 private RpcProviderRegistryImpl baRpcRegistryImpl;
145 private NotificationProviderService baNotifyService;
147 private NotificationPublishService domNotificationService;
151 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
152 } catch (Exception e) {
153 throw new RuntimeException(e);
158 public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
160 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
161 CompositeNode result = biDataService.readOperationalData(biPath);
162 return potentialAugmentationRead(path, biPath, result);
163 } catch (DeserializationException e) {
164 throw new IllegalStateException(e);
168 private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
169 final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, final CompositeNode result)
170 throws DeserializationException {
171 Class<? extends DataObject> targetType = path.getTargetType();
172 if (Augmentation.class.isAssignableFrom(targetType)) {
173 path = mappingService.fromDataDom(biPath);
174 Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
175 DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
176 if (parentTo instanceof Augmentable<?>) {
177 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
180 return mappingService.dataObjectFromDataDom(path, result);
184 public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
186 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
187 CompositeNode result = biDataService.readConfigurationData(biPath);
188 return potentialAugmentationRead(path, biPath, result);
189 } catch (DeserializationException e) {
190 throw new IllegalStateException(e);
194 private DataModificationTransaction createBindingToDomTransaction(
195 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
196 DataModificationTransaction target = biDataService.beginTransaction();
197 LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(), source.getIdentifier());
198 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
199 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
200 target.removeConfigurationData(biEntry);
201 LOG.debug("Delete of Binding Configuration Data {} is translated to {}", entry, biEntry);
203 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
204 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
205 target.removeOperationalData(biEntry);
206 LOG.debug("Delete of Binding Operational Data {} is translated to {}", entry, biEntry);
208 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
210 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
212 target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
213 LOG.debug("Update of Binding Configuration Data {} is translated to {}", entry, biEntry);
215 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
217 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
219 target.putOperationalData(biEntry.getKey(), biEntry.getValue());
220 LOG.debug("Update of Binding Operational Data {} is translated to {}", entry, biEntry);
226 private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
227 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
228 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
230 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
233 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
234 target.removeConfigurationData(baEntry);
235 } catch (DeserializationException e) {
236 LOG.error("Ommiting from BA transaction: {}.", entry, e);
239 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
242 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
243 target.removeOperationalData(baEntry);
244 } catch (DeserializationException e) {
245 LOG.error("Ommiting from BA transaction: {}.", entry, e);
248 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
249 .getUpdatedConfigurationData().entrySet()) {
251 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
252 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
253 target.putConfigurationData(baKey, baData);
254 } catch (DeserializationException e) {
255 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
258 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
259 .getUpdatedOperationalData().entrySet()) {
262 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
263 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
264 target.putOperationalData(baKey, baData);
265 } catch (DeserializationException e) {
266 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
272 public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
273 return biDataService;
276 protected void setDomDataService(
277 final org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
278 this.biDataService = biDataService;
281 public DataProviderService getBaDataService() {
282 return baDataService;
285 protected void setBindingDataService(final DataProviderService baDataService) {
286 this.baDataService = baDataService;
289 public RpcProviderRegistry getRpcRegistry() {
290 return baRpcRegistry;
293 protected void setBindingRpcRegistry(final RpcProviderRegistry rpcRegistry) {
294 this.baRpcRegistry = rpcRegistry;
297 public void startDataForwarding() {
298 if (baDataService instanceof AbstractForwardedDataBroker) {
299 dataForwarding = true;
303 final DataProviderService baData;
304 if (baDataService instanceof BindingMountPointImpl) {
305 baData = ((BindingMountPointImpl) baDataService).getDataBrokerImpl();
306 LOG.debug("Extracted BA Data provider {} from mount point {}", baData, baDataService);
308 baData = baDataService;
311 if (baData instanceof DataBrokerImpl) {
312 checkState(!dataForwarding, "Connector is already forwarding data.");
313 ((DataBrokerImpl) baData).setDataReadDelegate(this);
314 ((DataBrokerImpl) baData).setRootCommitHandler(bindingToDomCommitHandler);
315 biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
316 baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
319 dataForwarding = true;
322 public void startRpcForwarding() {
323 if (biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
324 checkState(!rpcForwarding, "Connector is already forwarding RPCs");
325 domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
326 if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
327 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
328 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
329 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
331 rpcForwarding = true;
335 public void startNotificationForwarding() {
336 checkState(!notificationForwarding, "Connector is already forwarding notifications.");
337 if (baNotifyService != null && domNotificationService != null) {
338 baNotifyService.registerInterestListener(new DomToBindingNotificationForwarder());
340 notificationForwarding = true;
344 protected void setMappingService(final BindingIndependentMappingService mappingService) {
345 this.mappingService = mappingService;
349 public Collection<ProviderFunctionality> getProviderFunctionality() {
350 return Collections.emptyList();
354 public void onSessionInitiated(final ProviderSession session) {
355 setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
356 setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
360 public <T extends RpcService> void onRpcRouterCreated(final Class<T> serviceType, final RpcRouter<T> router) {
364 public void setDomRpcRegistry(final RpcProvisionRegistry registry) {
365 biRpcRegistry = registry;
369 public void close() throws Exception {
370 if (baCommitHandlerRegistration != null) {
371 baCommitHandlerRegistration.close();
373 if (biCommitHandlerRegistration != null) {
374 biCommitHandlerRegistration.close();
379 private class DomToBindingTransaction implements
380 DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
382 private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
383 private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
385 public DomToBindingTransaction(
386 final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
387 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
389 this.backing = backing;
390 this.modification = modification;
391 bindingOpenedTransactions.put(backing.getIdentifier(), this);
395 public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
400 public RpcResult<Void> rollback() throws IllegalStateException {
402 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
406 public RpcResult<Void> finish() throws IllegalStateException {
407 Future<RpcResult<TransactionStatus>> result = backing.commit();
409 RpcResult<TransactionStatus> baResult = result.get();
410 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
411 } catch (InterruptedException e) {
412 throw new IllegalStateException("", e);
413 } catch (ExecutionException e) {
414 throw new IllegalStateException("", e);
419 private class BindingToDomTransaction implements
420 DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
422 private final DataModificationTransaction backing;
423 private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
425 public BindingToDomTransaction(final DataModificationTransaction backing,
426 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
427 this.backing = backing;
428 this.modification = modification;
429 domOpenedTransactions.put(backing.getIdentifier(), this);
433 public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
438 public RpcResult<Void> finish() throws IllegalStateException {
439 Future<RpcResult<TransactionStatus>> result = backing.commit();
441 RpcResult<TransactionStatus> biResult = result.get();
442 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
443 } catch (InterruptedException e) {
444 throw new IllegalStateException("", e);
445 } catch (ExecutionException e) {
446 throw new IllegalStateException("", e);
448 domOpenedTransactions.remove(backing.getIdentifier());
453 public RpcResult<Void> rollback() throws IllegalStateException {
454 domOpenedTransactions.remove(backing.getIdentifier());
455 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
459 private class BindingToDomCommitHandler implements
460 DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
463 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
464 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
467 * Transaction was created as DOM transaction, in that case we do
468 * not need to forward it back.
470 if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
472 return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction);
474 DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
475 BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
476 LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .",
477 bindingTransaction.getIdentifier(), domTransaction.getIdentifier());
482 private class DomToBindingCommitHandler implements //
483 RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject>>, //
484 DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
487 public void onRegister(
488 final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
490 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
496 public void onUnregister(
497 final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
499 // FIXME: do registration based on only active commit handlers.
503 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
504 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
505 Object identifier = domTransaction.getIdentifier();
508 * We checks if the transcation was originated in this mapper. If it
509 * was originated in this mapper we are returing allways success
510 * commit hanlder to prevent creating loop in two-phase commit and
513 if (domOpenedTransactions.containsKey(identifier)) {
514 return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction);
517 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
518 DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
519 LOG.trace("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
520 baTransaction.getIdentifier());
521 return forwardedTransaction;
526 * Manager responsible for instantiating forwarders responsible for
527 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
530 private class DomToBindingRpcForwardingManager implements
531 RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>, RouterInstantiationListener,
532 GlobalRpcRegistrationListener {
534 private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
535 private RpcProviderRegistryImpl registryImpl;
537 public RpcProviderRegistryImpl getRegistryImpl() {
541 public void setRegistryImpl(final RpcProviderRegistryImpl registryImpl) {
542 this.registryImpl = registryImpl;
546 public void onGlobalRpcRegistered(final Class<? extends RpcService> cls) {
547 getRpcForwarder(cls, null);
551 public void onGlobalRpcUnregistered(final Class<? extends RpcService> cls) {
556 public void onRpcRouterCreated(final RpcRouter<?> router) {
557 Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
558 getRpcForwarder(router.getServiceType(), ctx);
562 public void onRouteChange(final RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
563 for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
564 bindingRoutesAdded(entry);
568 private void bindingRoutesAdded(final Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
569 Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
570 Class<? extends RpcService> service = entry.getKey().getRpcService();
571 if (context != null) {
572 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
576 private DomToBindingRpcForwarder getRpcForwarder(final Class<? extends RpcService> service,
577 final Class<? extends BaseIdentity> context) {
578 DomToBindingRpcForwarder potential = forwarders.get(service);
579 if (potential != null) {
582 if (context == null) {
583 potential = new DomToBindingRpcForwarder(service);
585 potential = new DomToBindingRpcForwarder(service, context);
588 forwarders.put(service, potential);
594 private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
596 private final Set<QName> supportedRpcs;
597 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
598 private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
599 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
600 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
602 public DomToBindingRpcForwarder(final Class<? extends RpcService> service) {
603 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
604 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
606 for (QName rpc : supportedRpcs) {
607 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
608 strategiesByMethod.put(strategy.targetMethod, strategy);
609 strategiesByQName.put(rpc, strategy);
610 biRpcRegistry.addRpcImplementation(rpc, this);
613 } catch (Exception e) {
614 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
616 registrations = ImmutableSet.of();
620 * Constructor for Routed RPC Forwareder.
625 public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
626 final Class<? extends BaseIdentity> context) {
627 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
628 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
629 Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
630 .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
632 for (QName rpc : supportedRpcs) {
633 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
634 strategiesByMethod.put(strategy.targetMethod, strategy);
635 strategiesByQName.put(rpc, strategy);
636 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
638 createDefaultDomForwarder();
639 } catch (Exception e) {
640 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
642 registrations = registrationsBuilder.build();
645 public void registerPaths(final Class<? extends BaseIdentity> context,
646 final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
647 QName ctx = BindingReflections.findQName(context);
648 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
649 toDOMInstanceIdentifier)) {
650 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
651 reg.registerPath(ctx, path);
657 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
658 if (EQUALS_METHOD.equals(method)) {
661 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
662 checkState(strategy != null);
663 checkArgument(args.length <= 2);
664 if (args.length == 1) {
665 checkArgument(args[0] instanceof DataObject);
666 return strategy.forwardToDomBroker((DataObject) args[0]);
668 return strategy.forwardToDomBroker(null);
671 public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
672 final Set<InstanceIdentifier<?>> set) {
673 QName ctx = BindingReflections.findQName(context);
674 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
675 toDOMInstanceIdentifier)) {
676 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
677 reg.unregisterPath(ctx, path);
683 public Set<QName> getSupportedRpcs() {
684 return supportedRpcs;
687 @SuppressWarnings({ "unchecked", "rawtypes" })
688 public void createDefaultDomForwarder() {
689 if (baRpcRegistryImpl != null) {
690 Class<?> cls = rpcServiceType.get();
691 ClassLoader clsLoader = cls.getClassLoader();
692 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
694 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
695 rpcRouter.registerDefaultService(proxy);
700 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
701 checkArgument(rpc != null);
702 checkArgument(domInput != null);
704 Class<? extends RpcService> rpcType = rpcServiceType.get();
705 checkState(rpcType != null);
706 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
707 checkState(rpcService != null);
708 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
711 return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
712 } catch (Exception e) {
713 return Futures.immediateFailedFuture(e);
717 private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
718 return strategiesByQName.get(rpc);
721 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
722 final Class<? extends RpcService> rpcType) throws Exception {
723 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
725 public RpcInvocationStrategy call() throws Exception {
726 String methodName = BindingMapping.getMethodName(rpc);
727 Method targetMethod = null;
728 for (Method possibleMethod : rpcType.getMethods()) {
729 if (possibleMethod.getName().equals(methodName)
730 && BindingReflections.isRpcMethod(possibleMethod)) {
731 targetMethod = possibleMethod;
735 checkState(targetMethod != null, "Rpc method not found");
736 return new RpcInvocationStrategy(rpc,targetMethod, mappingService, biRpcRegistry);
743 public boolean isRpcForwarding() {
744 return rpcForwarding;
747 public boolean isDataForwarding() {
748 return dataForwarding;
751 public boolean isNotificationForwarding() {
752 return notificationForwarding;
755 public BindingIndependentMappingService getMappingService() {
756 return mappingService;
759 public void setBindingNotificationService(final NotificationProviderService baService) {
760 this.baNotifyService = baService;
764 public void setDomNotificationService(final NotificationPublishService domService) {
765 this.domNotificationService = domService;
768 private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
770 private final ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
771 private final Set<QName> supportedNotifications = new HashSet<>();
774 public Set<QName> getSupportedNotifications() {
775 return Collections.unmodifiableSet(supportedNotifications);
779 public void onNotification(final CompositeNode notification) {
780 QName qname = notification.getNodeType();
781 WeakReference<Class<? extends Notification>> potential = notifications.get(qname);
782 if (potential != null) {
783 Class<? extends Notification> potentialClass = potential.get();
784 if (potentialClass != null) {
785 final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
788 if (baNotification instanceof Notification) {
789 baNotifyService.publish((Notification) baNotification);
796 public void onNotificationSubscribtion(final Class<? extends Notification> notificationType) {
797 QName qname = BindingReflections.findQName(notificationType);
799 WeakReference<Class<? extends Notification>> already = notifications.putIfAbsent(qname,
800 new WeakReference<Class<? extends Notification>>(notificationType));
801 if (already == null) {
802 domNotificationService.addNotificationListener(qname, this);
803 supportedNotifications.add(qname);