Skip to content

Commit

Permalink
Added WeakSignal class. A WeakSignal is functionally the same as a Si…
Browse files Browse the repository at this point in the history
…gnal but contains weak references to its listeners.

Updated version number to 2.2.
Updated README with WeakSignal example.
  • Loading branch information
paulmoore committed May 17, 2011
1 parent e5b9944 commit f8bd776
Show file tree
Hide file tree
Showing 12 changed files with 448 additions and 104 deletions.
3 changes: 2 additions & 1 deletion .gitignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ ehthumbs.db
Icon?
Thumbs.db
build/*
bin/*
bin/*
.settings/*
82 changes: 25 additions & 57 deletions README.textile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ h1. A new approach to events in Java.

h2. Examples

h3. Basic Signal Example

<pre><code>// using the Java Signals event model in a simple banking example
import com.paulm.jsignal.Signal;
import com.paulm.jsignal.SignalException;
Expand Down Expand Up @@ -64,70 +66,36 @@ class ATM
}
}</code></pre>

h3. PrioritySignal Example

<pre><code>// using the Java Signals event model for priority based event dispatching
import com.paulm.jsignal.PrioritySignal;
import com.paulm.jsignal.SignalException;

public class BankApp
{
// for display purposes only
private String priority;

public static void main (String args[])
{
BankApp lowPriorityApp = new BankApp();
lowPriorityApp.priority = "LOW";
BankApp highPriorityApp = new BankApp();
highPriorityApp.priority = "HIGH";
ATM atm = new ATM();
try
{
// add the high and low priority handlers
// note that Integers are compared by their natural ordering, so a lower number has a higher priority in this case
atm.transactionComplete.add(lowPriorityApp, "handleNewBalance", 1);
atm.transactionComplete.add(highPriorityApp, "handleNewBalance", 0);
}
catch (SignalException e)
{
e.printStackTrace();
}
atm.doTransaction();
}
//...
// we can specify generically a comparable type to use as priority, in this case we will use Integers
PrioritySignal<Integer> transactionComplete = new PrioritySignal<Integer>(String.class, double.class);
//...

public void handleNewBalance (String name, double balance)
{
System.out.println("New balance recieved with "+priority+" priority, name:"+name+" balance:"+balance);
}
}
// add the high and low priority handlers
// note that Integers are compared by their natural ordering, so a lower number has a higher priority in this case
atm.transactionComplete.add(lowPriorityApp, "handleNewBalance", 1);
atm.transactionComplete.add(highPriorityApp, "handleNewBalance", 0);</code></pre>

class ATM
{
protected final PrioritySignal<Integer> transactionComplete;

public ATM ()
{
// we can specify generically a comparable type to use as priority, in this case we will use Integers
transactionComplete = new PrioritySignal<Integer>(String.class, double.class);
}

public void doTransaction ()
{
// do something
try
{
// dispatch the event; to enforce strict-typing of event data, the data types of the arguments must match up with formal parameters
transactionComplete.dispatch("Paul", 17.06);
}
catch (SignalException e)
{
e.printStackTrace();
}
}
}</code></pre>
h3. WeakSignal Example

<pre><code>// using WeakSignals for memory sensitive code

//...
WeakSignal signal = new WeakSignal();
Listener listener = new Listener();
signal.add(listener, "callback");
listener = null;
//... after garbage collection

signal.dispatch(); // listener was garbaged collected and automatically removed as a listener from the WeakSignal instance</code></pre>

*Note:* Because native AWT events haven't yet been wrapped by Java Signals, there is no need to post a side by side comparison of the two methods. You can find Oracle's tutorial on events "here":http://download.oracle.com/javase/tutorial/uiswing/events/index.html

h3. Links
h2. Links

* "Robert Penner's original Signals API for AS3":https://github.com/robertpenner/as3-signals
* Feel free to contact me at <b>[email protected]</b> with any questions/comments/concerns/critiques/etc
2 changes: 1 addition & 1 deletion build.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Project properties
project.name=jsignal
project.title=Java Signals
project.version=2.1
project.version=2.2
project.author=Paul Moore

# Build directories
Expand Down
24 changes: 12 additions & 12 deletions src/com/paulm/jsignal/PrioritySignal.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
* @author Paul Moore
* @see com.paulm.jsignal.Signal
*/
public class PrioritySignal <E extends Comparable<E>> extends Signal
public final class PrioritySignal <E extends Comparable<E>> extends Signal
{
private PriorityQueue<PrioritySlot<E>> listenerQueue;
private PriorityQueue<ISlot> listenerQueue;

/**
* Constructor
Expand All @@ -64,7 +64,7 @@ public PrioritySignal (int initialCapacity, Class<?>... params)
{
super(params);

listenerQueue = new PriorityQueue<PrioritySlot<E>>(initialCapacity);
listenerQueue = new PriorityQueue<ISlot>(initialCapacity);
}

/**
Expand All @@ -90,19 +90,19 @@ public Object add (Object listener, String callback, boolean addOnce, E priority
}
catch (SecurityException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+listener+" callback:"+callback+" priority:"+priority);
SignalException se = new SignalException (e+" listener:"+listener+" callback:"+callback+" priority:"+priority);
log.throwing("PrioritySignal", "add", se);
throw se;
}
catch (NoSuchMethodException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+listener+" callback:"+callback+" priority:"+priority);
SignalException se = new SignalException (e+" listener:"+listener+" callback:"+callback+" priority:"+priority);
log.throwing("PrioritySignal", "add", se);
throw se;
}

PrioritySlot<E> newSlot = new PrioritySlot<E>(listener, delegate, addOnce, priority);
Slot previous = listenerMap.put(listener, newSlot);
ISlot newSlot = new PrioritySlot<E>(listener, delegate, addOnce, priority);
ISlot previous = listenerMap.put(listener, newSlot);

if (previous != null)
{
Expand Down Expand Up @@ -187,8 +187,8 @@ public void removeAll ()
@Override
public void dispatch (Object... args) throws SignalException
{
PrioritySlot<E> slot;
PriorityQueue<PrioritySlot<E>> newQueue = new PriorityQueue<PrioritySlot<E>>(listenerQueue.size());
ISlot slot;
PriorityQueue<ISlot> newQueue = new PriorityQueue<ISlot>(listenerQueue.size());

while (!listenerQueue.isEmpty())
{
Expand All @@ -200,19 +200,19 @@ public void dispatch (Object... args) throws SignalException
}
catch (IllegalArgumentException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
SignalException se = new SignalException (e+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
log.throwing("PrioritySignal", "add", se);
throw se;
}
catch (IllegalAccessException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
SignalException se = new SignalException (e+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
log.throwing("PrioritySignal", "add", se);
throw se;
}
catch (InvocationTargetException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
SignalException se = new SignalException (e+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
log.throwing("PrioritySignal", "add", se);
throw se;
}
Expand Down
2 changes: 1 addition & 1 deletion src/com/paulm/jsignal/PrioritySlot.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import java.lang.reflect.Method;

class PrioritySlot <E extends Comparable<E>> extends Slot implements Comparable<PrioritySlot<E>>
final class PrioritySlot <E extends Comparable<E>> extends Slot implements Comparable<PrioritySlot<E>>
{
private E priority;

Expand Down
23 changes: 12 additions & 11 deletions src/com/paulm/jsignal/Signal.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ public class Signal implements ISignalOwner
{
protected final Class<?>[] params;

protected final Map<Object, Slot> listenerMap = new HashMap<Object, Slot>();
protected final Map<Object, ISlot> listenerMap = new HashMap<Object, ISlot>();

protected static final Logger log;

static
{
log = Logger.getLogger(Signal.class.getPackage().getName());
log = Logger.getLogger(WeakSignal.class.getPackage().getName());
System.out.println(log.getName());
}

/**
Expand Down Expand Up @@ -94,18 +95,18 @@ public Object add (Object listener, String callback, boolean addOnce) throws Sig
}
catch (SecurityException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+listener+" callback:"+callback);
SignalException se = new SignalException (e+" listener:"+listener+" callback:"+callback);
log.throwing("Signal", "add", se);
throw se;
}
catch (NoSuchMethodException e)
{
SignalException se = new SignalException (e.getLocalizedMessage()+" listener:"+listener+" callback:"+callback);
SignalException se = new SignalException (e+" listener:"+listener+" callback:"+callback);
log.throwing("Signal", "add", se);
throw se;
}

Slot previous = listenerMap.put(listener, new Slot(listener, delegate, addOnce));
ISlot previous = listenerMap.put(listener, new Slot(listener, delegate, addOnce));

return previous == null ? null : previous.getListener();
}
Expand Down Expand Up @@ -164,8 +165,8 @@ public void removeAll ()
@Override
public void dispatch (Object... args) throws SignalException
{
Iterator<Slot> iterator = listenerMap.values().iterator();
Slot slot;
Iterator<ISlot> iterator = listenerMap.values().iterator();
ISlot slot;

while (iterator.hasNext())
{
Expand All @@ -177,19 +178,19 @@ public void dispatch (Object... args) throws SignalException
}
catch (IllegalArgumentException e)
{
SignalException se = new SignalException(e.getLocalizedMessage()+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
SignalException se = new SignalException(e+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
log.throwing("Signal", "dispatch", se);
throw se;
}
catch (IllegalAccessException e)
{
SignalException se = new SignalException(e.getLocalizedMessage()+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
SignalException se = new SignalException(e+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
log.throwing("Signal", "dispatch", se);
throw se;
}
catch (InvocationTargetException e)
{
SignalException se = new SignalException(e.getLocalizedMessage()+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
SignalException se = new SignalException(e+" listener:"+slot.getDelegate()+" args:"+Arrays.deepToString(args));
log.throwing("Signal", "dispatch", se);
throw se;
}
Expand All @@ -211,7 +212,7 @@ public void dispatch (Object... args) throws SignalException
@Override
public boolean containsListener (Object listener)
{
Slot slot = listenerMap.get(listener);
ISlot slot = listenerMap.get(listener);

return slot == null ? false : slot.getListener().equals(listener);
}
Expand Down
7 changes: 5 additions & 2 deletions src/com/paulm/jsignal/Slot.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import java.lang.reflect.Method;

class Slot
class Slot implements ISlot
{
private Object listener;
private Method delegate;
Expand All @@ -39,16 +39,19 @@ public Slot (Object listener, Method delegate, boolean addOnce)
this.addOnce = addOnce;
}

@Override
public Object getListener ()
{
return listener;
}

@Override
public Method getDelegate ()
{
return delegate;
}

@Override
public boolean getAddOnce ()
{
return addOnce;
Expand All @@ -63,7 +66,7 @@ public int hashCode ()
@Override
public boolean equals (Object obj)
{
if (obj instanceof Slot)
if (obj instanceof ISlot)
{
return obj == this;
}
Expand Down
Loading

0 comments on commit f8bd776

Please sign in to comment.