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.controller.sal.binding.impl.RpcProviderRegistryImpl;
46 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
47 import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions;
48 import org.opendaylight.controller.sal.common.util.Rpcs;
49 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
50 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
51 import org.opendaylight.controller.sal.core.api.Provider;
52 import org.opendaylight.controller.sal.core.api.RpcImplementation;
53 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
54 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
55 import org.opendaylight.yangtools.concepts.ListenerRegistration;
56 import org.opendaylight.yangtools.concepts.Registration;
57 import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
58 import org.opendaylight.yangtools.yang.binding.Augmentable;
59 import org.opendaylight.yangtools.yang.binding.Augmentation;
60 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
61 import org.opendaylight.yangtools.yang.binding.BindingMapping;
62 import org.opendaylight.yangtools.yang.binding.DataContainer;
63 import org.opendaylight.yangtools.yang.binding.DataObject;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.binding.RpcService;
66 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
67 import org.opendaylight.yangtools.yang.common.QName;
68 import org.opendaylight.yangtools.yang.common.RpcError;
69 import org.opendaylight.yangtools.yang.common.RpcResult;
70 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
71 import org.opendaylight.yangtools.yang.data.api.Node;
72 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
76 import com.google.common.base.Function;
77 import com.google.common.base.Optional;
78 import com.google.common.collect.FluentIterable;
79 import com.google.common.collect.ImmutableList;
80 import com.google.common.collect.ImmutableSet;
81 import com.google.common.collect.ImmutableSet.Builder;
82 import com.google.common.util.concurrent.Futures;
84 public class BindingIndependentConnector implements //
85 RuntimeDataProvider, //
89 private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
91 @SuppressWarnings( "deprecation")
92 private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
94 private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
95 .builder().toInstance();
97 private final static Method EQUALS_METHOD;
100 private BindingIndependentMappingService mappingService;
102 private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
104 private DataProviderService baDataService;
106 private ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
107 private ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
109 private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
110 private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
112 private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
114 private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
116 private RpcProvisionRegistry biRpcRegistry;
117 private RpcProviderRegistry baRpcRegistry;
119 private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
120 // private ListenerRegistration<BindingToDomRpcForwardingManager>
121 // bindingToDomRpcManager;
123 private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
126 public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
127 return mappingService.toDataDom(input);
132 private Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> baDataReaderRegistration;
134 private boolean rpcForwarding = false;
136 private boolean dataForwarding = false;
138 private boolean notificationForwarding = false;
140 private RpcProviderRegistryImpl baRpcRegistryImpl;
142 private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
147 EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
148 } catch (Exception e) {
149 throw new RuntimeException(e);
154 public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
156 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
157 CompositeNode result = biDataService.readOperationalData(biPath);
158 return potentialAugmentationRead(path, biPath, result);
159 } catch (DeserializationException e) {
160 throw new IllegalStateException(e);
164 private DataObject potentialAugmentationRead(InstanceIdentifier<? extends DataObject> path,
165 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result)
166 throws DeserializationException {
167 Class<? extends DataObject> targetType = path.getTargetType();
168 if (Augmentation.class.isAssignableFrom(targetType)) {
169 path = mappingService.fromDataDom(biPath);
170 Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
171 DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
172 if (parentTo instanceof Augmentable<?>) {
173 return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
176 return mappingService.dataObjectFromDataDom(path, result);
180 public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
182 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
183 CompositeNode result = biDataService.readConfigurationData(biPath);
184 return potentialAugmentationRead(path, biPath, result);
185 } catch (DeserializationException e) {
186 throw new IllegalStateException(e);
190 private DataModificationTransaction createBindingToDomTransaction(
191 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
192 DataModificationTransaction target = biDataService.beginTransaction();
193 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
195 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
197 target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
199 for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
201 Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
203 target.putOperationalData(biEntry.getKey(), biEntry.getValue());
205 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
206 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
207 target.removeConfigurationData(biEntry);
209 for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
210 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
211 target.removeOperationalData(biEntry);
216 private org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction createDomToBindingTransaction(
217 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
218 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
220 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
221 .getUpdatedConfigurationData().entrySet()) {
223 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
224 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
225 target.putConfigurationData(baKey, baData);
226 } catch (DeserializationException e) {
227 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
230 for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
231 .getUpdatedOperationalData().entrySet()) {
234 InstanceIdentifier<?> baKey = mappingService.fromDataDom(entry.getKey());
235 DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
236 target.putOperationalData(baKey, baData);
237 } catch (DeserializationException e) {
238 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
241 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
244 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
245 target.removeConfigurationData(baEntry);
246 } catch (DeserializationException e) {
247 LOG.error("Ommiting from BA transaction: {}.", entry, e);
250 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
253 InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
254 target.removeOperationalData(baEntry);
255 } catch (DeserializationException e) {
256 LOG.error("Ommiting from BA transaction: {}.", entry, e);
262 public org.opendaylight.controller.sal.core.api.data.DataProviderService getBiDataService() {
263 return biDataService;
266 protected void setDomDataService(org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
267 this.biDataService = biDataService;
270 public DataProviderService getBaDataService() {
271 return baDataService;
274 protected void setBindingDataService(DataProviderService baDataService) {
275 this.baDataService = baDataService;
278 public RpcProviderRegistry getRpcRegistry() {
279 return baRpcRegistry;
282 protected void setBindingRpcRegistry(RpcProviderRegistry rpcRegistry) {
283 this.baRpcRegistry = rpcRegistry;
286 public void startDataForwarding() {
287 checkState(!dataForwarding, "Connector is already forwarding data.");
288 baDataReaderRegistration = baDataService.registerDataReader(ROOT, this);
289 baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
290 biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
291 baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
292 dataForwarding = true;
295 public void startRpcForwarding() {
296 if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
297 checkState(!rpcForwarding, "Connector is already forwarding RPCs");
298 domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
299 if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
300 baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
301 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
303 if(biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
304 biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
306 rpcForwarding = true;
310 public void startNotificationForwarding() {
311 checkState(!notificationForwarding, "Connector is already forwarding notifications.");
312 notificationForwarding = true;
315 protected void setMappingService(BindingIndependentMappingService mappingService) {
316 this.mappingService = mappingService;
320 public Collection<ProviderFunctionality> getProviderFunctionality() {
321 return Collections.emptyList();
325 public void onSessionInitiated(ProviderSession session) {
326 setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class));
327 setDomRpcRegistry(session.getService(RpcProvisionRegistry.class));
331 public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
335 public void setDomRpcRegistry(RpcProvisionRegistry registry) {
336 biRpcRegistry = registry;
340 public void close() throws Exception {
341 if (baCommitHandlerRegistration != null) {
342 baCommitHandlerRegistration.close();
344 if (biCommitHandlerRegistration != null) {
345 biCommitHandlerRegistration.close();
350 private class DomToBindingTransaction implements
351 DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
353 private final org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing;
354 private final DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification;
356 public DomToBindingTransaction(
357 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction backing,
358 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> modification) {
360 this.backing = backing;
361 this.modification = modification;
362 bindingOpenedTransactions.put(backing.getIdentifier(), this);
366 public DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getModification() {
371 public RpcResult<Void> rollback() throws IllegalStateException {
373 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
377 public RpcResult<Void> finish() throws IllegalStateException {
378 Future<RpcResult<TransactionStatus>> result = backing.commit();
380 RpcResult<TransactionStatus> baResult = result.get();
381 return Rpcs.<Void> getRpcResult(baResult.isSuccessful(), null, baResult.getErrors());
382 } catch (InterruptedException e) {
383 throw new IllegalStateException("", e);
384 } catch (ExecutionException e) {
385 throw new IllegalStateException("", e);
390 private class BindingToDomTransaction implements
391 DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
393 private DataModificationTransaction backing;
394 private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
396 public BindingToDomTransaction(DataModificationTransaction backing,
397 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
398 this.backing = backing;
399 this.modification = modification;
400 domOpenedTransactions.put(backing.getIdentifier(), this);
404 public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
409 public RpcResult<Void> finish() throws IllegalStateException {
410 Future<RpcResult<TransactionStatus>> result = backing.commit();
412 RpcResult<TransactionStatus> biResult = result.get();
413 return Rpcs.<Void> getRpcResult(biResult.isSuccessful(), null, biResult.getErrors());
414 } catch (InterruptedException e) {
415 throw new IllegalStateException("", e);
416 } catch (ExecutionException e) {
417 throw new IllegalStateException("", e);
419 domOpenedTransactions.remove(backing.getIdentifier());
424 public RpcResult<Void> rollback() throws IllegalStateException {
425 domOpenedTransactions.remove(backing.getIdentifier());
426 return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
430 private class BindingToDomCommitHandler implements
431 DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
434 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> requestCommit(
435 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> bindingTransaction) {
438 * Transaction was created as DOM transaction, in that case we do
439 * not need to forward it back.
441 if (bindingOpenedTransactions.containsKey(bindingTransaction.getIdentifier())) {
443 return CommitHandlerTransactions.allwaysSuccessfulTransaction(bindingTransaction);
445 DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
446 BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
447 LOG.info("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
448 domTransaction.getIdentifier());
453 private class DomToBindingCommitHandler implements //
454 RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject>>, //
455 DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
458 public void onRegister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
460 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
466 public void onUnregister(DataCommitHandlerRegistration<InstanceIdentifier<?>, DataObject> registration) {
468 // FIXME: do registration based on only active commit handlers.
471 public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
472 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
473 Object identifier = domTransaction.getIdentifier();
476 * We checks if the transcation was originated in this mapper. If it
477 * was originated in this mapper we are returing allways success
478 * commit hanlder to prevent creating loop in two-phase commit and
481 if (domOpenedTransactions.containsKey(identifier)) {
482 return CommitHandlerTransactions.allwaysSuccessfulTransaction(domTransaction);
485 org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction baTransaction = createDomToBindingTransaction(domTransaction);
486 DomToBindingTransaction forwardedTransaction = new DomToBindingTransaction(baTransaction, domTransaction);
487 LOG.info("Forwarding DOM Transaction: {} as Binding Transaction: {}.", domTransaction.getIdentifier(),
488 baTransaction.getIdentifier());
489 return forwardedTransaction;
494 * Manager responsible for instantiating forwarders responsible for
495 * forwarding of RPC invocations from DOM Broker to Binding Aware Broker
498 private class DomToBindingRpcForwardingManager implements
499 RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
500 RouterInstantiationListener {
502 private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
503 private RpcProviderRegistryImpl registryImpl;
505 public RpcProviderRegistryImpl getRegistryImpl() {
509 public void setRegistryImpl(RpcProviderRegistryImpl registryImpl) {
510 this.registryImpl = registryImpl;
515 public void onRpcRouterCreated(RpcRouter<?> router) {
516 Class<? extends BaseIdentity> ctx = router.getContexts().iterator().next();
517 getRpcForwarder(router.getServiceType(), ctx);
521 public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
522 for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
523 bindingRoutesAdded(entry);
527 private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
528 Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
529 Class<? extends RpcService> service = entry.getKey().getRpcService();
530 if (context != null) {
531 getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
535 private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
536 Class<? extends BaseIdentity> context) {
537 DomToBindingRpcForwarder potential = forwarders.get(service);
538 if (potential != null) {
541 if (context == null) {
542 potential = new DomToBindingRpcForwarder(service);
544 potential = new DomToBindingRpcForwarder(service, context);
547 forwarders.put(service, potential);
553 private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
555 private final Set<QName> supportedRpcs;
556 private final WeakReference<Class<? extends RpcService>> rpcServiceType;
557 private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
558 private Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
559 private WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
561 public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
562 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
563 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
565 for (QName rpc : supportedRpcs) {
566 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
567 strategiesByMethod.put(strategy.targetMethod, strategy);
568 strategiesByQName.put(rpc, strategy);
569 biRpcRegistry.addRpcImplementation(rpc, this);
572 } catch (Exception e) {
573 LOG.error("Could not forward Rpcs of type {}", service.getName());
575 registrations = ImmutableSet.of();
579 * Constructor for Routed RPC Forwareder.
584 public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
585 this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
586 this.supportedRpcs = mappingService.getRpcQNamesFor(service);
587 Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
588 .<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
590 for (QName rpc : supportedRpcs) {
591 RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
592 strategiesByMethod.put(strategy.targetMethod, strategy);
593 strategiesByQName.put(rpc, strategy);
594 registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
596 createDefaultDomForwarder();
597 } catch (Exception e) {
598 LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
600 registrations = registrationsBuilder.build();
603 public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
604 Set<InstanceIdentifier<?>> set) {
605 QName ctx = BindingReflections.findQName(context);
606 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
607 toDOMInstanceIdentifier)) {
608 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
609 reg.registerPath(ctx, path);
616 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
617 if(EQUALS_METHOD.equals(method)) {
620 RpcInvocationStrategy strategy = strategiesByMethod.get(method);
621 checkState(strategy != null);
622 checkArgument(args.length <= 2);
623 if(args.length == 1) {
624 checkArgument(args[0] instanceof DataObject);
625 return strategy.forwardToDomBroker((DataObject) args[0]);
627 return strategy.forwardToDomBroker(null);
630 public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
631 Set<InstanceIdentifier<?>> set) {
632 QName ctx = BindingReflections.findQName(context);
633 for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
634 toDOMInstanceIdentifier)) {
635 for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
636 reg.unregisterPath(ctx, path);
642 public Set<QName> getSupportedRpcs() {
643 return supportedRpcs;
646 @SuppressWarnings({ "unchecked", "rawtypes" })
647 public void createDefaultDomForwarder() {
648 if (baRpcRegistryImpl != null) {
649 Class<?> cls = rpcServiceType.get();
650 ClassLoader clsLoader = cls.getClassLoader();
651 RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
653 RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get());
654 rpcRouter.registerDefaultService(proxy);
659 public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
660 checkArgument(rpc != null);
661 checkArgument(domInput != null);
663 Class<? extends RpcService> rpcType = rpcServiceType.get();
664 checkState(rpcType != null);
665 RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
666 checkState(rpcService != null);
667 CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
669 return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput);
670 } catch (Exception e) {
671 throw new IllegalStateException(e);
675 private RpcInvocationStrategy resolveInvocationStrategy(QName rpc) {
676 return strategiesByQName.get(rpc);
679 private RpcInvocationStrategy createInvocationStrategy(final QName rpc,
680 final Class<? extends RpcService> rpcType) throws Exception {
681 return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
683 public RpcInvocationStrategy call() throws Exception {
684 String methodName = BindingMapping.getMethodName(rpc);
685 Method targetMethod = null;
686 for (Method possibleMethod : rpcType.getMethods()) {
687 if (possibleMethod.getName().equals(methodName)
688 && BindingReflections.isRpcMethod(possibleMethod)) {
689 targetMethod = possibleMethod;
693 checkState(targetMethod != null, "Rpc method not found");
694 Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
695 Optional<Class<? extends DataContainer>> inputClass = BindingReflections
696 .resolveRpcInputClass(targetMethod);
698 RpcInvocationStrategy strategy = null;
699 if (outputClass.isPresent()) {
700 if (inputClass.isPresent()) {
701 strategy = new DefaultInvocationStrategy(rpc,targetMethod, outputClass.get(), inputClass.get());
703 strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
715 private abstract class RpcInvocationStrategy {
717 protected final Method targetMethod;
718 protected final QName rpc;
720 public RpcInvocationStrategy(QName rpc,Method targetMethod) {
721 this.targetMethod = targetMethod;
725 public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
727 public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
730 public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
731 return uncheckedInvoke(rpcService, domInput);
735 private class DefaultInvocationStrategy extends RpcInvocationStrategy {
737 @SuppressWarnings("rawtypes")
738 private WeakReference<Class> inputClass;
740 @SuppressWarnings("rawtypes")
741 private WeakReference<Class> outputClass;
743 @SuppressWarnings({ "rawtypes", "unchecked" })
744 public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
745 Class<? extends DataContainer> inputClass) {
746 super(rpc,targetMethod);
747 this.outputClass = new WeakReference(outputClass);
748 this.inputClass = new WeakReference(inputClass);
752 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
753 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
754 Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
755 if (result == null) {
756 return Rpcs.getRpcResult(false);
758 RpcResult<?> bindingResult = result.get();
759 return Rpcs.getRpcResult(true);
763 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
764 if(biRouter != null) {
765 CompositeNode xml = mappingService.toDataDom(input);
766 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
767 RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
768 Object baResultValue = null;
769 if(result.getResult() != null) {
770 baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
772 RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
773 return Futures.<RpcResult<?>>immediateFuture(baResult);
775 return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
780 private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
782 public NoInputNoOutputInvocationStrategy(QName rpc, Method targetMethod) {
783 super(rpc,targetMethod);
786 public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
787 @SuppressWarnings("unchecked")
788 Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
789 RpcResult<Void> bindingResult = result.get();
790 return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
794 public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
795 return Futures.immediateFuture(null);
799 public boolean isRpcForwarding() {
800 return rpcForwarding;
803 public boolean isDataForwarding() {
804 return dataForwarding;
807 public boolean isNotificationForwarding() {
808 // TODO Auto-generated method stub
809 return notificationForwarding;
812 public BindingIndependentMappingService getMappingService() {
813 return mappingService;