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.api.Node;
81 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
82 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
83 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
87 import com.google.common.base.Function;
88 import com.google.common.base.Optional;
89 import com.google.common.collect.FluentIterable;
90 import com.google.common.collect.ImmutableList;
91 import com.google.common.collect.ImmutableSet;
92 import com.google.common.collect.ImmutableSet.Builder;
93 import com.google.common.util.concurrent.Futures;
94 import com.google.common.util.concurrent.ListenableFuture;
96 public class BindingIndependentConnector implements //
97 RuntimeDataProvider, //
101 private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
103 private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
104 .builder().toInstance();
106 private final static Method EQUALS_METHOD;
108 private BindingIndependentMappingService mappingService;
110 private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
112 private DataProviderService baDataService;
114 private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
115 private final ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
117 private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
118 private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
120 private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
122 private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
124 private RpcProvisionRegistry biRpcRegistry;
125 private RpcProviderRegistry baRpcRegistry;
127 private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
128 // private ListenerRegistration<BindingToDomRpcForwardingManager>
129 // bindingToDomRpcManager;
131 private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
134 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(final InstanceIdentifier<?> input) {
135 return mappingService.toDataDom(input);
140 private boolean rpcForwarding = false;
142 private boolean dataForwarding = false;
144 private boolean notificationForwarding = false;
146 private RpcProviderRegistryImpl baRpcRegistryImpl;
148 private NotificationProviderService baNotifyService;
150 private NotificationPublishService domNotificationService;
154 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
155 } catch (Exception e) {
156 throw new RuntimeException(e);
161 public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
163 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
164 CompositeNode result = biDataService.readOperationalData(biPath);
165 return potentialAugmentationRead(path, biPath, result);
166 } catch (DeserializationException e) {
167 throw new IllegalStateException(e);
171 private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
172 final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, final CompositeNode result)
173 throws DeserializationException {
174 Class<? extends DataObject> targetType = path.getTargetType();
175 if (Augmentation.class.isAssignableFrom(targetType)) {
176 path = mappingService.fromDataDom(biPath);
177 Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
178 DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
179 if (parentTo instanceof Augmentable<?>) {
180 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
183 return mappingService.dataObjectFromDataDom(path, result);
187 public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
189 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
190 CompositeNode result = biDataService.readConfigurationData(biPath);
191 return potentialAugmentationRead(path, biPath, result);
192 } catch (DeserializationException e) {
193 throw new IllegalStateException(e);
197 private DataModificationTransaction createBindingToDomTransaction(
198 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
199 DataModificationTransaction target = biDataService.beginTransaction();
200 LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(), source.getIdentifier());
201 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
202 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
203 target.removeConfigurationData(biEntry);
204 LOG.debug("Delete of Binding Configuration Data {} is translated to {}", entry, biEntry);
206 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
207 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
208 target.removeOperationalData(biEntry);
209 LOG.debug("Delete of Binding Operational Data {} is translated to {}", entry, biEntry);
211 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
213 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
215 target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
216 LOG.debug("Update of Binding Configuration Data {} is translated to {}", entry, biEntry);
218 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
220 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
222 target.putOperationalData(biEntry.getKey(), biEntry.getValue());
223 LOG.debug("Update of Binding Operational Data {} is translated to {}", entry, biEntry);
229 private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
230 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
231 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
233 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
236 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
237 target.removeConfigurationData(baEntry);
238 } catch (DeserializationException e) {
239 LOG.error("Ommiting from BA transaction: {}.", entry, e);
242 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
245 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
246 target.removeOperationalData(baEntry);
247 } catch (DeserializationException e) {
248 LOG.error("Ommiting from BA transaction: {}.", entry, e);
251 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
252 .getUpdatedConfigurationData().entrySet()) {
254 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
255 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
256 target.putConfigurationData(baKey, baData);
257 } catch (DeserializationException e) {
258 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
261 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
262 .getUpdatedOperationalData().entrySet()) {
265 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
266 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
267 target.putOperationalData(baKey, baData);
268 } catch (DeserializationException e) {
269 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
275 public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
276 return biDataService;
279 protected void setDomDataService(
280 final org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
281 this.biDataService = biDataService;
284 public DataProviderService getBaDataService() {
285 return baDataService;
288 protected void setBindingDataService(final DataProviderService baDataService) {
289 this.baDataService = baDataService;
292 public RpcProviderRegistry getRpcRegistry() {
293 return baRpcRegistry;
296 protected void setBindingRpcRegistry(final RpcProviderRegistry rpcRegistry) {
297 this.baRpcRegistry = rpcRegistry;
300 public void startDataForwarding() {
301 if (baDataService instanceof AbstractForwardedDataBroker) {
302 dataForwarding = true;
306 final DataProviderService baData;
307 if (baDataService instanceof BindingMountPointImpl) {
308 baData = ((BindingMountPointImpl) baDataService).getDataBrokerImpl();
309 LOG.debug("Extracted BA Data provider {} from mount point {}", baData, baDataService);
311 baData = baDataService;
314 if (baData instanceof DataBrokerImpl) {
315 checkState(!dataForwarding, "Connector is already forwarding data.");
316 ((DataBrokerImpl) baData).setDataReadDelegate(this);
317 ((DataBrokerImpl) baData).setRootCommitHandler(bindingToDomCommitHandler);
318 biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
319 baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
322 dataForwarding = true;
325 public void startRpcForwarding() {
326 if (biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
327 checkState(!rpcForwarding, "Connector is already forwarding RPCs");
328 domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
329 if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
330 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
331 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
332 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
334 rpcForwarding = true;
338 public void startNotificationForwarding() {
339 checkState(!notificationForwarding, "Connector is already forwarding notifications.");
340 if (baNotifyService != null && domNotificationService != null) {
341 baNotifyService.registerInterestListener(new DomToBindingNotificationForwarder());
343 notificationForwarding = true;
347 protected void setMappingService(final BindingIndependentMappingService mappingService) {
348 this.mappingService = mappingService;
352 public Collection<ProviderFunctionality> getProviderFunctionality() {
353 return Collections.emptyList();
357 public void onSessionInitiated(final ProviderSession session) {
358 setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
359 setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
363 public <T extends RpcService> void onRpcRouterCreated(final Class<T> serviceType, final RpcRouter<T> router) {
367 public void setDomRpcRegistry(final RpcProvisionRegistry registry) {
368 biRpcRegistry = registry;
372 public void close() throws Exception {
373 if (baCommitHandlerRegistration != null) {
374 baCommitHandlerRegistration.close();
376 if (biCommitHandlerRegistration != null) {
377 biCommitHandlerRegistration.close();
382 private class DomToBindingTransaction implements
383 DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
385 private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
386 private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
388 public DomToBindingTransaction(
389 final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
390 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
392 this.backing = backing;
393 this.modification = modification;
394 bindingOpenedTransactions.put(backing.getIdentifier(), this);
398 public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
403 public RpcResult<Void> rollback() throws IllegalStateException {
405 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
409 public RpcResult<Void> finish() throws IllegalStateException {
410 Future<RpcResult<TransactionStatus>> result = backing.commit();
412 RpcResult<TransactionStatus> baResult = result.get();
413 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
414 } catch (InterruptedException e) {
415 throw new IllegalStateException("", e);
416 } catch (ExecutionException e) {
417 throw new IllegalStateException("", e);
422 private class BindingToDomTransaction implements
423 DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
425 private final DataModificationTransaction backing;
426 private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
428 public BindingToDomTransaction(final DataModificationTransaction backing,
429 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
430 this.backing = backing;
431 this.modification = modification;
432 domOpenedTransactions.put(backing.getIdentifier(), this);
436 public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
441 public RpcResult<Void> finish() throws IllegalStateException {
442 Future<RpcResult<TransactionStatus>> result = backing.commit();
444 RpcResult<TransactionStatus> biResult = result.get();
445 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
446 } catch (InterruptedException e) {
447 throw new IllegalStateException("", e);
448 } catch (ExecutionException e) {
449 throw new IllegalStateException("", e);
451 domOpenedTransactions.remove(backing.getIdentifier());
456 public RpcResult<Void> rollback() throws IllegalStateException {
457 domOpenedTransactions.remove(backing.getIdentifier());
458 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
462 private class BindingToDomCommitHandler implements
463 DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
466 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
467 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
470 * Transaction was created as DOM transaction, in that case we do
471 * not need to forward it back.
473 if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
475 return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction);
477 DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
478 BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
479 LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .",
480 bindingTransaction.getIdentifier(), domTransaction.getIdentifier());
485 private class DomToBindingCommitHandler implements //
486 RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject>>, //
487 DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
490 public void onRegister(
491 final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
493 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
499 public void onUnregister(
500 final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
502 // FIXME: do registration based on only active commit handlers.
506 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
507 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
508 Object identifier = domTransaction.getIdentifier();
511 * We checks if the transcation was originated in this mapper. If it
512 * was originated in this mapper we are returing allways success
513 * commit hanlder to prevent creating loop in two-phase commit and
516 if (domOpenedTransactions.containsKey(identifier)) {
517 return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction);
520 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
521 DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
522 LOG.trace("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
523 baTransaction.getIdentifier());
524 return forwardedTransaction;
529 * Manager responsible for instantiating forwarders responsible for
530 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
533 private class DomToBindingRpcForwardingManager implements
534 RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>, RouterInstantiationListener,
535 GlobalRpcRegistrationListener {
537 private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
538 private RpcProviderRegistryImpl registryImpl;
540 public RpcProviderRegistryImpl getRegistryImpl() {
544 public void setRegistryImpl(final RpcProviderRegistryImpl registryImpl) {
545 this.registryImpl = registryImpl;
549 public void onGlobalRpcRegistered(final Class<? extends RpcService> cls) {
550 getRpcForwarder(cls, null);
554 public void onGlobalRpcUnregistered(final Class<? extends RpcService> cls) {
559 public void onRpcRouterCreated(final RpcRouter<?> router) {
560 Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
561 getRpcForwarder(router.getServiceType(), ctx);
565 public void onRouteChange(final RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
566 for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
567 bindingRoutesAdded(entry);
571 private void bindingRoutesAdded(final Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
572 Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
573 Class<? extends RpcService> service = entry.getKey().getRpcService();
574 if (context != null) {
575 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
579 private DomToBindingRpcForwarder getRpcForwarder(final Class<? extends RpcService> service,
580 final Class<? extends BaseIdentity> context) {
581 DomToBindingRpcForwarder potential = forwarders.get(service);
582 if (potential != null) {
585 if (context == null) {
586 potential = new DomToBindingRpcForwarder(service);
588 potential = new DomToBindingRpcForwarder(service, context);
591 forwarders.put(service, potential);
597 private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
599 private final Set<QName> supportedRpcs;
600 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
601 private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
602 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
603 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
605 public DomToBindingRpcForwarder(final Class<? extends RpcService> service) {
606 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
607 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
609 for (QName rpc : supportedRpcs) {
610 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
611 strategiesByMethod.put(strategy.targetMethod, strategy);
612 strategiesByQName.put(rpc, strategy);
613 biRpcRegistry.addRpcImplementation(rpc, this);
616 } catch (Exception e) {
617 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
619 registrations = ImmutableSet.of();
623 * Constructor for Routed RPC Forwareder.
628 public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
629 final Class<? extends BaseIdentity> context) {
630 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
631 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
632 Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
633 .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
635 for (QName rpc : supportedRpcs) {
636 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
637 strategiesByMethod.put(strategy.targetMethod, strategy);
638 strategiesByQName.put(rpc, strategy);
639 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
641 createDefaultDomForwarder();
642 } catch (Exception e) {
643 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
645 registrations = registrationsBuilder.build();
648 public void registerPaths(final Class<? extends BaseIdentity> context,
649 final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
650 QName ctx = BindingReflections.findQName(context);
651 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
652 toDOMInstanceIdentifier)) {
653 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
654 reg.registerPath(ctx, path);
660 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
661 if (EQUALS_METHOD.equals(method)) {
664 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
665 checkState(strategy != null);
666 checkArgument(args.length <= 2);
667 if (args.length == 1) {
668 checkArgument(args[0] instanceof DataObject);
669 return strategy.forwardToDomBroker((DataObject) args[0]);
671 return strategy.forwardToDomBroker(null);
674 public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
675 final Set<InstanceIdentifier<?>> set) {
676 QName ctx = BindingReflections.findQName(context);
677 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
678 toDOMInstanceIdentifier)) {
679 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
680 reg.unregisterPath(ctx, path);
686 public Set<QName> getSupportedRpcs() {
687 return supportedRpcs;
690 @SuppressWarnings({ "unchecked", "rawtypes" })
691 public void createDefaultDomForwarder() {
692 if (baRpcRegistryImpl != null) {
693 Class<?> cls = rpcServiceType.get();
694 ClassLoader clsLoader = cls.getClassLoader();
695 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
697 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
698 rpcRouter.registerDefaultService(proxy);
703 public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
704 checkArgument(rpc != null);
705 checkArgument(domInput != null);
707 Class<? extends RpcService> rpcType = rpcServiceType.get();
708 checkState(rpcType != null);
709 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
710 checkState(rpcService != null);
711 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
714 return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
715 } catch (Exception e) {
716 return Futures.immediateFailedFuture(e);
720 private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
721 return strategiesByQName.get(rpc);
724 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
725 final Class<? extends RpcService> rpcType) throws Exception {
726 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
728 public RpcInvocationStrategy call() throws Exception {
729 String methodName = BindingMapping.getMethodName(rpc);
730 Method targetMethod = null;
731 for (Method possibleMethod : rpcType.getMethods()) {
732 if (possibleMethod.getName().equals(methodName)
733 && BindingReflections.isRpcMethod(possibleMethod)) {
734 targetMethod = possibleMethod;
738 checkState(targetMethod != null, "Rpc method not found");
739 Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
740 Optional<Class<? extends DataContainer>> inputClass = BindingReflections
741 .resolveRpcInputClass(targetMethod);
743 RpcInvocationStrategy strategy = null;
744 if (outputClass.isPresent()) {
745 if (inputClass.isPresent()) {
746 strategy = new DefaultInvocationStrategy(rpc, targetMethod, outputClass.get(), inputClass
749 strategy = new NoInputInvocationStrategy(rpc, targetMethod, outputClass.get());
751 } else if (inputClass.isPresent()) {
752 strategy = new NoOutputInvocationStrategy(rpc, targetMethod, inputClass.get());
754 strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
763 private abstract class RpcInvocationStrategy {
765 protected final Method targetMethod;
766 protected final QName rpc;
768 public RpcInvocationStrategy(final QName rpc, final Method targetMethod) {
769 this.targetMethod = targetMethod;
773 public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
775 public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
778 public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput)
780 return uncheckedInvoke(rpcService, domInput);
784 private class DefaultInvocationStrategy extends RpcInvocationStrategy {
786 @SuppressWarnings("rawtypes")
787 private final WeakReference<Class> inputClass;
789 @SuppressWarnings("rawtypes")
790 private final WeakReference<Class> outputClass;
792 @SuppressWarnings({ "rawtypes", "unchecked" })
793 public DefaultInvocationStrategy(final QName rpc, final Method targetMethod, final Class<?> outputClass,
794 final Class<? extends DataContainer> inputClass) {
795 super(rpc, targetMethod);
796 this.outputClass = new WeakReference(outputClass);
797 this.inputClass = new WeakReference(inputClass);
800 @SuppressWarnings("unchecked")
802 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
804 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
805 Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
806 if (futureResult == null) {
807 return Rpcs.getRpcResult(false);
809 RpcResult<?> bindingResult = futureResult.get();
810 final Object resultObj = bindingResult.getResult();
811 if (resultObj instanceof DataObject) {
812 final CompositeNode output = mappingService.toDataDom((DataObject) resultObj);
813 return Rpcs.getRpcResult(true, output, Collections.<RpcError> emptySet());
815 return Rpcs.getRpcResult(true);
819 public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
820 if (biRpcRegistry == null) {
821 return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
824 CompositeNode xml = mappingService.toDataDom(input);
825 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
827 return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
828 new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
830 public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
831 Object baResultValue = null;
832 if (input.getResult() != null) {
833 baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(),
836 return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
842 private class NoInputInvocationStrategy extends RpcInvocationStrategy {
844 @SuppressWarnings("rawtypes")
845 private final WeakReference<Class> outputClass;
847 @SuppressWarnings({ "rawtypes", "unchecked" })
848 public NoInputInvocationStrategy(final QName rpc, final Method targetMethod, final Class<?> outputClass) {
849 super(rpc, targetMethod);
850 this.outputClass = new WeakReference(outputClass);
853 @SuppressWarnings("unchecked")
855 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
857 Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService);
858 if (futureResult == null) {
859 return Rpcs.getRpcResult(false);
861 RpcResult<?> bindingResult = futureResult.get();
862 final Object resultObj = bindingResult.getResult();
863 if (resultObj instanceof DataObject) {
864 final CompositeNode output = mappingService.toDataDom((DataObject) resultObj);
865 return Rpcs.getRpcResult(true, output, Collections.<RpcError> emptySet());
867 return Rpcs.getRpcResult(true);
871 public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
872 if (biRpcRegistry != null) {
873 CompositeNode xml = mappingService.toDataDom(input);
874 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
875 return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
876 new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
878 public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
879 Object baResultValue = null;
880 if (input.getResult() != null) {
881 baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(),
884 return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
888 return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
893 private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
895 public NoInputNoOutputInvocationStrategy(final QName rpc, final Method targetMethod) {
896 super(rpc, targetMethod);
900 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
902 @SuppressWarnings("unchecked")
903 Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
904 RpcResult<Void> bindingResult = result.get();
905 return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
909 public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
910 return Futures.immediateFuture(null);
914 private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
916 @SuppressWarnings("rawtypes")
917 private final WeakReference<Class> inputClass;
919 @SuppressWarnings({ "rawtypes", "unchecked" })
920 public NoOutputInvocationStrategy(final QName rpc, final Method targetMethod,
921 final Class<? extends DataContainer> inputClass) {
922 super(rpc, targetMethod);
923 this.inputClass = new WeakReference(inputClass);
927 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
929 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
930 Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
931 if (result == null) {
932 return Rpcs.getRpcResult(false);
934 RpcResult<?> bindingResult = result.get();
935 return Rpcs.getRpcResult(true);
939 public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
940 if (biRpcRegistry == null) {
941 return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
944 CompositeNode xml = mappingService.toDataDom(input);
945 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
947 return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
948 new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
950 public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
951 return Rpcs.<Void> getRpcResult(input.isSuccessful(), null, input.getErrors());
957 public boolean isRpcForwarding() {
958 return rpcForwarding;
961 public boolean isDataForwarding() {
962 return dataForwarding;
965 public boolean isNotificationForwarding() {
966 return notificationForwarding;
969 public BindingIndependentMappingService getMappingService() {
970 return mappingService;
973 public void setBindingNotificationService(final NotificationProviderService baService) {
974 this.baNotifyService = baService;
978 public void setDomNotificationService(final NotificationPublishService domService) {
979 this.domNotificationService = domService;
982 private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
984 private final ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
985 private final Set<QName> supportedNotifications = new HashSet<>();
988 public Set<QName> getSupportedNotifications() {
989 return Collections.unmodifiableSet(supportedNotifications);
993 public void onNotification(final CompositeNode notification) {
994 QName qname = notification.getNodeType();
995 WeakReference<Class<? extends Notification>> potential = notifications.get(qname);
996 if (potential != null) {
997 Class<? extends Notification> potentialClass = potential.get();
998 if (potentialClass != null) {
999 final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
1002 if (baNotification instanceof Notification) {
1003 baNotifyService.publish((Notification) baNotification);
1010 public void onNotificationSubscribtion(final Class<? extends Notification> notificationType) {
1011 QName qname = BindingReflections.findQName(notificationType);
1012 if (qname != null) {
1013 WeakReference<Class<? extends Notification>> already = notifications.putIfAbsent(qname,
1014 new WeakReference<Class<? extends Notification>>(notificationType));
1015 if (already == null) {
1016 domNotificationService.addNotificationListener(qname, this);
1017 supportedNotifications.add(qname);