Coverage Summary for Class: Subscriber (com.google.common.eventbus)

Class Method, % Line, %
Subscriber 0% (0/9) 0% (0/28)
Subscriber$1 0% (0/2) 0% (0/5)
Subscriber$SynchronizedSubscriber 0% (0/3) 0% (0/5)
Total 0% (0/14) 0% (0/38)


1 /* 2  * Copyright (C) 2014 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.eventbus; 16  17 import static com.google.common.base.Preconditions.checkNotNull; 18  19 import com.google.common.annotations.VisibleForTesting; 20 import com.google.j2objc.annotations.Weak; 21 import java.lang.reflect.InvocationTargetException; 22 import java.lang.reflect.Method; 23 import java.util.concurrent.Executor; 24 import javax.annotation.CheckForNull; 25  26 /** 27  * A subscriber method on a specific object, plus the executor that should be used for dispatching 28  * events to it. 29  * 30  * <p>Two subscribers are equivalent when they refer to the same method on the same object (not 31  * class). This property is used to ensure that no subscriber method is registered more than once. 32  * 33  * @author Colin Decker 34  */ 35 @ElementTypesAreNonnullByDefault 36 class Subscriber { 37  38  /** Creates a {@code Subscriber} for {@code method} on {@code listener}. */ 39  static Subscriber create(EventBus bus, Object listener, Method method) { 40  return isDeclaredThreadSafe(method) 41  ? new Subscriber(bus, listener, method) 42  : new SynchronizedSubscriber(bus, listener, method); 43  } 44  45  /** The event bus this subscriber belongs to. */ 46  @Weak private EventBus bus; 47  48  /** The object with the subscriber method. */ 49  @VisibleForTesting final Object target; 50  51  /** Subscriber method. */ 52  private final Method method; 53  54  /** Executor to use for dispatching events to this subscriber. */ 55  private final Executor executor; 56  57  private Subscriber(EventBus bus, Object target, Method method) { 58  this.bus = bus; 59  this.target = checkNotNull(target); 60  this.method = method; 61  method.setAccessible(true); 62  63  this.executor = bus.executor(); 64  } 65  66  /** Dispatches {@code event} to this subscriber using the proper executor. */ 67  final void dispatchEvent(final Object event) { 68  executor.execute( 69  new Runnable() { 70  @Override 71  public void run() { 72  try { 73  invokeSubscriberMethod(event); 74  } catch (InvocationTargetException e) { 75  bus.handleSubscriberException(e.getCause(), context(event)); 76  } 77  } 78  }); 79  } 80  81  /** 82  * Invokes the subscriber method. This method can be overridden to make the invocation 83  * synchronized. 84  */ 85  @VisibleForTesting 86  void invokeSubscriberMethod(Object event) throws InvocationTargetException { 87  try { 88  method.invoke(target, checkNotNull(event)); 89  } catch (IllegalArgumentException e) { 90  throw new Error("Method rejected target/argument: " + event, e); 91  } catch (IllegalAccessException e) { 92  throw new Error("Method became inaccessible: " + event, e); 93  } catch (InvocationTargetException e) { 94  if (e.getCause() instanceof Error) { 95  throw (Error) e.getCause(); 96  } 97  throw e; 98  } 99  } 100  101  /** Gets the context for the given event. */ 102  private SubscriberExceptionContext context(Object event) { 103  return new SubscriberExceptionContext(bus, event, target, method); 104  } 105  106  @Override 107  public final int hashCode() { 108  return (31 + method.hashCode()) * 31 + System.identityHashCode(target); 109  } 110  111  @Override 112  public final boolean equals(@CheckForNull Object obj) { 113  if (obj instanceof Subscriber) { 114  Subscriber that = (Subscriber) obj; 115  // Use == so that different equal instances will still receive events. 116  // We only guard against the case that the same object is registered 117  // multiple times 118  return target == that.target && method.equals(that.method); 119  } 120  return false; 121  } 122  123  /** 124  * Checks whether {@code method} is thread-safe, as indicated by the presence of the {@link 125  * AllowConcurrentEvents} annotation. 126  */ 127  private static boolean isDeclaredThreadSafe(Method method) { 128  return method.getAnnotation(AllowConcurrentEvents.class) != null; 129  } 130  131  /** 132  * Subscriber that synchronizes invocations of a method to ensure that only one thread may enter 133  * the method at a time. 134  */ 135  @VisibleForTesting 136  static final class SynchronizedSubscriber extends Subscriber { 137  138  private SynchronizedSubscriber(EventBus bus, Object target, Method method) { 139  super(bus, target, method); 140  } 141  142  @Override 143  void invokeSubscriberMethod(Object event) throws InvocationTargetException { 144  synchronized (this) { 145  super.invokeSubscriberMethod(event); 146  } 147  } 148  } 149 }