/* * Copyright 2016 Kejun Xia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.shipdream.lib.android.mvc.event.bus.internal; import com.shipdream.lib.android.mvc.event.bus.EventBus; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.LinkedHashMap; import java.util.Map; public class EventBusImpl implements EventBus { Map<Class<?>, Map<Object, Method>> subscribers = new LinkedHashMap<>(); public void register(Object subscriber) { if(subscriber == null) { throw new IllegalArgumentException("Subscriber registering to an event bus must not be NULL"); } Class<?> subscriberClass = subscriber.getClass(); while (subscriberClass != null) { String name = subscriberClass.getName(); if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { // Ignore system classes break; } Method[] methods = subscriberClass.getDeclaredMethods(); for (Method method : methods) { if (method.getName().equals("onEvent") && method.getParameterTypes().length == 1) { Class<?> eventType = method.getParameterTypes()[0]; Map<Object, Method> subs = subscribers.get(eventType); if (subs == null) { subs = new LinkedHashMap<>(); subscribers.put(eventType, subs); } subs.put(subscriber, method); } } subscriberClass = subscriberClass.getSuperclass(); } } public void unregister(Object subscriber) { if(subscriber == null) { throw new IllegalArgumentException("Subscriber unregistering to an event bus must not be NULL"); } Class<?> subscriberClass = subscriber.getClass(); while (subscriberClass != null) { String name = subscriberClass.getName(); if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { // Ignore system classes break; } Method[] methods = subscriberClass.getDeclaredMethods(); for (Method method : methods) { if (method.getName().equals("onEvent") && method.getParameterTypes().length == 1) { Class eventType = method.getParameterTypes()[0]; Map<Object, Method> subs = subscribers.get(eventType); if(subs != null) { subs.remove(subscriber); if (subs.isEmpty()) { subscribers.remove(eventType); } } } } subscriberClass = subscriberClass.getSuperclass(); } } public void post(Object event) { if(event == null) { throw new IllegalArgumentException("Event2C bus can't post a NULL event"); } Map<Object, Method> subs = subscribers.get(event.getClass()); if(subs != null) { for (Map.Entry<Object, Method> entry : subs.entrySet()) { entry.getValue().setAccessible(true); try { entry.getValue().invoke(entry.getKey(), event); } catch (IllegalAccessException e) { //This should never happen since setAccessible has already opened the access throw new RuntimeException("Not able to post event - " + event.getClass().getName() + " due to IllegalAccessException: " + e.getMessage(), e); } catch (InvocationTargetException e) { String msg = e.getMessage(); if (msg == null || msg.isEmpty() && e.getCause() != null) { msg = e.getCause().getMessage(); } throw new RuntimeException("Not able to post event - " + event.getClass().getName() + " due to error: " + msg, e); } } } } }