b803c96b80c7ec998e3f257ab12a4e9f4bb59382
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / compat / NotificationInvoker.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.sal.binding.compat;
9
10 import com.google.common.collect.ImmutableMap;
11 import com.google.common.reflect.TypeToken;
12 import java.lang.reflect.Method;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Map;
16 import java.util.Set;
17 import org.opendaylight.yangtools.yang.binding.Notification;
18 import org.opendaylight.yangtools.yang.binding.NotificationListener;
19 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
20 import org.opendaylight.yangtools.yang.binding.util.NotificationListenerInvoker;
21 import org.opendaylight.yangtools.yang.common.QName;
22
23 final class NotificationInvoker
24         implements org.opendaylight.controller.sal.binding.api.NotificationListener<Notification> {
25
26     private final NotificationListener delegate;
27     private final Map<Class<? extends Notification>,InvokerContext> invokers;
28
29
30     private NotificationInvoker(final NotificationListener listener) {
31         delegate = listener;
32         final Map<Class<? extends Notification>, InvokerContext> builder = new HashMap<>();
33         for (final TypeToken<?> ifaceToken : TypeToken.of(listener.getClass()).getTypes().interfaces()) {
34             final Class<?> iface = ifaceToken.getRawType();
35             if (NotificationListener.class.isAssignableFrom(iface) && BindingReflections.isBindingClass(iface)) {
36                 @SuppressWarnings("unchecked")
37                 final Class<? extends NotificationListener> listenerType =
38                         (Class<? extends NotificationListener>) iface;
39                 final NotificationListenerInvoker invoker = NotificationListenerInvoker.from(listenerType);
40                 for (final Class<? extends Notification> type : getNotificationTypes(listenerType)) {
41                     builder.put(type, new InvokerContext(BindingReflections.findQName(type), invoker));
42                 }
43             }
44         }
45         invokers = ImmutableMap.copyOf(builder);
46     }
47
48     public static NotificationInvoker invokerFor(final NotificationListener listener) {
49         return new NotificationInvoker(listener);
50     }
51
52     public Set<Class<? extends Notification>> getSupportedNotifications() {
53         return invokers.keySet();
54     }
55
56     @Override
57     public void onNotification(final Notification notification) {
58         getContext(notification.getImplementedInterface()).invoke(notification);
59     }
60
61     private InvokerContext getContext(final Class<?> type) {
62         return invokers.get(type);
63     }
64
65     @SuppressWarnings("unchecked")
66     private static Set<Class<? extends Notification>> getNotificationTypes(
67             final Class<? extends org.opendaylight.yangtools.yang.binding.NotificationListener> type) {
68         // TODO: Investigate possibility and performance impact if we cache this or expose
69         // it from NotificationListenerInvoker
70         final Set<Class<? extends Notification>> ret = new HashSet<>();
71         for (final Method method : type.getMethods()) {
72             if (BindingReflections.isNotificationCallback(method)) {
73                 final Class<? extends Notification> notification =
74                         (Class<? extends Notification>) method.getParameterTypes()[0];
75                 ret.add(notification);
76             }
77         }
78         return ret;
79     }
80
81     private final class InvokerContext {
82
83         private final QName name;
84         private final NotificationListenerInvoker invoker;
85
86         private InvokerContext(final QName name, final NotificationListenerInvoker invoker) {
87             this.name = name;
88             this.invoker = invoker;
89         }
90
91         public void invoke(final Notification notification) {
92             invoker.invokeNotification(delegate, name, notification);
93         }
94     }
95 }