2 ** Copyright (c) 2014 Brocade Communications 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
9 package org.opendaylight.controller.sal.binding.impl.connect.dom;
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Function;
13 import com.google.common.base.Optional;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.lang.ref.WeakReference;
18 import java.lang.reflect.Method;
19 import java.util.Collections;
20 import java.util.concurrent.Future;
21 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
22 import org.opendaylight.yangtools.yang.binding.DataContainer;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.RpcService;
25 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.common.RpcResult;
28 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
29 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
30 import org.opendaylight.yangtools.yang.data.api.Node;
31 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
32 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
35 * RPC's can have both input, output, one or the other, or neither.
37 * This class handles the permutations and provides two means of invocation:
38 * 1. forwardToDomBroker
41 * Weak References to the input and output classes are used to allow these classes to
42 * be from another OSGi bundle/class loader which may come and go.
45 public class RpcInvocationStrategy {
46 private final Function<RpcResult<CompositeNode>, RpcResult<?>> transformationFunction = new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
47 @SuppressWarnings("rawtypes")
49 public RpcResult<?> apply(final RpcResult<CompositeNode> result) {
51 if (getOutputClass() != null && result.getResult() != null) {
52 output = mappingService.dataObjectFromDataDom(getOutputClass().get(), result.getResult());
57 return RpcResultBuilder.from( (RpcResult)result ).withResult( output ).build();
61 private final BindingIndependentMappingService mappingService;
62 private final RpcProvisionRegistry biRpcRegistry;
63 protected final Method targetMethod;
64 protected final QName rpc;
66 @SuppressWarnings("rawtypes")
67 private final WeakReference<Class> inputClass;
69 @SuppressWarnings("rawtypes")
70 private final WeakReference<Class> outputClass;
72 @SuppressWarnings({ "rawtypes" })
73 public RpcInvocationStrategy(final QName rpc,
74 final Method targetMethod,
75 final BindingIndependentMappingService mappingService,
76 final RpcProvisionRegistry biRpcRegistry ) {
77 this.mappingService = mappingService;
78 this.biRpcRegistry = biRpcRegistry;
79 this.targetMethod = targetMethod;
82 final Optional<Class<?>> outputClassOption = BindingReflections.resolveRpcOutputClass(targetMethod);
83 if (outputClassOption.isPresent()) {
84 this.outputClass = new WeakReference(outputClassOption.get());
86 this.outputClass = null;
89 final Optional<Class<? extends DataContainer>> inputClassOption = BindingReflections.resolveRpcInputClass(targetMethod);
90 if (inputClassOption.isPresent() ) {
91 this.inputClass = new WeakReference(inputClassOption.get());
93 this.inputClass = null;
97 @SuppressWarnings({ "unchecked" })
98 public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
100 if(biRpcRegistry == null) {
101 return Futures.<RpcResult<?>> immediateFuture(RpcResultBuilder.failed().build());
104 CompositeNode inputXml = null;
105 if( input != null ) {
106 CompositeNode xml = mappingService.toDataDom(input);
107 inputXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
109 inputXml = ImmutableCompositeNode.create( rpc, Collections.<Node<?>>emptyList() );
112 return Futures.transform(biRpcRegistry.invokeRpc(rpc, inputXml), transformationFunction);
115 @SuppressWarnings("unchecked")
116 private RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
118 Future<RpcResult<?>> futureResult = null;
120 if( inputClass != null ){
121 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
122 futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
125 futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService);
128 if (futureResult == null) {
129 return RpcResultBuilder.<CompositeNode>failed().build();
132 @SuppressWarnings("rawtypes")
133 RpcResult bindingResult = futureResult.get();
135 final Object resultObj = bindingResult.getResult();
136 Object output = null;
137 if (resultObj instanceof DataObject) {
138 output = mappingService.toDataDom((DataObject)resultObj);
140 return RpcResultBuilder.from( bindingResult ).withResult( output ).build();
143 public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput) throws Exception {
144 return uncheckedInvoke(rpcService, domInput);
147 @SuppressWarnings("rawtypes")
149 WeakReference<Class> getOutputClass() {