package net.sourceforge.pain; import net.sourceforge.pain.data.*; import net.sourceforge.pain.util.*; /** * Codebase internal clocks (pulse) impl. */ public final class Pulse implements Runnable { public static final int PULSE_PER_SCD = 10; public static final int PULSE_PER_MIN = PULSE_PER_SCD * 60; private final Object monitor = new Object(); private final int msec_in_pulse = 1000 / PULSE_PER_SCD; private final Listeners active = new Listeners(); private final Listeners toRemove = new Listeners(); private boolean started = false; private CodebasePulse codebasePulse = null; private int pulse = 0; Pulse() { } public void addListener(PulseListener l) { Log.debug("adding listener:" + l); active.add(l); } public void removeListener(PulseListener l) { Log.debug("adding to remove listener:" + l); toRemove.add(l); } public void run() { codebasePulse = Codebase.getCodebaseData().getCodebasePulse(); pulse = codebasePulse.getPulse(); Log.debug("CodebasePulser start:" + pulse); started = true; long nextPulseTime = System.currentTimeMillis() + msec_in_pulse; long timeToWait; while (started) { try { timeToWait = nextPulseTime - System.currentTimeMillis(); if (timeToWait > 10) { synchronized (monitor) { monitor.wait(timeToWait); } } nextPulseTime = System.currentTimeMillis() + msec_in_pulse; if (toRemove.size > 0) { processRemoved(); } pulse++; codebasePulse.setPulse(pulse); final PulseListener[] data = active.data; final int size = active.size; for (int i = 0; i < size; i++) { try { data[i].pulse(pulse); } catch (Exception e) { Log.error(e); } } } catch (Exception e) { Log.error(e); } catch (Error e) { Log.error("CRITICAL BUG! ERROR THROWN!", e); // new Thread(this).start(); // break; } } Codebase.shutdown(); } private synchronized void processRemoved() { for (int i = 0; i < toRemove.size; i++) { active.remove(toRemove.data[i]); } toRemove.clear(); } /** * @return current time in pulse */ public int currentTime() { return pulse; } /** * the way to stop codebase. */ public void stopPulse() { started = false; } static final class Listeners { PulseListener[] data = new PulseListener[10]; int size = 0; synchronized void add(PulseListener l) { if (size == data.length) { PulseListener[] newData = new PulseListener[size * 2]; System.arraycopy(data, 0, newData, 0, size); data = newData; } data[size] = l; size++; } synchronized void remove(PulseListener l) { for (int i = 0; i < size; i++) { if (data[i] == l) { int numMoved = size - i - 1; if (numMoved > 0) { System.arraycopy(data, i + 1, data, i, numMoved); } data[size] = null; size--; } } } synchronized void clear() { for (int i = 0; i < size; i++) { data[i] = null; } size = 0; } } }