/* ** Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. ** ** This program and the accompanying materials are made available under the ** terms of the Eclipse Public License v1.0 which accompanies this distribution, ** and is available at http://www.eclipse.org/legal/epl-v10.html **/ package org.opendaylight.controller.sal.binding.impl.connect.dom; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.util.Collections; import java.util.concurrent.Future; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; /* * RPC's can have both input, output, one or the other, or neither. * * This class handles the permutations and provides two means of invocation: * 1. forwardToDomBroker * 2. * * Weak References to the input and output classes are used to allow these classes to * be from another OSGi bundle/class loader which may come and go. * */ public class RpcInvocationStrategy { private final BindingIndependentMappingService mappingService; private final RpcProvisionRegistry biRpcRegistry; protected final Method targetMethod; protected final QName rpc; @SuppressWarnings("rawtypes") private final WeakReference inputClass; @SuppressWarnings("rawtypes") private final WeakReference outputClass; @SuppressWarnings({ "rawtypes" }) public RpcInvocationStrategy(final QName rpc, final Method targetMethod, final BindingIndependentMappingService mappingService, final RpcProvisionRegistry biRpcRegistry ) { this.targetMethod = targetMethod; this.rpc = rpc; Optional> outputClassOption = BindingReflections.resolveRpcOutputClass(targetMethod); Optional> inputClassOption = BindingReflections.resolveRpcInputClass(targetMethod); if ( outputClassOption != null && outputClassOption.isPresent() ) { this.outputClass = new WeakReference(outputClassOption.get() ) ; } else { this.outputClass = null ; } if ( inputClassOption != null && inputClassOption.isPresent() ) { this.inputClass = new WeakReference(inputClassOption.get() ) ; } else { this.inputClass = null ; } this.mappingService = mappingService; this.biRpcRegistry = biRpcRegistry; } @SuppressWarnings({ "unchecked" }) public ListenableFuture> forwardToDomBroker(final DataObject input) { if(biRpcRegistry == null) { return Futures.> immediateFuture(RpcResultBuilder.failed().build()); } CompositeNode inputXml = null; if( input != null ) { CompositeNode xml = mappingService.toDataDom(input); inputXml = ImmutableCompositeNode.create(rpc, ImmutableList.> of(xml)); } else { inputXml = ImmutableCompositeNode.create( rpc, Collections.>emptyList() ); } Function, RpcResult> transformationFunction = new Function, RpcResult>() { @SuppressWarnings("rawtypes") @Override public RpcResult apply(RpcResult result) { Object output = null; if( getOutputClass() != null ) { if (result.getResult() != null) { output = mappingService.dataObjectFromDataDom(getOutputClass().get(), result.getResult()); } } return RpcResultBuilder.from( (RpcResult)result ).withResult( output ).build(); } }; return Futures.transform(biRpcRegistry.invokeRpc(rpc, inputXml), transformationFunction); } @SuppressWarnings("unchecked") private RpcResult uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception { Future> futureResult = null; if( inputClass != null ){ DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput); futureResult = (Future>) targetMethod.invoke(rpcService, bindingInput); } else { futureResult = (Future>) targetMethod.invoke(rpcService); } if (futureResult == null) { return RpcResultBuilder.failed().build(); } @SuppressWarnings("rawtypes") RpcResult bindingResult = futureResult.get(); final Object resultObj = bindingResult.getResult(); Object output = null; if (resultObj instanceof DataObject) { output = mappingService.toDataDom((DataObject)resultObj); } return RpcResultBuilder.from( bindingResult ).withResult( output ).build(); } public RpcResult invokeOn(final RpcService rpcService, final CompositeNode domInput) throws Exception { return uncheckedInvoke(rpcService, domInput); } @SuppressWarnings("rawtypes") public WeakReference getOutputClass() { return outputClass; } }