X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-binding-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fbinding%2Fimpl%2FRpcServiceAdapter.java;h=f9163ce78ad739460987a6ca56b30fc7eb0b6a35;hp=61b32324a9d6b1c5db39e562c6a98f24e5e0e493;hb=b830d5ede22e323fe724cd747fe99280dfa2240d;hpb=d8d8f731bbe6c58fcbd0e616734e2e230aaf4ab4 diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/RpcServiceAdapter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/RpcServiceAdapter.java index 61b32324a9..f9163ce78a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/RpcServiceAdapter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/RpcServiceAdapter.java @@ -1,40 +1,81 @@ /* - * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2015 Cisco 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.md.sal.binding.impl; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.Map.Entry; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.md.sal.dom.broker.spi.rpc.RpcRoutingStrategy; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 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.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaPath; class RpcServiceAdapter implements InvocationHandler { - interface InvocationDelegate { - - ListenableFuture> invoke(SchemaPath rpc, DataObject dataObject); + private final ImmutableMap rpcNames; + private final Class type; + private final BindingToNormalizedNodeCodec codec; + private final DOMRpcService delegate; + private final RpcService proxy; + RpcServiceAdapter(final Class type, final BindingToNormalizedNodeCodec codec, + final DOMRpcService domService) { + this.type = Preconditions.checkNotNull(type); + this.codec = Preconditions.checkNotNull(codec); + this.delegate = Preconditions.checkNotNull(domService); + final ImmutableMap.Builder rpcBuilder = ImmutableMap.builder(); + for (final Entry rpc : codec.getRpcMethodToSchema(type).entrySet()) { + rpcBuilder.put(rpc.getKey(), createStrategy(rpc.getKey(), rpc.getValue())); + } + rpcNames = rpcBuilder.build(); + proxy = (RpcService) Proxy.newProxyInstance(type.getClassLoader(), new Class[] {type}, this); } - private final RpcService proxy; - private final ImmutableMap rpcNames; - private final Class type; - private final InvocationDelegate delegate; + private ListenableFuture> invoke0(final SchemaPath schemaPath, final NormalizedNode input) { + final CheckedFuture result = delegate.invokeRpc(schemaPath, input); + if(result instanceof LazyDOMRpcResultFuture) { + return ((LazyDOMRpcResultFuture) result).getBindingFuture(); + } - RpcServiceAdapter(Class type, ImmutableMap rpcNames, InvocationDelegate delegate) { - this.rpcNames = rpcNames; - this.type = type; - this.delegate = delegate; - this.proxy = (RpcService) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, this); + return transformFuture(schemaPath, result, codec.getCodecFactory()); + } + + private RpcInvocationStrategy createStrategy(final Method method, final RpcDefinition schema) { + final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(schema); + if (strategy.isContextBasedRouted()) { + return new RoutedStrategy(schema.getPath(), method, strategy.getLeaf()); + } + return new NonRoutedStrategy(schema.getPath()); } RpcService getProxy() { @@ -42,46 +83,130 @@ class RpcServiceAdapter implements InvocationHandler { } @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { - SchemaPath rpc = rpcNames.get(method); - if(rpc != null) { - if(method.getParameterTypes().length == 0) { - return delegate.invoke(rpc, null); + final RpcInvocationStrategy rpc = rpcNames.get(method); + if (rpc != null) { + if (method.getParameterTypes().length == 0) { + return rpc.invokeEmpty(); } - if(args.length != 1) { + if (args.length != 1) { throw new IllegalArgumentException("Input must be provided."); } - return delegate.invoke(rpc,(DataObject) args[0]); + return rpc.invoke((DataObject) args[0]); } - if(isObjectMethod(method)) { + if (isObjectMethod(method)) { return callObjectMethod(proxy, method, args); } throw new UnsupportedOperationException("Method " + method.toString() + "is unsupported."); } - private static boolean isObjectMethod(Method m) { + private static boolean isObjectMethod(final Method m) { switch (m.getName()) { - case "toString": - return (m.getReturnType() == String.class && m.getParameterTypes().length == 0); - case "hashCode": - return (m.getReturnType() == int.class && m.getParameterTypes().length == 0); - case "equals": - return (m.getReturnType() == boolean.class && m.getParameterTypes().length == 1 && m.getParameterTypes()[0] == Object.class); + case "toString": + return (m.getReturnType().equals(String.class) && m.getParameterTypes().length == 0); + case "hashCode": + return (m.getReturnType().equals(int.class) && m.getParameterTypes().length == 0); + case "equals": + return (m.getReturnType().equals(boolean.class) && m.getParameterTypes().length == 1 && m + .getParameterTypes()[0] == Object.class); + default: + return false; } - return false; } - private Object callObjectMethod(Object self, Method m, Object[] args) { + private Object callObjectMethod(final Object self, final Method m, final Object[] args) { switch (m.getName()) { - case "toString": - return type.getName() + "$Adapter{delegate=" + delegate.toString()+"}"; - case "hashCode": - return System.identityHashCode(self); - case "equals": - return (self == args[0]); + case "toString": + return type.getName() + "$Adapter{delegate=" + delegate.toString() + "}"; + case "hashCode": + return System.identityHashCode(self); + case "equals": + return (self == args[0]); + default: + return null; } - return null; + } + + private static ListenableFuture> transformFuture(final SchemaPath rpc, + final ListenableFuture domFuture, final BindingNormalizedNodeCodecRegistry codec) { + return Futures.transform(domFuture, new Function>() { + @Override + public RpcResult apply(final DOMRpcResult input) { + final NormalizedNode domData = input.getResult(); + final DataObject bindingResult; + if (domData != null) { + final SchemaPath rpcOutput = rpc.createChild(QName.create(rpc.getLastComponent(), "output")); + bindingResult = codec.fromNormalizedNodeRpcData(rpcOutput, (ContainerNode) domData); + } else { + bindingResult = null; + } + return RpcResult.class.cast(RpcResultBuilder.success(bindingResult).build()); + } + }); + } + + private abstract class RpcInvocationStrategy { + + private final SchemaPath rpcName; + + protected RpcInvocationStrategy(final SchemaPath path) { + rpcName = path; + } + + final ListenableFuture> invoke(final DataObject input) { + return invoke0(rpcName, serialize(input)); + } + + abstract NormalizedNode serialize(DataObject input); + + final ListenableFuture> invokeEmpty() { + return invoke0(rpcName, null); + } + + final SchemaPath getRpcName() { + return rpcName; + } + + } + + private final class NonRoutedStrategy extends RpcInvocationStrategy { + + protected NonRoutedStrategy(final SchemaPath path) { + super(path); + } + + @Override + NormalizedNode serialize(final DataObject input) { + return LazySerializedContainerNode.create(getRpcName(), input, codec.getCodecRegistry()); + } + + } + + private final class RoutedStrategy extends RpcInvocationStrategy { + + private final ContextReferenceExtractor refExtractor; + private final NodeIdentifier contextName; + + protected RoutedStrategy(final SchemaPath path, final Method rpcMethod, final QName leafName) { + super(path); + final Class inputType = BindingReflections.resolveRpcInputClass(rpcMethod).get(); + refExtractor = ContextReferenceExtractor.from(inputType); + this.contextName = new NodeIdentifier(leafName); + } + + @Override + NormalizedNode serialize(final DataObject input) { + final InstanceIdentifier bindingII = refExtractor.extract(input); + if (bindingII != null) { + final YangInstanceIdentifier yangII = codec.toYangInstanceIdentifierCached(bindingII); + final LeafNode contextRef = ImmutableNodes.leafNode(contextName, yangII); + return LazySerializedContainerNode.withContextRef(getRpcName(), input, contextRef, + codec.getCodecRegistry()); + } + return LazySerializedContainerNode.create(getRpcName(), input, codec.getCodecRegistry()); + } + } }