11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License. 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License. 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.eventbus; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static com.google.common.base.Preconditions.checkNotNull; 207dd252788645e940eada959bdde927426e2531c9Paul Duffin 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Preconditions; 227dd252788645e940eada959bdde927426e2531c9Paul Duffin 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.InvocationTargetException; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.reflect.Method; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport javax.annotation.Nullable; 277dd252788645e940eada959bdde927426e2531c9Paul Duffin 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 290888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Wraps a single-argument subscriber method on a specific object. 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This class only verifies the suitability of the method and event type if 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * something fails. Callers are expected to verify their uses of this class. 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 340888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>Two EventSubscribers are equivalent when they refer to the same method on the 350888a09821a98ac0680fad765217302858e70fa4Paul Duffin * same object (not class). This property is used to ensure that no subscriber 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * method is registered more than once. 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Cliff Biffle 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 400888a09821a98ac0680fad765217302858e70fa4Paul Duffinclass EventSubscriber { 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 420888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** Object sporting the subscriber method. */ 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Object target; 440888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** Subscriber method. */ 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Method method; 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 480888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Creates a new EventSubscriber to wrap {@code method} on @{code target}. 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param target object to which the method applies. 510888a09821a98ac0680fad765217302858e70fa4Paul Duffin * @param method subscriber method. 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 530888a09821a98ac0680fad765217302858e70fa4Paul Duffin EventSubscriber(Object target, Method method) { 540888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(target, 550888a09821a98ac0680fad765217302858e70fa4Paul Duffin "EventSubscriber target cannot be null."); 560888a09821a98ac0680fad765217302858e70fa4Paul Duffin Preconditions.checkNotNull(method, "EventSubscriber method cannot be null."); 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.target = target; 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.method = method; 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert method.setAccessible(true); 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 640888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Invokes the wrapped subscriber method to handle {@code event}. 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param event event to handle 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws InvocationTargetException if the wrapped method throws any 687dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@link Throwable} that is not an {@link Error} ({@code Error} instances are 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * propagated as-is). 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void handleEvent(Object event) throws InvocationTargetException { 727dd252788645e940eada959bdde927426e2531c9Paul Duffin checkNotNull(event); 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert method.invoke(target, new Object[] { event }); 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IllegalArgumentException e) { 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new Error("Method rejected target/argument: " + event, e); 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IllegalAccessException e) { 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new Error("Method became inaccessible: " + event, e); 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (InvocationTargetException e) { 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (e.getCause() instanceof Error) { 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw (Error) e.getCause(); 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw e; 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 870888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public String toString() { 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return "[wrapper " + method + "]"; 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 910888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public int hashCode() { 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final int PRIME = 31; 930888a09821a98ac0680fad765217302858e70fa4Paul Duffin return (PRIME + method.hashCode()) * PRIME 940888a09821a98ac0680fad765217302858e70fa4Paul Duffin + System.identityHashCode(target); 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 970888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public boolean equals(@Nullable Object obj) { 980888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (obj instanceof EventSubscriber) { 990888a09821a98ac0680fad765217302858e70fa4Paul Duffin EventSubscriber that = (EventSubscriber) obj; 1007dd252788645e940eada959bdde927426e2531c9Paul Duffin // Use == so that different equal instances will still receive events. 1017dd252788645e940eada959bdde927426e2531c9Paul Duffin // We only guard against the case that the same object is registered 1027dd252788645e940eada959bdde927426e2531c9Paul Duffin // multiple times 1037dd252788645e940eada959bdde927426e2531c9Paul Duffin return target == that.target && method.equals(that.method); 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1057dd252788645e940eada959bdde927426e2531c9Paul Duffin return false; 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1070888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1080888a09821a98ac0680fad765217302858e70fa4Paul Duffin public Object getSubscriber() { 1090888a09821a98ac0680fad765217302858e70fa4Paul Duffin return target; 1100888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1110888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1120888a09821a98ac0680fad765217302858e70fa4Paul Duffin public Method getMethod() { 1130888a09821a98ac0680fad765217302858e70fa4Paul Duffin return method; 1140888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 116