package com.hypirion.beckon; import java.util.Map; import java.util.HashMap; import clojure.lang.Atom; import clojure.lang.PersistentHashMap; import clojure.lang.Keyword; import clojure.lang.AFn; import clojure.lang.IFn; import clojure.lang.Seqable; import clojure.lang.ISeq; public class SignalAtoms { private static final Map<String, Atom> atoms = new HashMap<String, Atom>(); /** * The keyword <code>:signal</code>. */ public static final Keyword SIGNAL = Keyword.intern("signal"); /** * A standard Atom validator function which tests whether the new value is a * Seqable, where each element in the Seqable implements Runnable. */ public static final IFn SIGNAL_ATOM_VALIDATOR = new SignalAtomValidator(); /** * Returns a Clojure Atom containing a Seqable. The Seqable represents a * list of functions where the functions are called in order whenever a * Signal by the type <code>signame</code> is received by this process. * * @exception SignalHandlerNotFoundException if this code is unable to * detect a SignalHandler and/or a Signal class. */ public static final synchronized Atom getSignalAtom(String signame) throws SignalHandlerNotFoundException{ if (!atoms.containsKey(signame)) { Object list; try { list = SignalRegistererHelper.getHandlerSeq(signame); } catch (LinkageError le) { throw new SignalHandlerNotFoundException(); } PersistentHashMap metadata = PersistentHashMap.create(SIGNAL, signame); Atom atm = new Atom(list, metadata); atm.setValidator(SIGNAL_ATOM_VALIDATOR); SignalAtomWatch saw = new SignalAtomWatch(signame); atm.addWatch(signame, saw); atoms.put(signame, atm); } return atoms.get(signame); } private static class SignalAtomValidator extends AFn { @Override public Object invoke(Object newVal) { if (newVal instanceof Seqable) { ISeq seq = ((Seqable) newVal).seq(); // An empty seqable returns null. if (seq == null) { return true; } int count = seq.count(); while (count --> 0) { Object o = seq.first(); seq = seq.next(); if (!(o instanceof Runnable)) { return false; } } return true; } else if (newVal == null) { return true; } else { return false; } } } private static class SignalAtomWatch extends AFn { public final String signame; public SignalAtomWatch(String signame) { this.signame = signame; } @Override public Object invoke(Object key, Object ref, Object oldState, Object newState) { SignalRegistererHelper.register(signame, (Seqable) newState); return null; } } }