Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
Nifty GUI is a Java Library that supports the building of interactive user interfaces for games or similar applications. It utilizes OpenGL for rendering and it can be easily integrated into many rendering systems. The configuration of the GUI is stored in xml files with little supporting Java code. In short Nifty helps you to layout stuff, display it in a cool way and interact with it :)
/**
* Copyright 2005-2007 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com
*
* 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 org.bushe.swing.event;
import org.bushe.swing.event.Logger.Level;
import org.bushe.swing.event.annotation.ReferenceStrength;
import org.bushe.swing.exception.SwingException;
import java.lang.ref.WeakReference;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Pattern;
/**
* A thread-safe EventService implementation.
*
Multithreading
*
* This implementation is not Swing thread-safe. If publication occurs on a thread other than the Swing
* EventDispatchThread, subscribers will receive the event on the calling thread, and not the EDT. Swing components
* should use the SwingEventService instead, which is the implementation used by the EventBus.
*
* Two threads may be accessing the ThreadSafeEventService at the same time, one unsubscribing a
* listener for topic "A" and the other publishing on topic "A". If the unsubscribing thread gets the lock first,
* then it is unsubscribed, end of story. If the publisher gets the lock first, then a snapshot copy of the current
* subscribers is made during the publication, the lock is released and the subscribers are called. Between the time
* the lock is released and the time that the listener is called, the unsubscribing thread can unsubscribe, resulting
* in an unsubscribed object receiving notification of the event after it was unsubscribed (but just once).
*
* On event publication, subscribers are called in the order in which they subscribed.
*
* Events and/or topic data can be cached, but are not by default. To cache events or topic data, call
* {@link #setDefaultCacheSizePerClassOrTopic(int)}, {@link #setCacheSizeForEventClass(Class, int)}, or
* {@link #setCacheSizeForTopic(String, int)}, {@link #setCacheSizeForTopic(Pattern, int)}. Retrieve cached values
* with {@link #getLastEvent(Class)}, {@link #getLastTopicData(String)}, {@link #getCachedEvents(Class)}, or
* {@link #getCachedTopicData(String)}. Using caching while subscribing
* is most likely to make sense only if you subscribe and publish on the same thread (so caching is very useful for
* Swing applications since both happen on the EDT in a single-threaded manner). In multithreaded applications, you
* never know if your subscriber has handled an event while it was being subscribed (before the subscribe() method
* returned) that is newer or older than the retrieved cached value (taken before or after subscribe() respectively).
*
* To deal with subscribers that take too long (a concern in Swing applications), the EventService can be made to issue
* {@link SubscriberTimingEvent}s when subscribers exceed a certain time. This does not interrupt subscriber processing
* and is published after the subscriber finishes. The service can log a warning for SubscriberTimingEvents, see the
* constructor {@link ThreadSafeEventService (long, boolean)}. The timing is checked for veto subscribers too.
*
*
Logging
*
* All logging goes through the {@link Logger}. The Logger is configurable and supports multiple logging systems.
*
* Exceptions are logged by default, override {@link #handleException(String,Object,String,Object,Throwable,
* StackTraceElement[],String)} to handleException exceptions in another way. Each call to a subscriber is wrapped in
* a try block to ensure one listener does not interfere with another.
*
*
Cleanup of Stale WeakReferences and Stale Annotation Proxies
*
* The EventService may need to clean up stale WeakReferences and ProxySubscribers created for EventBus annotations. (Aside: EventBus
* Annotations are handled by the creation of proxies to the annotated objects. Since the annotations create weak references
* by default, annotation proxies must held strongly by the EventService, otherwise the proxy is garbage collected.) When
* a WeakReference's referent or an ProxySubscriber's proxiedObject (the annotated object) is claimed by the garbage collector,
* the EventService still holds onto the actual WeakReference or ProxySubscriber subscribed to the EventService (which are pretty tiny).
*
* There are two ways that these stale WeakReferences and ProxySubscribers are cleaned up.
*
*
On every publish, subscribe and unsubscribe, every subscriber and veto subscriber to a class or topic is checked to see
* if it is a stale WeakReference or a stale ProxySubscriber (one whose getProxySubscriber() returns null). If the subscriber
* is stale, it is unsubscribed from the EventService immediately. If it is a ProxySubscriber, it's proxyUnsubscribed()
* method is called after it is unsubscribed. (This isn't as expensive as it sounds, since checks to avoid double subscription is
* necessary anyway).
*
Another cleanup thread may get started to clean up remaining stale subscribers. This cleanup thread only comes into
* play for subscribers to topic or classes that haven't been used (published/subscribed/unsibscribed to). A detailed description
* of the cleanup thread follows.
*
*
The Cleanup Thread
* If a topic or class is never published to again, WeakReferences and ProxySubscribers can be left behind if they
* are not cleaned up. To prevent loitering stale subscribers, the ThreadSafeEventService may periodically run through
* all the EventSubscribers and VetoSubscribers for all topics and classes and clean up stale proxies. Proxies for
* Annotations that have a ReferenceStrength.STRONG are never cleaned up in normal usage. (By specifying
* ReferenceStrength.STRONG, the programmer is buying into unsubscribing annotated objects themselves. There is
* one caveat: If getProxiedSubscriber() returns null, even for a ProxySubscriber with a STRONG reference strength, that proxy
* is cleaned up as it is assumed it is stale or just wrong. This would not occur normally in EventBus usage, but only
* if someone is implementing their own custom ProxySubscriber and/or AnnotationProcessor.)
*
* Cleanup is pretty rare in general. Not only are stale subscribers cleaned up with regular usage, stale
* subscribers on abandoned topics and classes do not take up a lot of memory, hence, they are allowed to build up to a certain degree.
* Cleanup does not occur until the number of WeakReferences and SubscriptionsProxy's with WeakReference strength
* subscribed to an EventService for all the EventService's subscriptions in total exceed the cleanupStartThreshhold,
* which is set to CLEANUP_START_THRESHOLD_DEFAULT (500) by default. The default is overridable in the constructor
* or via #setCleanupStartThreshhold(Integer). If set to null, cleanup will never start.
*
* Once the cleanup start threshold is exceeded, a java.util.Timer is started to clean up stale subscribers periodically
* in another thread. The timer will fire every cleanupPeriodMS milliseconds, which is set to the
* CLEANUP_PERIOD_MS_DEFAULT (20 minutes) by default. The default is overridable in the constructor or
* via #setCleanupPeriodMS(Integer). If set to null, cleanup will not start. This is implemented with a java.util.Timer,
* so Timer's warnings apply - setting this too low will cause cleanups to bunch up and hog the cleanup thread.
*
* After a cleanup cycle completes, if the number of stale subscribers falls at or below the cleanupStopThreshhold
* cleanup stops until the cleanupStartThreshhold is exceeded again. The cleanupStopThreshhold is set
* to CLEANUP_STOP_THRESHOLD_DEFAULT (100) by default. The default is overridable in the constructor or via
* #setCleanupStopThreshhold(Integer). If set to null or 0, cleanup will not stop if it is ever started.
*
* Cleanup can be monitored by subscribing to the {@link CleanupEvent} class.
*
* All cleanup parameters are tunable "live" and checked after each subscription and after each cleanup cycle.
* To make cleanup never run, set cleanupStartThreshhold to Integer.MAX_VALUE and cleanupPeriodMS to null.
* To get cleanup to run continuously, set set cleanupStartThreshhold to 0 and cleanupPeriodMS to some reasonable value,
* perhaps 1000 (1 second) or so (not recommended, cleanup is conducted with regular usage and the cleanup thread is
* rarely created or invoked).
*
* Cleanup is not run in a daemon thread, and thus will not stop the JVM from exiting.
*
*
* @author Michael Bushe [email protected]
* @todo (param) a JMS-like selector (can be done in base classes by implements like a commons filter
* @see EventService for a complete description of the API
*/
@SuppressWarnings({"unchecked", "ForLoopReplaceableByForEach"})
public class ThreadSafeEventService implements EventService {
public static final Integer CLEANUP_START_THRESHOLD_DEFAULT = 250;
public static final Integer CLEANUP_STOP_THRESHOLD_DEFAULT = 100;
public static final Long CLEANUP_PERIOD_MS_DEFAULT = 20L*60L*1000L;
protected static final Logger LOG = Logger.getLogger(EventService.class.getName());
//Making these generic collections is a bad idea, it doesn't compile since it's better to have all the maps
//go through the same set of code to do all the real publish and subscribe work
private Map subscribersByEventType = new HashMap();
private Map subscribersByEventClass = new HashMap();
private Map subscribersByExactEventClass = new HashMap();
private Map subscribersByTopic = new HashMap();
private Map subscribersByTopicPattern = new HashMap();
private Map vetoListenersByClass = new HashMap();
private Map vetoListenersByExactClass = new HashMap();
private Map vetoListenersByTopic = new HashMap();
private Map vetoListenersByTopicPattern = new HashMap();
private final Object listenerLock = new Object();
private final Object cacheLock = new Object();
private Long timeThresholdForEventTimingEventPublication;
private Map cacheByEvent = new HashMap();
private int defaultCacheSizePerClassOrTopic = 0;
private Map cacheSizesForEventClass;
private Map rawCacheSizesForEventClass;
private boolean rawCacheSizesForEventClassChanged;
private Map cacheByTopic = new HashMap();
private Map cacheSizesForTopic;
private Map rawCacheSizesForTopic;
private boolean rawCacheSizesForTopicChanged;
private Map rawCacheSizesForPattern;
private boolean rawCacheSizesForPatternChanged;
private Integer cleanupStartThreshhold;
private Integer cleanupStopThreshold;
private Long cleanupPeriodMS;
private int weakRefPlusProxySubscriberCount;
private Timer cleanupTimer;
private TimerTask cleanupTimerTask;
private static final Comparator PRIORITIZED_SUBSCRIBER_COMPARATOR = new PrioritizedSubscriberComparator();
private boolean hasEverUsedPrioritized;
/** Creates a ThreadSafeEventService that does not monitor timing of handlers. */
public ThreadSafeEventService() {
this(null, false, null, null, null);
}
/**
* Creates a ThreadSafeEventService while providing time monitoring options.
*
* @param timeThresholdForEventTimingEventPublication the longest time a subscriber should spend handling an event,
* The service will publish an SubscriberTimingEvent after listener processing if the time was exceeded. If null, no
* EventSubscriberTimingEvent will be issued.
*/
public ThreadSafeEventService(Long timeThresholdForEventTimingEventPublication) {
this(timeThresholdForEventTimingEventPublication, false, null, null, null);
}
/**
* Creates a ThreadSafeEventService while providing time monitoring options.
*
* @param timeThresholdForEventTimingEventPublication the longest time a subscriber should spend handling an event,
* The service will publish an SubscriberTimingEvent after listener processing if the time was exceeded. If null, no
* EventSubscriberTimingEvent will be issued.
* @param subscribeTimingEventsInternally add a subscriber to the SubscriberTimingEvent internally and call the
* protected subscribeTiming() method when they occur. This logs a warning to the {@link Logger} by
* default.
*/
public ThreadSafeEventService(Long timeThresholdForEventTimingEventPublication, boolean subscribeTimingEventsInternally) {
this(timeThresholdForEventTimingEventPublication, subscribeTimingEventsInternally, null, null, null);
}
/**
* Creates a ThreadSafeEventService while providing proxy cleanup customization.
* Proxies are used with Annotations.
*
* @param cleanupStartThreshold see class javadoc.
* @param cleanupStopThreshold see class javadoc.
* @param cleanupPeriodMS see class javadoc.
*/
public ThreadSafeEventService(Integer cleanupStartThreshold,
Integer cleanupStopThreshold, Long cleanupPeriodMS) {
this(null, false, cleanupStartThreshold,
cleanupStopThreshold, cleanupPeriodMS);
}
/**
* Creates a ThreadSafeEventService while providing time monitoring options.
*
* @param timeThresholdForEventTimingEventPublication the longest time a subscriber should spend handling an event.
* The service will publish an SubscriberTimingEvent after listener processing if the time was exceeded. If null, no
* SubscriberTimingEvent will be issued.
* @param subscribeTimingEventsInternally add a subscriber to the SubscriberTimingEvent internally and call the
* protected subscribeTiming() method when they occur. This logs a warning to the {@link Logger} by
* default.
* @param cleanupStartThreshold see class javadoc.
* @param cleanupStopThreshold see class javadoc.
* @param cleanupPeriodMS see class javadoc.
*
* @throws IllegalArgumentException if timeThresholdForEventTimingEventPublication is null and
* subscribeTimingEventsInternally is true.
*/
public ThreadSafeEventService(Long timeThresholdForEventTimingEventPublication,
boolean subscribeTimingEventsInternally, Integer cleanupStartThreshold,
Integer cleanupStopThreshold, Long cleanupPeriodMS) {
if (timeThresholdForEventTimingEventPublication == null && subscribeTimingEventsInternally) {
throw new IllegalArgumentException("null, true in constructor is not valid. If you want to send timing messages for all events and subscribe them internally, pass 0, true");
}
this.timeThresholdForEventTimingEventPublication = timeThresholdForEventTimingEventPublication;
if (subscribeTimingEventsInternally) {
//Listen to timing events and log them
subscribeStrongly(SubscriberTimingEvent.class, new EventSubscriber() {
public void onEvent(Object event) {
subscribeTiming((SubscriberTimingEvent) event);
}
});
}
if (cleanupStartThreshold == null) {
this.cleanupStartThreshhold = CLEANUP_START_THRESHOLD_DEFAULT;
} else {
this.cleanupStartThreshhold = cleanupStartThreshold;
}
if (cleanupStopThreshold == null) {
this.cleanupStopThreshold = CLEANUP_STOP_THRESHOLD_DEFAULT;
} else {
this.cleanupStopThreshold = cleanupStopThreshold;
}
if (cleanupPeriodMS == null) {
this.cleanupPeriodMS = CLEANUP_PERIOD_MS_DEFAULT;
} else {
this.cleanupPeriodMS = cleanupPeriodMS;
}
}
/**
* Gets the threshold above which cleanup starts. See the class javadoc on cleanup.
* @return the threshold at which cleanup starts
*/
public Integer getCleanupStartThreshhold() {
synchronized (listenerLock) {
return cleanupStartThreshhold;
}
}
/**
* Sets the threshold above which cleanup starts. See the class javadoc on cleanup.
* @param cleanupStartThreshhold threshold at which cleanup starts
*/
public void setCleanupStartThreshhold(Integer cleanupStartThreshhold) {
synchronized (listenerLock) {
this.cleanupStartThreshhold = cleanupStartThreshhold;
}
}
/**
* Gets the threshold below which cleanup stops. See the class javadoc on cleanup.
* @return threshold at which cleanup stops (it may start again)
*/
public Integer getCleanupStopThreshold() {
synchronized (listenerLock) {
return cleanupStopThreshold;
}
}
/**
* Sets the threshold below which cleanup stops. See the class javadoc on cleanup.
* @param cleanupStopThreshold threshold at which cleanup stops (it may start again).
*/
public void setCleanupStopThreshold(Integer cleanupStopThreshold) {
synchronized (listenerLock) {
this.cleanupStopThreshold = cleanupStopThreshold;
}
}
/**
* Get the cleanup interval. See the class javadoc on cleanup.
* @return interval in milliseconds between cleanup runs.
*/
public Long getCleanupPeriodMS() {
synchronized (listenerLock) {
return cleanupPeriodMS;
}
}
/**
* Sets the cleanup interval. See the class javadoc on cleanup.
* @param cleanupPeriodMS interval in milliseconds between cleanup runs. Passing null
* stops cleanup.
*/
public void setCleanupPeriodMS(Long cleanupPeriodMS) {
synchronized (listenerLock) {
this.cleanupPeriodMS = cleanupPeriodMS;
}
}
/** @see EventService#subscribe(Class,EventSubscriber) */
public boolean subscribe(Class cl, EventSubscriber eh) {
if (cl == null) {
throw new IllegalArgumentException("Event class must not be null");
}
if (eh == null) {
throw new IllegalArgumentException("Event subscriber must not be null");
}
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing by class, class:" + cl + ", subscriber:" + eh);
}
return subscribe(cl, subscribersByEventClass, new WeakReference(eh));
}
/** @see EventService#subscribe(java.lang.reflect.Type, EventSubscriber) */
public boolean subscribe(Type type, EventSubscriber eh) {
return subscribe(type, subscribersByEventType, new WeakReference(eh));
}
/** @see EventService#subscribeExactly(Class,EventSubscriber) */
public boolean subscribeExactly(Class cl, EventSubscriber eh) {
if (cl == null) {
throw new IllegalArgumentException("Event class must not be null");
}
if (eh == null) {
throw new IllegalArgumentException("Event subscriber must not be null");
}
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing by class, class:" + cl + ", subscriber:" + eh);
}
return subscribe(cl, subscribersByExactEventClass, new WeakReference(eh));
}
/** @see EventService#subscribe(String,EventTopicSubscriber) */
public boolean subscribe(String topic, EventTopicSubscriber eh) {
if (topic == null) {
throw new IllegalArgumentException("Topic must not be null");
}
if (eh == null) {
throw new IllegalArgumentException("Event topic subscriber must not be null");
}
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing by topic name, name:" + topic + ", subscriber:" + eh);
}
return subscribe(topic, subscribersByTopic, new WeakReference(eh));
}
/** @see EventService#subscribe(Pattern,EventTopicSubscriber) */
public boolean subscribe(Pattern pat, EventTopicSubscriber eh) {
if (pat == null) {
throw new IllegalArgumentException("Pattern must not be null");
}
if (eh == null) {
throw new IllegalArgumentException("Event subscriber must not be null");
}
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing by pattern, pattern:" + pat + ", subscriber:" + eh);
}
PatternWrapper patternWrapper = new PatternWrapper(pat);
return subscribe(patternWrapper, subscribersByTopicPattern, new WeakReference(eh));
}
/** @see EventService#subscribeStrongly(Class,EventSubscriber) */
public boolean subscribeStrongly(Class cl, EventSubscriber eh) {
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing weakly by class, class:" + cl + ", subscriber:" + eh);
}
if (eh == null) {
throw new IllegalArgumentException("Subscriber cannot be null.");
}
return subscribe(cl, subscribersByEventClass, eh);
}
/** @see EventService#subscribeExactlyStrongly(Class,EventSubscriber) */
public boolean subscribeExactlyStrongly(Class cl, EventSubscriber eh) {
if (cl == null) {
throw new IllegalArgumentException("Event class must not be null");
}
if (eh == null) {
throw new IllegalArgumentException("Event subscriber must not be null");
}
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing by class, class:" + cl + ", subscriber:" + eh);
}
return subscribe(cl, subscribersByExactEventClass, eh);
}
/** @see EventService#subscribeStrongly(String,EventTopicSubscriber) */
public boolean subscribeStrongly(String name, EventTopicSubscriber eh) {
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing weakly by topic name, name:" + name + ", subscriber:" + eh);
}
if (eh == null) {
throw new IllegalArgumentException("Subscriber cannot be null.");
}
return subscribe(name, subscribersByTopic, eh);
}
/** @see EventService#subscribeStrongly(Pattern,EventTopicSubscriber) */
public boolean subscribeStrongly(Pattern pat, EventTopicSubscriber eh) {
if (pat == null) {
throw new IllegalArgumentException("Pattern must not be null");
}
if (eh == null) {
throw new IllegalArgumentException("Event subscriber must not be null");
}
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("Subscribing by pattern, pattern:" + pat + ", subscriber:" + eh);
}
PatternWrapper patternWrapper = new PatternWrapper(pat);
return subscribe(patternWrapper, subscribersByTopicPattern, eh);
}
/** @see org.bushe.swing.event.EventService#clearAllSubscribers() */
public void clearAllSubscribers() {
synchronized (listenerLock) {
unsubscribeAllInMap(subscribersByEventType);
unsubscribeAllInMap(subscribersByEventClass);
unsubscribeAllInMap(subscribersByExactEventClass);
unsubscribeAllInMap(subscribersByTopic);
unsubscribeAllInMap(subscribersByTopicPattern);
unsubscribeAllInMap(vetoListenersByClass);
unsubscribeAllInMap(vetoListenersByExactClass);
unsubscribeAllInMap(vetoListenersByTopic);
unsubscribeAllInMap(vetoListenersByTopicPattern);
}
}
private void unsubscribeAllInMap(Map subscriberMap) {
synchronized (listenerLock) {
Set subscriptionKeys = subscriberMap.keySet();
for (Object key : subscriptionKeys) {
List subscribers = (List) subscriberMap.get(key);
while (!subscribers.isEmpty()) {
unsubscribe(key, subscriberMap, subscribers.get(0));
}
}
}
}
/** @see EventService#subscribeVetoListener(Class,VetoEventListener) */
public boolean subscribeVetoListener(Class eventClass, VetoEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoEventListener cannot be null.");
}
if (eventClass == null) {
throw new IllegalArgumentException("eventClass cannot be null.");
}
return subscribeVetoListener(eventClass, vetoListenersByClass, new WeakReference(vetoListener));
}
/** @see EventService#subscribeVetoListenerExactly(Class,VetoEventListener) */
public boolean subscribeVetoListenerExactly(Class eventClass, VetoEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoEventListener cannot be null.");
}
if (eventClass == null) {
throw new IllegalArgumentException("eventClass cannot be null.");
}
return subscribeVetoListener(eventClass, vetoListenersByExactClass, new WeakReference(vetoListener));
}
/** @see EventService#subscribeVetoListener(String,VetoTopicEventListener) */
public boolean subscribeVetoListener(String topic, VetoTopicEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoEventListener cannot be null.");
}
if (topic == null) {
throw new IllegalArgumentException("topic cannot be null.");
}
return subscribeVetoListener(topic, vetoListenersByTopic, new WeakReference(vetoListener));
}
/** @see EventService#subscribeVetoListener(Pattern,VetoTopicEventListener) */
public boolean subscribeVetoListener(Pattern topicPattern, VetoTopicEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoEventListener cannot be null.");
}
if (topicPattern == null) {
throw new IllegalArgumentException("topicPattern cannot be null.");
}
PatternWrapper patternWrapper = new PatternWrapper(topicPattern);
return subscribeVetoListener(patternWrapper, vetoListenersByTopicPattern, new WeakReference(vetoListener));
}
/** @see EventService#subscribeVetoListenerStrongly(Class,VetoEventListener) */
public boolean subscribeVetoListenerStrongly(Class eventClass, VetoEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoEventListener cannot be null.");
}
if (eventClass == null) {
throw new IllegalArgumentException("eventClass cannot be null.");
}
return subscribeVetoListener(eventClass, vetoListenersByClass, vetoListener);
}
/** @see EventService#subscribeVetoListenerExactlyStrongly(Class,VetoEventListener) */
public boolean subscribeVetoListenerExactlyStrongly(Class eventClass, VetoEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoEventListener cannot be null.");
}
if (eventClass == null) {
throw new IllegalArgumentException("eventClass cannot be null.");
}
return subscribeVetoListener(eventClass, vetoListenersByExactClass, vetoListener);
}
/** @see EventService#subscribeVetoListenerStrongly(String,VetoTopicEventListener) */
public boolean subscribeVetoListenerStrongly(String topic, VetoTopicEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoListener cannot be null.");
}
if (topic == null) {
throw new IllegalArgumentException("topic cannot be null.");
}
return subscribeVetoListener(topic, vetoListenersByTopic, vetoListener);
}
/** @see EventService#subscribeVetoListenerStrongly(Pattern,VetoTopicEventListener) */
public boolean subscribeVetoListenerStrongly(Pattern topicPattern, VetoTopicEventListener vetoListener) {
if (vetoListener == null) {
throw new IllegalArgumentException("VetoTopicEventListener cannot be null.");
}
if (topicPattern == null) {
throw new IllegalArgumentException("topicPattern cannot be null.");
}
PatternWrapper patternWrapper = new PatternWrapper(topicPattern);
return subscribeVetoListener(patternWrapper, vetoListenersByTopicPattern, vetoListener);
}
/**
* All veto subscriptions methods call this method. Extending classes only have to override this method to subscribe
* all veto subscriptions.
*
* @param subscription the topic, Pattern, or event class to subscribe to
* @param vetoListenerMap the internal map of veto listeners to use (by topic of class)
* @param vetoListener the veto listener to subscribe, may be a VetoEventListener or a WeakReference to one
*
* @return boolean if the veto listener is subscribed (was not subscribed).
*
* @throws IllegalArgumentException if vl or o is null
*/
protected boolean subscribeVetoListener(final Object subscription, final Map vetoListenerMap, final Object vetoListener) {
if (LOG.isLoggable(Level.DEBUG)) {
LOG.debug("subscribeVetoListener(" + subscription + "," + vetoListener + ")");
}
if (vetoListener == null) {
throw new IllegalArgumentException("Can't subscribe null veto listener to " + subscription);
}
if (subscription == null) {
throw new IllegalArgumentException("Can't subscribe veto listener to null.");
}
return subscribe(subscription, vetoListenerMap, vetoListener);
}
/**
* All subscribe methods call this method, including veto subscriptions.
* Extending classes only have to override this method to subscribe all
* subscriber subscriptions.
*
* Overriding this method is only for the adventurous. This basically gives you just enough rope to hang yourself.
*
* @param classTopicOrPatternWrapper the topic String, event Class, or PatternWrapper to subscribe to
* @param subscriberMap the internal map of subscribers to use (by topic or class)
* @param subscriber the EventSubscriber or EventTopicSubscriber to subscribe, or a WeakReference to either
*
* @return boolean if the subscriber is subscribed (was not subscribed).
*
* @throws IllegalArgumentException if subscriber or topicOrClass is null
*/
protected boolean subscribe(final Object classTopicOrPatternWrapper, final Map