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 java.lang.ref.WeakReference;
12 import java.lang.reflect.Method;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.concurrent.Future;
17 import org.opendaylight.controller.sal.common.util.Rpcs;
18 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
19 import org.opendaylight.yangtools.yang.binding.DataContainer;
20 import org.opendaylight.yangtools.yang.binding.DataObject;
21 import org.opendaylight.yangtools.yang.binding.RpcService;
22 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.RpcError;
25 import org.opendaylight.yangtools.yang.common.RpcResult;
26 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
27 import org.opendaylight.yangtools.yang.data.api.Node;
28 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
29 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
31 import com.google.common.base.Function;
32 import com.google.common.base.Optional;
33 import com.google.common.collect.ImmutableList;
34 import com.google.common.util.concurrent.Futures;
35 import com.google.common.util.concurrent.ListenableFuture;
38 * RPC's can have both input, output, one or the other, or neither.
40 * This class handles the permutations and provides two means of invocation:
41 * 1. forwardToDomBroker
44 * Weak References to the input and output classes are used to allow these classes to
45 * be from another OSGi bundle/class loader which may come and go.
48 public class RpcInvocationStrategy {
50 private final BindingIndependentMappingService mappingService;
51 private final RpcProvisionRegistry biRpcRegistry;
52 protected final Method targetMethod;
53 protected final QName rpc;
55 @SuppressWarnings("rawtypes")
56 private final WeakReference<Class> inputClass;
58 @SuppressWarnings("rawtypes")
59 private final WeakReference<Class> outputClass;
61 @SuppressWarnings({ "rawtypes" })
62 public RpcInvocationStrategy(final QName rpc,
63 final Method targetMethod,
64 final BindingIndependentMappingService mappingService,
65 final RpcProvisionRegistry biRpcRegistry ) {
67 this.targetMethod = targetMethod;
70 Optional<Class<?>> outputClassOption = BindingReflections.resolveRpcOutputClass(targetMethod);
71 Optional<Class<? extends DataContainer>> inputClassOption = BindingReflections.resolveRpcInputClass(targetMethod);
73 if ( outputClassOption != null && outputClassOption.isPresent() ) {
74 this.outputClass = new WeakReference(outputClassOption.get() ) ;
76 this.outputClass = null ;
78 if ( inputClassOption != null && inputClassOption.isPresent() ) {
79 this.inputClass = new WeakReference(inputClassOption.get() ) ;
81 this.inputClass = null ;
84 this.mappingService = mappingService;
85 this.biRpcRegistry = biRpcRegistry;
88 @SuppressWarnings({ "unchecked" })
89 public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
91 if(biRpcRegistry == null) {
92 return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
95 CompositeNode inputXml = null;
97 CompositeNode xml = mappingService.toDataDom(input);
98 inputXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
100 inputXml = ImmutableCompositeNode.create( rpc, Collections.<Node<?>>emptyList() );
103 Function<RpcResult<CompositeNode>, RpcResult<?>> transformationFunction =
104 new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
106 public RpcResult<?> apply(RpcResult<CompositeNode> result) {
108 Object output = null;
110 if( getOutputClass() != null ) {
111 if (result.getResult() != null) {
112 output = mappingService.dataObjectFromDataDom(getOutputClass().get(),
117 return Rpcs.getRpcResult(result.isSuccessful(), output, result.getErrors());
121 return Futures.transform(biRpcRegistry.invokeRpc(rpc, inputXml), transformationFunction);
124 @SuppressWarnings("unchecked")
125 private RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
127 Future<RpcResult<?>> futureResult = null;
129 if( inputClass != null ){
130 DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
131 futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
134 futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService);
137 if (futureResult == null) {
138 return Rpcs.getRpcResult(false);
141 RpcResult<?> bindingResult = futureResult.get();
143 Collection<RpcError> errors = bindingResult.getErrors();
144 if( errors == null ) {
145 errors = Collections.<RpcError>emptySet();
148 final Object resultObj = bindingResult.getResult();
149 CompositeNode output = null;
150 if (resultObj instanceof DataObject) {
151 output = mappingService.toDataDom((DataObject)resultObj);
153 return Rpcs.getRpcResult( bindingResult.isSuccessful(), output, errors);
156 public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput) throws Exception {
157 return uncheckedInvoke(rpcService, domInput);
160 @SuppressWarnings("rawtypes")
161 public WeakReference<Class> getOutputClass() {