--- /dev/null
+/*
+ * 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.yangtools.yang.binding.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Future;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractMappedRpcInvoker<T> extends RpcServiceInvoker {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractMappedRpcInvoker.class);
+ private final Map<T, RpcMethodInvoker> map;
+
+ protected AbstractMappedRpcInvoker(final Map<T, Method> map) {
+ final Builder<T, RpcMethodInvoker> b = ImmutableMap.builder();
+
+ for (Entry<T, Method> e : map.entrySet()) {
+ if (BindingReflections.isRpcMethod(e.getValue())) {
+ b.put(e.getKey(), RpcMethodInvoker.from(e.getValue()));
+ } else {
+ LOG.debug("Method {} is not an RPC method, ignoring it", e.getValue());
+ }
+ }
+
+ this.map = b.build();
+ }
+
+ protected abstract T qnameToKey(final QName qname);
+
+ @Override
+ public final Future<RpcResult<?>> invokeRpc(@Nonnull final RpcService impl, @Nonnull final QName rpcName, @Nullable final DataObject input) {
+ Preconditions.checkNotNull(impl, "implemetation must be supplied");
+
+ RpcMethodInvoker invoker = map.get(qnameToKey(rpcName));
+ Preconditions.checkArgument(invoker != null, "Supplied RPC is not valid for implementation %s", impl);
+ return invoker.invokeOn(impl, input);
+ }
+}
--- /dev/null
+/*
+ * 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.yangtools.yang.binding.util;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+
+final class ClassBasedRpcServiceInvoker extends AbstractMappedRpcInvoker<String> {
+ private static final LoadingCache<Class<? extends RpcService>, RpcServiceInvoker> INVOKERS = CacheBuilder.newBuilder()
+ .weakKeys()
+ .build(new CacheLoader<Class<? extends RpcService>, RpcServiceInvoker>() {
+ @Override
+ public RpcServiceInvoker load(final Class<? extends RpcService> key) {
+ final Map<String, Method> ret = new HashMap<>();
+ for (Method m : key.getMethods()) {
+ ret.put(m.getName(), m);
+ }
+
+ return new ClassBasedRpcServiceInvoker(ret);
+ }
+ });
+
+ ClassBasedRpcServiceInvoker(final Map<String, Method> ret) {
+ super(ret);
+ }
+
+ @Override
+ protected String qnameToKey(final QName qname) {
+ return BindingMapping.getMethodName(qname);
+ }
+
+ static RpcServiceInvoker instanceFor(final Class<? extends RpcService> type) {
+ Preconditions.checkArgument(type.isInterface());
+ Preconditions.checkArgument(BindingReflections.isBindingClass(type));
+ return INVOKERS.getUnchecked(type);
+ }
+}
--- /dev/null
+/*
+ * 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.yangtools.yang.binding.util;
+
+import com.google.common.base.Preconditions;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+final class LocalNameRpcServiceInvoker extends AbstractMappedRpcInvoker<String> {
+ private final QNameModule module;
+
+ private LocalNameRpcServiceInvoker(final QNameModule module, final Map<String, Method> map) {
+ super(map);
+ this.module = Preconditions.checkNotNull(module);
+ }
+
+ static RpcServiceInvoker instanceFor(final QNameModule module, final Map<QName, Method> qnameToMethod) {
+ final Map<String, Method> map = new HashMap<>();
+ for (Entry<QName, Method> e : qnameToMethod.entrySet()) {
+ map.put(e.getKey().getLocalName(), e.getValue());
+ }
+
+ return new LocalNameRpcServiceInvoker(module, map);
+ }
+
+ @Override
+ protected String qnameToKey(final QName qname) {
+ if (module.equals(qname.getModule())) {
+ return qname.getLocalName();
+ } else {
+ return null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.yangtools.yang.binding.util;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+
+final class QNameRpcServiceInvoker extends AbstractMappedRpcInvoker<QName> {
+ private QNameRpcServiceInvoker(final Map<QName, Method> qnameToMethod) {
+ super(qnameToMethod);
+ }
+
+ static RpcServiceInvoker instanceFor(final Map<QName, Method> qnameToMethod) {
+ return new QNameRpcServiceInvoker(qnameToMethod);
+ }
+
+ @Override
+ protected QName qnameToKey(final QName qname) {
+ return qname;
+ }
+}
protected abstract Future<RpcResult<?>> invokeOn(RpcService impl, DataObject input);
- protected static RpcMethodInvoker from(Method method) {
+ protected static RpcMethodInvoker from(final Method method) {
Optional<Class<? extends DataContainer>> input = BindingReflections.resolveRpcInputClass(method);
try {
MethodHandle methodHandle = LOOKUP.unreflect(method);
- if(input.isPresent()) {
+ if (input.isPresent()) {
return new RpcMethodInvokerWithInput(methodHandle);
}
return new RpcMethodInvokerWithoutInput(methodHandle);
package org.opendaylight.yangtools.yang.binding.util;
import com.google.common.base.Preconditions;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.Future;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Provides single method invocation of RPCs on supplied instance.
*
* Rpc Service invoker provides common invocation interface for any subtype of {@link RpcService}.
* via {@link #invokeRpc(RpcService, QName, DataObject)} method.
- *
- *
- *
*/
-public final class RpcServiceInvoker {
-
- private static final LoadingCache<Class<? extends RpcService>, RpcServiceInvoker> INVOKERS = CacheBuilder.newBuilder()
- .weakKeys()
- .build(new CacheLoader<Class<? extends RpcService>, RpcServiceInvoker>() {
-
- @Override
- public RpcServiceInvoker load(Class<? extends RpcService> key) throws Exception {
- return createInvoker(key);
- }
-
- });
-
- private final Map<String, RpcMethodInvoker> methodInvokers;
-
- private RpcServiceInvoker(Map<String, RpcMethodInvoker> methodInvokers) {
- this.methodInvokers = Preconditions.checkNotNull(methodInvokers);
- }
+public abstract class RpcServiceInvoker {
+ private static final Logger LOG = LoggerFactory.getLogger(RpcServiceInvoker.class);
/**
- *
* Creates RPCServiceInvoker for specified RpcService type
*
* @param type RpcService interface, which was generated from model.
* @return Cached instance of {@link RpcServiceInvoker} for supplied RPC type.
*
*/
- public static RpcServiceInvoker from(Class<? extends RpcService> type) {
- Preconditions.checkArgument(type.isInterface());
- Preconditions.checkArgument(BindingReflections.isBindingClass(type));
- return INVOKERS.getUnchecked(type);
+ public static RpcServiceInvoker from(final Class<? extends RpcService> type) {
+ return ClassBasedRpcServiceInvoker.instanceFor(type);
}
/**
- * Invokes supplied RPC on provided implementation of RPC Service.
+ * Creates an RPCServiceInvoker for specified QName-<Method mapping.
*
- * @param impl Imlementation on which RPC should be invoked.
- * @param rpcName Name of RPC to be invoked.
- * @param input Input data for RPC.
- * @return Future which will complete once rpc procesing is finished.
+ * @param qnameToMethod translation mapping, must not be null nor empty.
+ * @return An {@link RpcMethodInvoker} instance.
*/
- public Future<RpcResult<?>> invokeRpc(@Nonnull RpcService impl, @Nonnull QName rpcName,@Nullable DataObject input ) {
- Preconditions.checkNotNull(impl, "implemetation must be supplied");
- return invoke(impl,BindingMapping.getMethodName(rpcName),input);
- }
-
- private static RpcServiceInvoker createInvoker(Class<? extends RpcService> key) {
- return new RpcServiceInvoker(createInvokerMap(key));
- }
+ public static RpcServiceInvoker from(final Map<QName, Method> qnameToMethod) {
+ Preconditions.checkArgument(!qnameToMethod.isEmpty());
+ QNameModule module = null;
- private static Map<String, RpcMethodInvoker> createInvokerMap(Class<? extends RpcService> key) {
- Builder<String, RpcMethodInvoker> ret = ImmutableMap.<String, RpcMethodInvoker>builder();
- for(Method method : key.getMethods()) {
- if(BindingReflections.isRpcMethod(method)) {
- ret.put(method.getName(), RpcMethodInvoker.from(method));
+ for (QName qname : qnameToMethod.keySet()) {
+ if (module != null) {
+ if (!module.equals(qname.getModule())) {
+ LOG.debug("QNames from different modules {} and {}, falling back to QName map", module, qname.getModule());
+ return QNameRpcServiceInvoker.instanceFor(qnameToMethod);
+ }
+ } else {
+ module = qname.getModule();
}
-
}
- return ret.build();
- }
- private Future<RpcResult<?>> invoke(RpcService impl, String methodName, DataObject input) {
- RpcMethodInvoker invoker = methodInvokers.get(methodName);
- Preconditions.checkArgument(invoker != null,"Supplied rpc is not valid for implementation %s",impl);
- return invoker.invokeOn(impl, input);
+ // All module are equal, which means we can use localName only
+ return LocalNameRpcServiceInvoker.instanceFor(module, qnameToMethod);
}
+
+ /**
+ * Invokes supplied RPC on provided implementation of RPC Service.
+ *
+ * @param impl Imlementation on which RPC should be invoked.
+ * @param rpcName Name of RPC to be invoked.
+ * @param input Input data for RPC.
+ * @return Future which will complete once rpc procesing is finished.
+ */
+ public abstract Future<RpcResult<?>> invokeRpc(@Nonnull final RpcService impl, @Nonnull final QName rpcName, @Nullable final DataObject input);
}