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.data.DataReader;
39 import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
40 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
41 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
42 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
43 import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener;
44 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
45 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
46 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
47 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
48 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
49 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
50 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener;
51 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
52 import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions;
53 import org.opendaylight.controller.sal.common.util.Rpcs;
54 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
55 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
56 import org.opendaylight.controller.sal.core.api.Provider;
57 import org.opendaylight.controller.sal.core.api.RpcImplementation;
58 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
59 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
60 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
61 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
62 import org.opendaylight.yangtools.concepts.ListenerRegistration;
63 import org.opendaylight.yangtools.concepts.Registration;
64 import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
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.common.QName;
76 import org.opendaylight.yangtools.yang.common.RpcError;
77 import org.opendaylight.yangtools.yang.common.RpcResult;
78 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
79 import org.opendaylight.yangtools.yang.data.api.Node;
80 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
81 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
82 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
86 import com.google.common.base.Function;
87 import com.google.common.base.Optional;
88 import com.google.common.collect.FluentIterable;
89 import com.google.common.collect.ImmutableList;
90 import com.google.common.collect.ImmutableSet;
91 import com.google.common.collect.ImmutableSet.Builder;
92 import com.google.common.util.concurrent.Futures;
94 public class BindingIndependentConnector implements //
95 RuntimeDataProvider, //
101 private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
103 @SuppressWarnings("deprecation")
104 private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
106 private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
107 .builder().toInstance();
109 private final static Method EQUALS_METHOD;
111 private BindingIndependentMappingService mappingService;
113 private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
115 private DataProviderService baDataService;
117 private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
118 private final ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
120 private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
121 private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
123 private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
125 private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
127 private RpcProvisionRegistry biRpcRegistry;
128 private RpcProviderRegistry baRpcRegistry;
130 private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
131 // private ListenerRegistration<BindingToDomRpcForwardingManager>
132 // bindingToDomRpcManager;
134 private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
137 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(final InstanceIdentifier<?> input) {
138 return mappingService.toDataDom(input);
143 private Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> baDataReaderRegistration;
145 private boolean rpcForwarding = false;
147 private boolean dataForwarding = false;
149 private boolean notificationForwarding = false;
151 private RpcProviderRegistryImpl baRpcRegistryImpl;
153 private NotificationProviderService baNotifyService;
155 private NotificationPublishService domNotificationService;
159 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
160 } catch (Exception e) {
161 throw new RuntimeException(e);
166 public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
168 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
169 CompositeNode result = biDataService.readOperationalData(biPath);
170 return potentialAugmentationRead(path, biPath, result);
171 } catch (DeserializationException e) {
172 throw new IllegalStateException(e);
176 private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
177 final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, final CompositeNode result)
178 throws DeserializationException {
179 Class<? extends DataObject> targetType = path.getTargetType();
180 if (Augmentation.class.isAssignableFrom(targetType)) {
181 path = mappingService.fromDataDom(biPath);
182 Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
183 DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
184 if (parentTo instanceof Augmentable<?>) {
185 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
188 return mappingService.dataObjectFromDataDom(path, result);
192 public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
194 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
195 CompositeNode result = biDataService.readConfigurationData(biPath);
196 return potentialAugmentationRead(path, biPath, result);
197 } catch (DeserializationException e) {
198 throw new IllegalStateException(e);
202 private DataModificationTransaction createBindingToDomTransaction(
203 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
204 DataModificationTransaction target = biDataService.beginTransaction();
205 LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier());
206 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
207 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
208 target.removeConfigurationData(biEntry);
209 LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
211 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
212 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
213 target.removeOperationalData(biEntry);
214 LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
216 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
218 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
220 target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
221 LOG.debug("Update of Binding Configuration Data {} is translated to {}",entry,biEntry);
223 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
225 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
227 target.putOperationalData(biEntry.getKey(), biEntry.getValue());
228 LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry);
234 private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
235 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
236 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
238 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
241 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
242 target.removeConfigurationData(baEntry);
243 } catch (DeserializationException e) {
244 LOG.error("Ommiting from BA transaction: {}.", entry, e);
247 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
250 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
251 target.removeOperationalData(baEntry);
252 } catch (DeserializationException e) {
253 LOG.error("Ommiting from BA transaction: {}.", entry, e);
256 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
257 .getUpdatedConfigurationData().entrySet()) {
259 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
260 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
261 target.putConfigurationData(baKey, baData);
262 } catch (DeserializationException e) {
263 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
266 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
267 .getUpdatedOperationalData().entrySet()) {
270 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
271 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
272 target.putOperationalData(baKey, baData);
273 } catch (DeserializationException e) {
274 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
280 public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
281 return biDataService;
284 protected void setDomDataService(final org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
285 this.biDataService = biDataService;
288 public DataProviderService getBaDataService() {
289 return baDataService;
292 protected void setBindingDataService(final DataProviderService baDataService) {
293 this.baDataService = baDataService;
296 public RpcProviderRegistry getRpcRegistry() {
297 return baRpcRegistry;
300 protected void setBindingRpcRegistry(final RpcProviderRegistry rpcRegistry) {
301 this.baRpcRegistry = rpcRegistry;
304 public void startDataForwarding() {
305 if(baDataService instanceof AbstractForwardedDataBroker) {
306 dataForwarding = true;
309 checkState(!dataForwarding, "Connector is already forwarding data.");
310 baDataReaderRegistration = baDataService.registerDataReader(ROOT, this);
311 baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
312 biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
313 baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
314 dataForwarding = true;
317 public void startRpcForwarding() {
318 if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
319 checkState(!rpcForwarding, "Connector is already forwarding RPCs");
320 domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
321 if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
322 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
323 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
324 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
326 rpcForwarding = true;
330 public void startNotificationForwarding() {
331 checkState(!notificationForwarding, "Connector is already forwarding notifications.");
332 if (baNotifyService != null && domNotificationService != null) {
333 baNotifyService.registerInterestListener(new DomToBindingNotificationForwarder());
335 notificationForwarding = true;
339 protected void setMappingService(final BindingIndependentMappingService mappingService) {
340 this.mappingService = mappingService;
344 public Collection<ProviderFunctionality> getProviderFunctionality() {
345 return Collections.emptyList();
349 public void onSessionInitiated(final ProviderSession session) {
350 setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
351 setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
355 public <T extends RpcService> void onRpcRouterCreated(final Class<T> serviceType, final RpcRouter<T> router) {
359 public void setDomRpcRegistry(final RpcProvisionRegistry registry) {
360 biRpcRegistry = registry;
364 public void close() throws Exception {
365 if (baCommitHandlerRegistration != null) {
366 baCommitHandlerRegistration.close();
368 if (biCommitHandlerRegistration != null) {
369 biCommitHandlerRegistration.close();
374 private class DomToBindingTransaction implements
375 DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
377 private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
378 private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
380 public DomToBindingTransaction(
381 final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
382 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
384 this.backing = backing;
385 this.modification = modification;
386 bindingOpenedTransactions.put(backing.getIdentifier(), this);
390 public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
395 public RpcResult<Void> rollback() throws IllegalStateException {
397 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
401 public RpcResult<Void> finish() throws IllegalStateException {
402 Future<RpcResult<TransactionStatus>> result = backing.commit();
404 RpcResult<TransactionStatus> baResult = result.get();
405 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
406 } catch (InterruptedException e) {
407 throw new IllegalStateException("", e);
408 } catch (ExecutionException e) {
409 throw new IllegalStateException("", e);
414 private class BindingToDomTransaction implements
415 DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
417 private final DataModificationTransaction backing;
418 private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
420 public BindingToDomTransaction(final DataModificationTransaction backing,
421 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
422 this.backing = backing;
423 this.modification = modification;
424 domOpenedTransactions.put(backing.getIdentifier(), this);
428 public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
433 public RpcResult<Void> finish() throws IllegalStateException {
434 Future<RpcResult<TransactionStatus>> result = backing.commit();
436 RpcResult<TransactionStatus> biResult = result.get();
437 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
438 } catch (InterruptedException e) {
439 throw new IllegalStateException("", e);
440 } catch (ExecutionException e) {
441 throw new IllegalStateException("", e);
443 domOpenedTransactions.remove(backing.getIdentifier());
448 public RpcResult<Void> rollback() throws IllegalStateException {
449 domOpenedTransactions.remove(backing.getIdentifier());
450 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
454 private class BindingToDomCommitHandler implements
455 DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
458 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
459 final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
462 * Transaction was created as DOM transaction, in that case we do
463 * not need to forward it back.
465 if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
467 return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction);
469 DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
470 BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
471 LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
472 domTransaction.getIdentifier());
477 private class DomToBindingCommitHandler implements //
478 RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject>>, //
479 DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
482 public void onRegister(final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
484 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
490 public void onUnregister(final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
492 // FIXME: do registration based on only active commit handlers.
496 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
497 final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
498 Object identifier = domTransaction.getIdentifier();
501 * We checks if the transcation was originated in this mapper. If it
502 * was originated in this mapper we are returing allways success
503 * commit hanlder to prevent creating loop in two-phase commit and
506 if (domOpenedTransactions.containsKey(identifier)) {
507 return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction);
510 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
511 DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
512 LOG.trace("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
513 baTransaction.getIdentifier());
514 return forwardedTransaction;
519 * Manager responsible for instantiating forwarders responsible for
520 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
523 private class DomToBindingRpcForwardingManager implements
524 RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
525 RouterInstantiationListener,
526 GlobalRpcRegistrationListener {
528 private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
529 private RpcProviderRegistryImpl registryImpl;
531 public RpcProviderRegistryImpl getRegistryImpl() {
535 public void setRegistryImpl(final RpcProviderRegistryImpl registryImpl) {
536 this.registryImpl = registryImpl;
540 public void onGlobalRpcRegistered(final Class<? extends RpcService> cls) {
541 getRpcForwarder(cls, null);
545 public void onGlobalRpcUnregistered(final Class<? extends RpcService> cls) {
550 public void onRpcRouterCreated(final RpcRouter<?> router) {
551 Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
552 getRpcForwarder(router.getServiceType(), ctx);
556 public void onRouteChange(final RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
557 for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
558 bindingRoutesAdded(entry);
562 private void bindingRoutesAdded(final Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
563 Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
564 Class<? extends RpcService> service = entry.getKey().getRpcService();
565 if (context != null) {
566 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
570 private DomToBindingRpcForwarder getRpcForwarder(final Class<? extends RpcService> service,
571 final Class<? extends BaseIdentity> context) {
572 DomToBindingRpcForwarder potential = forwarders.get(service);
573 if (potential != null) {
576 if (context == null) {
577 potential = new DomToBindingRpcForwarder(service);
579 potential = new DomToBindingRpcForwarder(service, context);
582 forwarders.put(service, potential);
588 private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
590 private final Set<QName> supportedRpcs;
591 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
592 private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
593 private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
594 private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
596 public DomToBindingRpcForwarder(final Class<? extends RpcService> service) {
597 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
598 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
600 for (QName rpc : supportedRpcs) {
601 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
602 strategiesByMethod.put(strategy.targetMethod, strategy);
603 strategiesByQName.put(rpc, strategy);
604 biRpcRegistry.addRpcImplementation(rpc, this);
607 } catch (Exception e) {
608 LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
610 registrations = ImmutableSet.of();
614 * Constructor for Routed RPC Forwareder.
619 public DomToBindingRpcForwarder(final Class<? extends RpcService> service, final Class<? extends BaseIdentity> context) {
620 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
621 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
622 Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
623 .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
625 for (QName rpc : supportedRpcs) {
626 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
627 strategiesByMethod.put(strategy.targetMethod, strategy);
628 strategiesByQName.put(rpc, strategy);
629 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
631 createDefaultDomForwarder();
632 } catch (Exception e) {
633 LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
635 registrations = registrationsBuilder.build();
638 public void registerPaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
639 final Set<InstanceIdentifier<?>> set) {
640 QName ctx = BindingReflections.findQName(context);
641 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
642 toDOMInstanceIdentifier)) {
643 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
644 reg.registerPath(ctx, path);
651 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
652 if (EQUALS_METHOD.equals(method)) {
655 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
656 checkState(strategy != null);
657 checkArgument(args.length <= 2);
658 if (args.length == 1) {
659 checkArgument(args[0] instanceof DataObject);
660 return strategy.forwardToDomBroker((DataObject) args[0]);
662 return strategy.forwardToDomBroker(null);
665 public void removePaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
666 final Set<InstanceIdentifier<?>> set) {
667 QName ctx = BindingReflections.findQName(context);
668 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
669 toDOMInstanceIdentifier)) {
670 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
671 reg.unregisterPath(ctx, path);
677 public Set<QName> getSupportedRpcs() {
678 return supportedRpcs;
681 @SuppressWarnings({ "unchecked", "rawtypes" })
682 public void createDefaultDomForwarder() {
683 if (baRpcRegistryImpl != null) {
684 Class<?> cls = rpcServiceType.get();
685 ClassLoader clsLoader = cls.getClassLoader();
686 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
688 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
689 rpcRouter.registerDefaultService(proxy);
694 public RpcResult<CompositeNode> invokeRpc(final QName rpc, final CompositeNode domInput) {
695 checkArgument(rpc != null);
696 checkArgument(domInput != null);
698 Class<? extends RpcService> rpcType = rpcServiceType.get();
699 checkState(rpcType != null);
700 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
701 checkState(rpcService != null);
702 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
704 return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput);
705 } catch (Exception e) {
706 throw new IllegalStateException(e);
710 private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc) {
711 return strategiesByQName.get(rpc);
714 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
715 final Class<? extends RpcService> rpcType) throws Exception {
716 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
718 public RpcInvocationStrategy call() throws Exception {
719 String methodName = BindingMapping.getMethodName(rpc);
720 Method targetMethod = null;
721 for (Method possibleMethod : rpcType.getMethods()) {
722 if (possibleMethod.getName().equals(methodName)
723 && BindingReflections.isRpcMethod(possibleMethod)) {
724 targetMethod = possibleMethod;
728 checkState(targetMethod != null, "Rpc method not found");
729 Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
730 Optional<Class<? extends DataContainer>> inputClass = BindingReflections
731 .resolveRpcInputClass(targetMethod);
733 RpcInvocationStrategy strategy = null;
734 if (outputClass.isPresent()) {
735 if (inputClass.isPresent()) {
736 strategy = new DefaultInvocationStrategy(rpc, targetMethod, outputClass.get(), inputClass
739 strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
741 } else if(inputClass.isPresent()){
742 strategy = new NoOutputInvocationStrategy(rpc,targetMethod, inputClass.get());
744 strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
753 private abstract class RpcInvocationStrategy {
755 protected final Method targetMethod;
756 protected final QName rpc;
758 public RpcInvocationStrategy(final QName rpc, final Method targetMethod) {
759 this.targetMethod = targetMethod;
763 public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
765 public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
768 public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput) throws Exception {
769 return uncheckedInvoke(rpcService, domInput);
773 private class DefaultInvocationStrategy extends RpcInvocationStrategy {
775 @SuppressWarnings("rawtypes")
776 private final WeakReference<Class> inputClass;
778 @SuppressWarnings("rawtypes")
779 private final WeakReference<Class> outputClass;
781 @SuppressWarnings({ "rawtypes", "unchecked" })
782 public DefaultInvocationStrategy(final QName rpc, final Method targetMethod, final Class<?> outputClass,
783 final Class<? extends DataContainer> inputClass) {
784 super(rpc, targetMethod);
785 this.outputClass = new WeakReference(outputClass);
786 this.inputClass = new WeakReference(inputClass);
789 @SuppressWarnings("unchecked")
791 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
792 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
793 Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
794 if (futureResult == null) {
795 return Rpcs.getRpcResult(false);
797 RpcResult<?> bindingResult = futureResult.get();
798 final Object resultObj = bindingResult.getResult();
799 if (resultObj instanceof DataObject) {
800 final CompositeNode output = mappingService.toDataDom((DataObject)resultObj);
801 return Rpcs.getRpcResult(true, output, Collections.<RpcError>emptySet());
803 return Rpcs.getRpcResult(true);
807 public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
808 if(biRpcRegistry != null) {
809 CompositeNode xml = mappingService.toDataDom(input);
810 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
811 RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
812 Object baResultValue = null;
813 if (result.getResult() != null) {
814 baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
816 RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
817 return Futures.<RpcResult<?>> immediateFuture(baResult);
819 return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
824 private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
826 public NoInputNoOutputInvocationStrategy(final QName rpc, final Method targetMethod) {
827 super(rpc, targetMethod);
831 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
832 @SuppressWarnings("unchecked")
833 Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
834 RpcResult<Void> bindingResult = result.get();
835 return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
839 public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
840 return Futures.immediateFuture(null);
844 private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
847 @SuppressWarnings("rawtypes")
848 private final WeakReference<Class> inputClass;
850 @SuppressWarnings({ "rawtypes", "unchecked" })
851 public NoOutputInvocationStrategy(final QName rpc, final Method targetMethod,
852 final Class<? extends DataContainer> inputClass) {
853 super(rpc,targetMethod);
854 this.inputClass = new WeakReference(inputClass);
859 public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
860 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
861 Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
862 if (result == null) {
863 return Rpcs.getRpcResult(false);
865 RpcResult<?> bindingResult = result.get();
866 return Rpcs.getRpcResult(true);
870 public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
871 if(biRpcRegistry != null) {
872 CompositeNode xml = mappingService.toDataDom(input);
873 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
874 RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
875 Object baResultValue = null;
876 RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
877 return Futures.<RpcResult<?>>immediateFuture(baResult);
879 return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
884 public boolean isRpcForwarding() {
885 return rpcForwarding;
888 public boolean isDataForwarding() {
889 return dataForwarding;
892 public boolean isNotificationForwarding() {
893 return notificationForwarding;
896 public BindingIndependentMappingService getMappingService() {
897 return mappingService;
900 public void setBindingNotificationService(final NotificationProviderService baService) {
901 this.baNotifyService = baService;
905 public void setDomNotificationService(final NotificationPublishService domService) {
906 this.domNotificationService = domService;
909 private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
911 private final ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
912 private final Set<QName> supportedNotifications = new HashSet<>();
915 public Set<QName> getSupportedNotifications() {
916 return Collections.unmodifiableSet(supportedNotifications);
920 public void onNotification(final CompositeNode notification) {
921 QName qname = notification.getNodeType();
922 WeakReference<Class<? extends Notification>> potential = notifications.get(qname);
923 if (potential != null) {
924 Class<? extends Notification> potentialClass = potential.get();
925 if (potentialClass != null) {
926 final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
929 if (baNotification instanceof Notification) {
930 baNotifyService.publish((Notification) baNotification);
937 public void onNotificationSubscribtion(final Class<? extends Notification> notificationType) {
938 QName qname = BindingReflections.findQName(notificationType);
940 WeakReference<Class<? extends Notification>> already = notifications.putIfAbsent(qname,
941 new WeakReference<Class<? extends Notification>>(notificationType));
942 if (already == null) {
943 domNotificationService.addNotificationListener(qname, this);
944 supportedNotifications.add(qname);