f98c8b8a53f3f6d1476ef9df377e7fbab112e285
[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 implements org.opendaylight.controller.sal.binding.api.NotificationListener<Notification> {
24
25     private final NotificationListener delegate;
26     private final Map<Class<? extends Notification>,InvokerContext> invokers;
27
28
29     private NotificationInvoker(final NotificationListener listener) {
30         delegate = listener;
31         final Map<Class<? extends Notification>, InvokerContext> builder = new HashMap<>();
32         for(final TypeToken<?> ifaceToken : TypeToken.of(listener.getClass()).getTypes().interfaces()) {
33             final Class<?> iface = ifaceToken.getRawType();
34             if(NotificationListener.class.isAssignableFrom(iface) && BindingReflections.isBindingClass(iface)) {
35                 @SuppressWarnings("unchecked")
36                 final Class<? extends NotificationListener> listenerType = (Class<? extends NotificationListener>) iface;
37                 final NotificationListenerInvoker invoker = NotificationListenerInvoker.from(listenerType);
38                 for(final Class<? extends Notification> type : getNotificationTypes(listenerType)) {
39                     builder.put(type, new InvokerContext(BindingReflections.findQName(type) , invoker));
40                 }
41             }
42         }
43         invokers = ImmutableMap.copyOf(builder);
44     }
45
46     public static NotificationInvoker invokerFor(final NotificationListener listener) {
47         return new NotificationInvoker(listener);
48     }
49
50     public Set<Class<? extends Notification>> getSupportedNotifications() {
51         return invokers.keySet();
52     }
53
54     @Override
55     public void onNotification(final Notification notification) {
56         getContext(notification.getImplementedInterface()).invoke(notification);
57     }
58
59     private InvokerContext getContext(final Class<?> type) {
60         return invokers.get(type);
61     }
62
63     @SuppressWarnings("unchecked")
64     private static Set<Class<? extends Notification>> getNotificationTypes(final Class<? extends org.opendaylight.yangtools.yang.binding.NotificationListener> type) {
65         // TODO: Investigate possibility and performance impact if we cache this or expose
66         // it from NotificationListenerInvoker
67         final Set<Class<? extends Notification>> ret = new HashSet<>();
68         for(final Method method : type.getMethods()) {
69             if(BindingReflections.isNotificationCallback(method)) {
70                 final Class<? extends Notification> notification = (Class<? extends Notification>) method.getParameterTypes()[0];
71                 ret.add(notification);
72             }
73         }
74         return ret;
75     }
76
77     private final class InvokerContext {
78
79         private final QName name;
80         private final NotificationListenerInvoker invoker;
81
82         private InvokerContext(final QName name, final NotificationListenerInvoker invoker) {
83             this.name = name;
84             this.invoker = invoker;
85         }
86
87         public void invoke(final Notification notification) {
88             invoker.invokeNotification(delegate, name, notification);
89         }
90
91     }
92
93 }