package xtc.lang.blink; import java.util.regex.Matcher; import java.util.regex.Pattern; import xtc.lang.blink.EventLoop.ReplyHandler; import xtc.lang.blink.Event.BlinkEventSource; import xtc.lang.blink.Event.Java2NativeCompletionEvent; import xtc.lang.blink.Event.DeathEvent; import xtc.lang.blink.Event.RawTextMessageEvent; /** * Event utility classes. */ public class EventUtil { /** A base class for composing the event reply handlers. */ static abstract class CompositionalReplyHandler extends ReplyHandler { /** The list of the handlers. The ordering of this handler matters.*/ protected final ReplyHandler[] handlers; /** Constructor. */ CompositionalReplyHandler(ReplyHandler[] handlers) { this.handlers = handlers; assert handlers != null && handlers.length > 0; } } static final class EventReplyHandler extends ReplyHandler { static final class EventFilter{ private BlinkEventSource source; private Class<?> eventClass; public EventFilter(BlinkEventSource source, Class<?> eventClass) { this.eventClass = eventClass; this.source = source; } public boolean matches(Event event) { return this.source == event.getSource() && eventClass.isInstance(event); } } private final EventFilter[] eventFilters; /** * @param eventClasses */ public EventReplyHandler(EventFilter[] filters) { assert filters != null; this.eventFilters = filters; } boolean dispatch(Event e) { for(EventFilter f: eventFilters) { if (f.matches(e)) { setResult(e); return true; } } return false; } Event getEvent() { return (Event)getResult(); } } /** Conjunctive Composition of the multiple reply handlers.*/ static final class ConjunctiveReplyHandler extends CompositionalReplyHandler { ConjunctiveReplyHandler(ReplyHandler[] handlers) { super(handlers); } /** Convenience constructors */ ConjunctiveReplyHandler(ReplyHandler r1, ReplyHandler r2) { this(new ReplyHandler[] {r1, r2}); } ConjunctiveReplyHandler(ReplyHandler r1, ReplyHandler r2, ReplyHandler r3) { this(new ReplyHandler[] {r1, r2, r3}); } /** The dispatch implementation. */ boolean dispatch(Event e) { if (getResult() != null) {return true;} int numSatisfied = 0; Object result = null; for(final ReplyHandler h : handlers) { if (h.dispatch(e)) { result = h.getResult(); numSatisfied++; } } if (numSatisfied == handlers.length) { assert result != null; setResult(result); return true; } else { return false; } } } static abstract class SingleSourceReplyHandler extends ReplyHandler { /** The event source to keep track of. */ protected final BlinkEventSource sourceFilter; public SingleSourceReplyHandler(final BlinkEventSource sourceFilter) { this.sourceFilter = sourceFilter; } public BlinkEventSource getSourceFilter() { return sourceFilter; } } /** A Declarative reply handler using regular expression. */ static final class RegExpReplyHandler extends SingleSourceReplyHandler { /** The specification - regular expression.*/ private final Pattern p; /** The message accumulated for all the dispatch method calls. */ private final StringBuffer buf; /** The pattern matter. */ private final Matcher m; /** * @param sourceFilter The event source filter. * @param regex The regular expression. */ RegExpReplyHandler(BlinkEventSource sourceFilter, String regex) { super(sourceFilter); this.p = Pattern.compile(regex); this.buf = new StringBuffer(); this.m = p.matcher(buf); } /** * Dispatch the debugger's message event. * @param e The event. * @return true the regular expression is found */ boolean dispatch(Event e) { if (getResult() != null) {return true;} if (e.getSource() != sourceFilter ) { return false; } if (e instanceof RawTextMessageEvent == false ) { return false; } RawTextMessageEvent me = (RawTextMessageEvent)e; String msg = new String(me.getMessage()); buf.append(msg); m.reset(); if (m.find()) { setResult(m); return true; } else { return false; } } /** * Getter method. * @return The matcher. */ public Matcher getMatcher() { return m; } } static abstract class EventClassReplyHandler extends SingleSourceReplyHandler { EventClassReplyHandler(BlinkEventSource sourceFilter) { super(sourceFilter); } public Event getEvent() { return (Event)getResult(); } } /** Observe the end of the death of the event source. */ static final class DeathReplyHandler extends EventClassReplyHandler { public DeathReplyHandler(BlinkEventSource sourceFilter) { super(sourceFilter); } boolean dispatch(Event e) { if (getResult() != null) {return true;} if (e instanceof DeathEvent && e.getSource() == sourceFilter) { setResult(e); return true; } return false; } } static final class J2CCompletionEventHandler extends EventClassReplyHandler { public J2CCompletionEventHandler(JavaDebugger sourceFilter) { super(sourceFilter); } boolean dispatch(Event e) { if (getResult() != null) {return true;} if (e instanceof Java2NativeCompletionEvent && e.getSource() == sourceFilter) { setResult(e); return true; } return false; } } }