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;
21 import java.util.Map.Entry;
23 import java.util.WeakHashMap;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
30 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
31 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
32 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
33 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
34 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
35 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
36 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
37 import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
38 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
39 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
40 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
41 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
42 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
43 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
44 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
45 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
46 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
47 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
48 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener;
49 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
50 import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions;
51 import org.opendaylight.controller.sal.common.util.Rpcs;
52 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
53 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
54 import org.opendaylight.controller.sal.core.api.Provider;
55 import org.opendaylight.controller.sal.core.api.RpcImplementation;
56 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
57 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
58 import org.opendaylight.yangtools.concepts.ListenerRegistration;
59 import org.opendaylight.yangtools.concepts.Registration;
60 import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
61 import org.opendaylight.yangtools.yang.binding.Augmentable;
62 import org.opendaylight.yangtools.yang.binding.Augmentation;
63 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
64 import org.opendaylight.yangtools.yang.binding.BindingMapping;
65 import org.opendaylight.yangtools.yang.binding.DataContainer;
66 import org.opendaylight.yangtools.yang.binding.DataObject;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.binding.RpcService;
69 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
70 import org.opendaylight.yangtools.yang.common.QName;
71 import org.opendaylight.yangtools.yang.common.RpcError;
72 import org.opendaylight.yangtools.yang.common.RpcResult;
73 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
74 import org.opendaylight.yangtools.yang.data.api.Node;
75 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
79 import com.google.common.base.Function;
80 import com.google.common.base.Optional;
81 import com.google.common.collect.FluentIterable;
82 import com.google.common.collect.ImmutableList;
83 import com.google.common.collect.ImmutableSet;
84 import com.google.common.collect.ImmutableSet.Builder;
85 import com.google.common.util.concurrent.Futures;
87 public class BindingIndependentConnector implements //
88 RuntimeDataProvider, //
92 private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
94 @SuppressWarnings( "deprecation")
95 private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
97 private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
98 .builder().toInstance();
100 private final static Method EQUALS_METHOD;
103 private BindingIndependentMappingService mappingService;
105 private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
107 private DataProviderService baDataService;
109 private ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
110 private ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
112 private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
113 private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
115 private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
117 private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
119 private RpcProvisionRegistry biRpcRegistry;
120 private RpcProviderRegistry baRpcRegistry;
122 private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
123 // private ListenerRegistration<BindingToDomRpcForwardingManager>
124 // bindingToDomRpcManager;
126 private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
129 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
130 return mappingService.toDataDom(input);
135 private Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> baDataReaderRegistration;
137 private boolean rpcForwarding = false;
139 private boolean dataForwarding = false;
141 private boolean notificationForwarding = false;
143 private RpcProviderRegistryImpl baRpcRegistryImpl;
145 private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
150 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
151 } catch (Exception e) {
152 throw new RuntimeException(e);
157 public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
159 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
160 CompositeNode result = biDataService.readOperationalData(biPath);
161 return potentialAugmentationRead(path, biPath, result);
162 } catch (DeserializationException e) {
163 throw new IllegalStateException(e);
167 private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
168 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result)
169 throws DeserializationException {
170 Class<? extends DataObject> targetType = path.getTargetType();
171 if (Augmentation.class.isAssignableFrom(targetType)) {
172 path = mappingService.fromDataDom(biPath);
173 Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
174 DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
175 if (parentTo instanceof Augmentable<?>) {
176 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
179 return mappingService.dataObjectFromDataDom(path, result);
183 public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
185 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
186 CompositeNode result = biDataService.readConfigurationData(biPath);
187 return potentialAugmentationRead(path, biPath, result);
188 } catch (DeserializationException e) {
189 throw new IllegalStateException(e);
193 private DataModificationTransaction createBindingToDomTransaction(
194 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
195 DataModificationTransaction target = biDataService.beginTransaction();
196 LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier());
197 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
199 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
201 target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
202 LOG.debug("Update of Binding Configuration Data {} is translated to {}",entry,biEntry);
204 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
206 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
208 target.putOperationalData(biEntry.getKey(), biEntry.getValue());
209 LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry);
211 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
212 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
213 target.removeConfigurationData(biEntry);
214 LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
216 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
217 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
218 target.removeOperationalData(biEntry);
219 LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
224 private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
225 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
226 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
228 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
229 .getUpdatedConfigurationData().entrySet()) {
231 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
232 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
233 target.putConfigurationData(baKey, baData);
234 } catch (DeserializationException e) {
235 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
238 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
239 .getUpdatedOperationalData().entrySet()) {
242 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
243 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
244 target.putOperationalData(baKey, baData);
245 } catch (DeserializationException e) {
246 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
249 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
252 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
253 target.removeConfigurationData(baEntry);
254 } catch (DeserializationException e) {
255 LOG.error("Ommiting from BA transaction: {}.", entry, e);
258 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
261 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
262 target.removeOperationalData(baEntry);
263 } catch (DeserializationException e) {
264 LOG.error("Ommiting from BA transaction: {}.", entry, e);
270 public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
271 return biDataService;
274 protected void setDomDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
275 this.biDataService = biDataService;
278 public DataProviderService getBaDataService() {
279 return baDataService;
282 protected void setBindingDataService(DataProviderService baDataService) {
283 this.baDataService = baDataService;
286 public RpcProviderRegistry getRpcRegistry() {
287 return baRpcRegistry;
290 protected void setBindingRpcRegistry(RpcProviderRegistry rpcRegistry) {
291 this.baRpcRegistry = rpcRegistry;
294 public void startDataForwarding() {
295 checkState(!dataForwarding, "Connector is already forwarding data.");
296 baDataReaderRegistration = baDataService.registerDataReader(ROOT, this);
297 baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
298 biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
299 baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
300 dataForwarding = true;
303 public void startRpcForwarding() {
304 if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
305 checkState(!rpcForwarding, "Connector is already forwarding RPCs");
306 domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
307 if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
308 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
309 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
310 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
312 if(biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
313 biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
315 rpcForwarding = true;
319 public void startNotificationForwarding() {
320 checkState(!notificationForwarding, "Connector is already forwarding notifications.");
321 notificationForwarding = true;
324 protected void setMappingService(BindingIndependentMappingService mappingService) {
325 this.mappingService = mappingService;
329 public Collection<ProviderFunctionality> getProviderFunctionality() {
330 return Collections.emptyList();
334 public void onSessionInitiated(ProviderSession session) {
335 setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
336 setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
340 public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
344 public void setDomRpcRegistry(RpcProvisionRegistry registry) {
345 biRpcRegistry = registry;
349 public void close() throws Exception {
350 if (baCommitHandlerRegistration != null) {
351 baCommitHandlerRegistration.close();
353 if (biCommitHandlerRegistration != null) {
354 biCommitHandlerRegistration.close();
359 private class DomToBindingTransaction implements
360 DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
362 private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
363 private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
365 public DomToBindingTransaction(
366 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
367 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
369 this.backing = backing;
370 this.modification = modification;
371 bindingOpenedTransactions.put(backing.getIdentifier(), this);
375 public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
380 public RpcResult<Void> rollback() throws IllegalStateException {
382 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
386 public RpcResult<Void> finish() throws IllegalStateException {
387 Future<RpcResult<TransactionStatus>> result = backing.commit();
389 RpcResult<TransactionStatus> baResult = result.get();
390 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
391 } catch (InterruptedException e) {
392 throw new IllegalStateException("", e);
393 } catch (ExecutionException e) {
394 throw new IllegalStateException("", e);
399 private class BindingToDomTransaction implements
400 DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
402 private DataModificationTransaction backing;
403 private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
405 public BindingToDomTransaction(DataModificationTransaction backing,
406 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
407 this.backing = backing;
408 this.modification = modification;
409 domOpenedTransactions.put(backing.getIdentifier(), this);
413 public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
418 public RpcResult<Void> finish() throws IllegalStateException {
419 Future<RpcResult<TransactionStatus>> result = backing.commit();
421 RpcResult<TransactionStatus> biResult = result.get();
422 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
423 } catch (InterruptedException e) {
424 throw new IllegalStateException("", e);
425 } catch (ExecutionException e) {
426 throw new IllegalStateException("", e);
428 domOpenedTransactions.remove(backing.getIdentifier());
433 public RpcResult<Void> rollback() throws IllegalStateException {
434 domOpenedTransactions.remove(backing.getIdentifier());
435 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
439 private class BindingToDomCommitHandler implements
440 DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
443 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
444 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
447 * Transaction was created as DOM transaction, in that case we do
448 * not need to forward it back.
450 if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
452 return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction);
454 DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
455 BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
456 LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
457 domTransaction.getIdentifier());
462 private class DomToBindingCommitHandler implements //
463 RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject>>, //
464 DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
467 public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
469 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
475 public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
477 // FIXME: do registration based on only active commit handlers.
480 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
481 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
482 Object identifier = domTransaction.getIdentifier();
485 * We checks if the transcation was originated in this mapper. If it
486 * was originated in this mapper we are returing allways success
487 * commit hanlder to prevent creating loop in two-phase commit and
490 if (domOpenedTransactions.containsKey(identifier)) {
491 return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction);
494 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
495 DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
496 LOG.trace("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
497 baTransaction.getIdentifier());
498 return forwardedTransaction;
503 * Manager responsible for instantiating forwarders responsible for
504 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
507 private class DomToBindingRpcForwardingManager implements
508 RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
509 RouterInstantiationListener,
510 GlobalRpcRegistrationListener {
512 private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
513 private RpcProviderRegistryImpl registryImpl;
515 public RpcProviderRegistryImpl getRegistryImpl() {
519 public void setRegistryImpl(RpcProviderRegistryImpl registryImpl) {
520 this.registryImpl = registryImpl;
524 public void onGlobalRpcRegistered(Class<? extends RpcService> cls) {
525 getRpcForwarder(cls, null);
529 public void onGlobalRpcUnregistered(Class<? extends RpcService> cls) {
534 public void onRpcRouterCreated(RpcRouter<?> router) {
535 Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
536 getRpcForwarder(router.getServiceType(), ctx);
540 public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
541 for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
542 bindingRoutesAdded(entry);
546 private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
547 Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
548 Class<? extends RpcService> service = entry.getKey().getRpcService();
549 if (context != null) {
550 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
554 private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
555 Class<? extends BaseIdentity> context) {
556 DomToBindingRpcForwarder potential = forwarders.get(service);
557 if (potential != null) {
560 if (context == null) {
561 potential = new DomToBindingRpcForwarder(service);
563 potential = new DomToBindingRpcForwarder(service, context);
566 forwarders.put(service, potential);
572 private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
574 private final Set<QName> supportedRpcs;
575 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
576 private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
577 private Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
578 private WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
580 public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
581 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
582 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
584 for (QName rpc : supportedRpcs) {
585 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
586 strategiesByMethod.put(strategy.targetMethod, strategy);
587 strategiesByQName.put(rpc, strategy);
588 biRpcRegistry.addRpcImplementation(rpc, this);
591 } catch (Exception e) {
592 LOG.error("Could not forward Rpcs of type {}", service.getName());
594 registrations = ImmutableSet.of();
598 * Constructor for Routed RPC Forwareder.
603 public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
604 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
605 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
606 Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
607 .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
609 for (QName rpc : supportedRpcs) {
610 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
611 strategiesByMethod.put(strategy.targetMethod, strategy);
612 strategiesByQName.put(rpc, strategy);
613 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
615 createDefaultDomForwarder();
616 } catch (Exception e) {
617 LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
619 registrations = registrationsBuilder.build();
622 public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
623 Set<InstanceIdentifier<?>> set) {
624 QName ctx = BindingReflections.findQName(context);
625 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
626 toDOMInstanceIdentifier)) {
627 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
628 reg.registerPath(ctx, path);
635 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
636 if(EQUALS_METHOD.equals(method)) {
639 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
640 checkState(strategy != null);
641 checkArgument(args.length <= 2);
642 if(args.length == 1) {
643 checkArgument(args[0] instanceof DataObject);
644 return strategy.forwardToDomBroker((DataObject) args[0]);
646 return strategy.forwardToDomBroker(null);
649 public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
650 Set<InstanceIdentifier<?>> set) {
651 QName ctx = BindingReflections.findQName(context);
652 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
653 toDOMInstanceIdentifier)) {
654 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
655 reg.unregisterPath(ctx, path);
661 public Set<QName> getSupportedRpcs() {
662 return supportedRpcs;
665 @SuppressWarnings({ "unchecked", "rawtypes" })
666 public void createDefaultDomForwarder() {
667 if (baRpcRegistryImpl != null) {
668 Class<?> cls = rpcServiceType.get();
669 ClassLoader clsLoader = cls.getClassLoader();
670 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
672 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
673 rpcRouter.registerDefaultService(proxy);
678 public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
679 checkArgument(rpc != null);
680 checkArgument(domInput != null);
682 Class<? extends RpcService> rpcType = rpcServiceType.get();
683 checkState(rpcType != null);
684 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
685 checkState(rpcService != null);
686 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
688 return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput);
689 } catch (Exception e) {
690 throw new IllegalStateException(e);
694 private RpcInvocationStrategy resolveInvocationStrategy(QName rpc) {
695 return strategiesByQName.get(rpc);
698 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
699 final Class<? extends RpcService> rpcType) throws Exception {
700 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
702 public RpcInvocationStrategy call() throws Exception {
703 String methodName = BindingMapping.getMethodName(rpc);
704 Method targetMethod = null;
705 for (Method possibleMethod : rpcType.getMethods()) {
706 if (possibleMethod.getName().equals(methodName)
707 && BindingReflections.isRpcMethod(possibleMethod)) {
708 targetMethod = possibleMethod;
712 checkState(targetMethod != null, "Rpc method not found");
713 Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
714 Optional<Class<? extends DataContainer>> inputClass = BindingReflections
715 .resolveRpcInputClass(targetMethod);
717 RpcInvocationStrategy strategy = null;
718 if (outputClass.isPresent()) {
719 if (inputClass.isPresent()) {
720 strategy = new DefaultInvocationStrategy(rpc,targetMethod, outputClass.get(), inputClass.get());
722 strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
734 private abstract class RpcInvocationStrategy {
736 protected final Method targetMethod;
737 protected final QName rpc;
739 public RpcInvocationStrategy(QName rpc,Method targetMethod) {
740 this.targetMethod = targetMethod;
744 public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
746 public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
749 public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
750 return uncheckedInvoke(rpcService, domInput);
754 private class DefaultInvocationStrategy extends RpcInvocationStrategy {
756 @SuppressWarnings("rawtypes")
757 private WeakReference<Class> inputClass;
759 @SuppressWarnings("rawtypes")
760 private WeakReference<Class> outputClass;
762 @SuppressWarnings({ "rawtypes", "unchecked" })
763 public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
764 Class<? extends DataContainer> inputClass) {
765 super(rpc,targetMethod);
766 this.outputClass = new WeakReference(outputClass);
767 this.inputClass = new WeakReference(inputClass);
771 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
772 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
773 Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
774 if (result == null) {
775 return Rpcs.getRpcResult(false);
777 RpcResult<?> bindingResult = result.get();
778 return Rpcs.getRpcResult(true);
782 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
783 if(biRouter != null) {
784 CompositeNode xml = mappingService.toDataDom(input);
785 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
786 RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
787 Object baResultValue = null;
788 if(result.getResult() != null) {
789 baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
791 RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
792 return Futures.<RpcResult<?>>immediateFuture(baResult);
794 return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
799 private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
801 public NoInputNoOutputInvocationStrategy(QName rpc, Method targetMethod) {
802 super(rpc,targetMethod);
805 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
806 @SuppressWarnings("unchecked")
807 Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
808 RpcResult<Void> bindingResult = result.get();
809 return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
813 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
814 return Futures.immediateFuture(null);
818 public boolean isRpcForwarding() {
819 return rpcForwarding;
822 public boolean isDataForwarding() {
823 return dataForwarding;
826 public boolean isNotificationForwarding() {
827 // TODO Auto-generated method stub
828 return notificationForwarding;
831 public BindingIndependentMappingService getMappingService() {
832 return mappingService;