2 * Copyright (c) 2013 Cisco 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
8 package org.opendaylight.yangtools.yang.binding.util;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Throwables;
12 import com.google.common.cache.CacheBuilder;
13 import com.google.common.cache.CacheLoader;
14 import com.google.common.cache.LoadingCache;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.ImmutableMap.Builder;
17 import java.lang.invoke.MethodHandle;
18 import java.lang.invoke.MethodHandles;
19 import java.lang.invoke.MethodHandles.Lookup;
20 import java.lang.invoke.MethodType;
21 import java.lang.reflect.Method;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import org.opendaylight.yangtools.yang.binding.DataContainer;
26 import org.opendaylight.yangtools.yang.binding.NotificationListener;
27 import org.opendaylight.yangtools.yang.common.QName;
30 * Provides single method invocation of notificatoin callbacks on supplied instance.
32 * Notification Listener invoker provides common invocation interface for any subtype of {@link NotificationListener}.
33 * via {@link #invokeNotification(NotificationListener, QName, DataContainer)} method.
36 public final class NotificationListenerInvoker {
38 private static final Lookup LOOKUP = MethodHandles.publicLookup();
40 private static final LoadingCache<Class<? extends NotificationListener>, NotificationListenerInvoker> INVOKERS = CacheBuilder
41 .newBuilder().weakKeys()
42 .build(new CacheLoader<Class<? extends NotificationListener>, NotificationListenerInvoker>() {
45 public NotificationListenerInvoker load(final Class<? extends NotificationListener> key) throws Exception {
46 return createInvoker(key);
51 private final Map<QName, MethodHandle> methodInvokers;
53 public NotificationListenerInvoker(final Map<QName, MethodHandle> map) {
54 this.methodInvokers = map;
59 * Creates RPCServiceInvoker for specified RpcService type
62 * RpcService interface, which was generated from model.
63 * @return Cached instance of {@link NotificationListenerInvoker} for
67 public static NotificationListenerInvoker from(final Class<? extends NotificationListener> type) {
68 Preconditions.checkArgument(type.isInterface());
69 Preconditions.checkArgument(BindingReflections.isBindingClass(type));
70 return INVOKERS.getUnchecked(type);
74 * Invokes supplied RPC on provided implementation of RPC Service.
77 * Imlementation on which notifiaction callback should be
80 * Name of RPC to be invoked.
85 public void invokeNotification(@Nonnull final NotificationListener impl, @Nonnull final QName rpcName,
86 @Nullable final DataContainer input) {
87 Preconditions.checkNotNull(impl, "implemetation must be supplied");
88 final MethodHandle invoker = methodInvokers.get(rpcName);
89 Preconditions.checkArgument(invoker != null, "Supplied notification is not valid for implementation %s", impl);
91 invoker.invokeExact(impl, input);
92 } catch (final Throwable e) {
93 throw Throwables.propagate(e);
97 private static NotificationListenerInvoker createInvoker(final Class<? extends NotificationListener> key) {
98 return new NotificationListenerInvoker(createInvokerMap(key));
101 private static Map<QName, MethodHandle> createInvokerMap(final Class<? extends NotificationListener> key) {
102 final Builder<QName, MethodHandle> ret = ImmutableMap.<QName, MethodHandle>builder();
103 for (final Method method : key.getMethods()) {
104 if (BindingReflections.isNotificationCallback(method)) {
106 final Class<?> notification = method.getParameterTypes()[0];
107 final QName name = BindingReflections.findQName(notification);
110 handle = LOOKUP.unreflect(method).asType(
111 MethodType.methodType(void.class, NotificationListener.class, DataContainer.class));
112 ret.put(name, handle);
113 } catch (final IllegalAccessException e) {
114 throw new IllegalStateException("Can not access public method.", e);