1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.eventbus; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.base.Preconditions; 22 23 import java.lang.reflect.InvocationTargetException; 24 import java.lang.reflect.Method; 25 26 import javax.annotation.Nullable; 27 28 /** 29 * Wraps a single-argument subscriber method on a specific object. 30 * 31 * <p>This class only verifies the suitability of the method and event type if 32 * something fails. Callers are expected to verify their uses of this class. 33 * 34 * <p>Two EventSubscribers are equivalent when they refer to the same method on the 35 * same object (not class). This property is used to ensure that no subscriber 36 * method is registered more than once. 37 * 38 * @author Cliff Biffle 39 */ 40 class EventSubscriber { 41 42 /** Object sporting the subscriber method. */ 43 private final Object target; 44 /** Subscriber method. */ 45 private final Method method; 46 47 /** 48 * Creates a new EventSubscriber to wrap {@code method} on @{code target}. 49 * 50 * @param target object to which the method applies. 51 * @param method subscriber method. 52 */ EventSubscriber(Object target, Method method)53 EventSubscriber(Object target, Method method) { 54 Preconditions.checkNotNull(target, 55 "EventSubscriber target cannot be null."); 56 Preconditions.checkNotNull(method, "EventSubscriber method cannot be null."); 57 58 this.target = target; 59 this.method = method; 60 method.setAccessible(true); 61 } 62 63 /** 64 * Invokes the wrapped subscriber method to handle {@code event}. 65 * 66 * @param event event to handle 67 * @throws InvocationTargetException if the wrapped method throws any 68 * {@link Throwable} that is not an {@link Error} ({@code Error} instances are 69 * propagated as-is). 70 */ handleEvent(Object event)71 public void handleEvent(Object event) throws InvocationTargetException { 72 checkNotNull(event); 73 try { 74 method.invoke(target, new Object[] { event }); 75 } catch (IllegalArgumentException e) { 76 throw new Error("Method rejected target/argument: " + event, e); 77 } catch (IllegalAccessException e) { 78 throw new Error("Method became inaccessible: " + event, e); 79 } catch (InvocationTargetException e) { 80 if (e.getCause() instanceof Error) { 81 throw (Error) e.getCause(); 82 } 83 throw e; 84 } 85 } 86 toString()87 @Override public String toString() { 88 return "[wrapper " + method + "]"; 89 } 90 hashCode()91 @Override public int hashCode() { 92 final int PRIME = 31; 93 return (PRIME + method.hashCode()) * PRIME 94 + System.identityHashCode(target); 95 } 96 equals(@ullable Object obj)97 @Override public boolean equals(@Nullable Object obj) { 98 if (obj instanceof EventSubscriber) { 99 EventSubscriber that = (EventSubscriber) obj; 100 // Use == so that different equal instances will still receive events. 101 // We only guard against the case that the same object is registered 102 // multiple times 103 return target == that.target && method.equals(that.method); 104 } 105 return false; 106 } 107 getSubscriber()108 public Object getSubscriber() { 109 return target; 110 } 111 getMethod()112 public Method getMethod() { 113 return method; 114 } 115 } 116