Improved concurrency, annotations

v5stable
Ondřej Hruška 11 years ago
parent e2b6752efb
commit 6b69dabbb9
  1. 20
      src/mightypork/rogue/App.java
  2. 2
      src/mightypork/rogue/Config.java
  3. 16
      src/mightypork/rogue/MainLoop.java
  4. 6
      src/mightypork/rogue/bus/events/ActionRequest.java
  5. 6
      src/mightypork/rogue/bus/events/DestroyEvent.java
  6. 4
      src/mightypork/rogue/bus/events/KeyboardEvent.java
  7. 6
      src/mightypork/rogue/bus/events/MainLoopTaskRequest.java
  8. 4
      src/mightypork/rogue/bus/events/MouseButtonEvent.java
  9. 4
      src/mightypork/rogue/bus/events/MouseMotionEvent.java
  10. 6
      src/mightypork/rogue/bus/events/ResourceLoadRequest.java
  11. 9
      src/mightypork/rogue/bus/events/ScreenChangeEvent.java
  12. 6
      src/mightypork/rogue/bus/events/ScreenRequestEvent.java
  13. 7
      src/mightypork/rogue/bus/events/UpdateEvent.java
  14. 2
      src/mightypork/rogue/fonts/FontBank.java
  15. 2
      src/mightypork/rogue/gui/screens/test_bouncyboxes/ScreenTestBouncy.java
  16. 4
      src/mightypork/rogue/gui/screens/test_cat_sound/ScreenTestCat.java
  17. 8
      src/mightypork/rogue/input/InputSystem.java
  18. 7
      src/mightypork/rogue/loading/AsyncResourceLoader.java
  19. 13
      src/mightypork/rogue/loading/BaseDeferredResource.java
  20. 4
      src/mightypork/rogue/render/DisplaySystem.java
  21. 2
      src/mightypork/rogue/sound/DeferredAudio.java
  22. 2
      src/mightypork/rogue/sound/SoundSystem.java
  23. 2
      src/mightypork/rogue/textures/TextureBank.java
  24. 150
      src/mightypork/utils/control/bus/EventBus.java
  25. 98
      src/mightypork/utils/control/bus/EventChannel.java
  26. 2
      src/mightypork/utils/control/bus/events/Event.java
  27. 2
      src/mightypork/utils/control/bus/events/types/SingularEvent.java
  28. 22
      src/mightypork/utils/logging/Log.java
  29. 205
      src/mightypork/utils/logging/LogInstance.java
  30. 16
      src/mightypork/utils/logging/LogMonitor.java
  31. 17
      src/mightypork/utils/logging/LogToSysoutMonitor.java

@ -5,6 +5,7 @@ import java.io.File;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.nio.channels.FileLock; import java.nio.channels.FileLock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.logging.Level;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
@ -18,9 +19,8 @@ import mightypork.rogue.input.InputSystem;
import mightypork.rogue.input.KeyStroke; import mightypork.rogue.input.KeyStroke;
import mightypork.rogue.render.DisplaySystem; import mightypork.rogue.render.DisplaySystem;
import mightypork.rogue.sound.SoundSystem; import mightypork.rogue.sound.SoundSystem;
import mightypork.rogue.util.SlickLogRedirector;
import mightypork.utils.control.bus.EventBus; import mightypork.utils.control.bus.EventBus;
import mightypork.utils.control.bus.events.DestroyEvent;
import mightypork.utils.control.bus.events.UpdateEvent;
import mightypork.utils.control.interf.Destroyable; import mightypork.utils.control.interf.Destroyable;
import mightypork.utils.control.interf.Updateable; import mightypork.utils.control.interf.Updateable;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@ -105,8 +105,10 @@ public class App implements AppAccess {
{ {
Log.i("Shutting down subsystems..."); Log.i("Shutting down subsystems...");
bus().send(new DestroyEvent()); if(bus() != null) {
bus().destroy(); bus().send(new DestroyEvent());
bus().destroy();
}
Log.i("Terminating..."); Log.i("Terminating...");
System.exit(0); System.exit(0);
@ -124,8 +126,11 @@ public class App implements AppAccess {
* Setup logging * Setup logging
*/ */
final LogInstance log = Log.create("runtime", Paths.LOGS, 10); final LogInstance log = Log.create("runtime", Paths.LOGS, 10);
log.setFileLevel(Level.WARNING);
log.setSysoutLevel(Level.ALL);
log.enable(Config.LOGGING_ENABLED); log.enable(Config.LOGGING_ENABLED);
log.enableSysout(Config.LOG_TO_STDOUT); log.enableSysout(Config.LOG_TO_STDOUT);
org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log));
Log.f1("Initializing subsystems..."); Log.f1("Initializing subsystems...");
@ -134,7 +139,6 @@ public class App implements AppAccess {
*/ */
Log.f2("Initializing Event Bus..."); Log.f2("Initializing Event Bus...");
eventBus = new EventBus(); eventBus = new EventBus();
eventBus.enableLogging(Config.LOG_BUS);
initChannels(); initChannels();
/* /*
@ -236,7 +240,7 @@ public class App implements AppAccess {
@Override @Override
public void run() public void run()
{ {
bus().queue(new ActionRequest(RequestType.FULLSCREEN)); bus().send(new ActionRequest(RequestType.FULLSCREEN));
} }
}); });
@ -246,7 +250,7 @@ public class App implements AppAccess {
@Override @Override
public void run() public void run()
{ {
bus().queue(new ActionRequest(RequestType.SCREENSHOT)); bus().send(new ActionRequest(RequestType.SCREENSHOT));
} }
}); });
@ -256,7 +260,7 @@ public class App implements AppAccess {
@Override @Override
public void run() public void run()
{ {
bus().queue(new ActionRequest(RequestType.SHUTDOWN)); bus().send(new ActionRequest(RequestType.SHUTDOWN));
} }
}); });
} }

@ -76,6 +76,4 @@ public class Config {
public static boolean LOG_TO_STDOUT = true; public static boolean LOG_TO_STDOUT = true;
public static boolean SINGLE_INSTANCE = true; public static boolean SINGLE_INSTANCE = true;
public static boolean LOG_BUS = false;
} }

@ -8,11 +8,11 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import mightypork.rogue.bus.Subsystem; import mightypork.rogue.bus.Subsystem;
import mightypork.rogue.bus.events.ActionRequest; import mightypork.rogue.bus.events.ActionRequest;
import mightypork.rogue.bus.events.UpdateEvent;
import mightypork.rogue.bus.events.ActionRequest.RequestType; import mightypork.rogue.bus.events.ActionRequest.RequestType;
import mightypork.rogue.bus.events.MainLoopTaskRequest; import mightypork.rogue.bus.events.MainLoopTaskRequest;
import mightypork.rogue.tasks.TaskTakeScreenshot; import mightypork.rogue.tasks.TaskTakeScreenshot;
import mightypork.rogue.util.Utils; import mightypork.rogue.util.Utils;
import mightypork.utils.control.bus.events.UpdateEvent;
import mightypork.utils.control.timing.TimerDelta; import mightypork.utils.control.timing.TimerDelta;
@ -38,17 +38,17 @@ public class MainLoop extends Subsystem implements ActionRequest.Listener, MainL
timer = new TimerDelta(); timer = new TimerDelta();
while (running) { while (running) {
Runnable r;
while ((r = taskQueue.poll()) != null) {
r.run();
}
disp().beginFrame(); disp().beginFrame();
bus().send(new UpdateEvent(timer.getDelta())); bus().send(new UpdateEvent(timer.getDelta()));
for (final Runnable r : regularTasks) { for (final Runnable r2 : regularTasks) {
r.run(); r2.run();
}
Runnable r;
while ((r = taskQueue.poll()) != null) {
r.run();
} }
disp().endFrame(); disp().endFrame();

@ -1,8 +1,9 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.SingularEvent; import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.control.bus.events.types.SingularEvent;
/** /**
@ -11,6 +12,7 @@ import mightypork.utils.control.bus.SingularEvent;
* @author MightyPork * @author MightyPork
*/ */
@SingularEvent @SingularEvent
@QueuedEvent
public class ActionRequest implements Event<ActionRequest.Listener> { public class ActionRequest implements Event<ActionRequest.Listener> {
private final RequestType type; private final RequestType type;

@ -1,7 +1,8 @@
package mightypork.utils.control.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.ImmediateEvent;
import mightypork.utils.control.interf.Destroyable; import mightypork.utils.control.interf.Destroyable;
@ -10,6 +11,7 @@ import mightypork.utils.control.interf.Destroyable;
* *
* @author MightyPork * @author MightyPork
*/ */
@ImmediateEvent
public class DestroyEvent implements Event<Destroyable> { public class DestroyEvent implements Event<Destroyable> {
@Override @Override

@ -1,7 +1,8 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.QueuedEvent;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
@ -11,6 +12,7 @@ import org.lwjgl.input.Keyboard;
* *
* @author MightyPork * @author MightyPork
*/ */
@QueuedEvent
public class KeyboardEvent implements Event<KeyboardEvent.Listener> { public class KeyboardEvent implements Event<KeyboardEvent.Listener> {
private final int key; private final int key;

@ -1,8 +1,9 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.SingularEvent; import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.control.bus.events.types.SingularEvent;
/** /**
@ -11,6 +12,7 @@ import mightypork.utils.control.bus.SingularEvent;
* @author MightyPork * @author MightyPork
*/ */
@SingularEvent @SingularEvent
@QueuedEvent
public class MainLoopTaskRequest implements Event<MainLoopTaskRequest.Listener> { public class MainLoopTaskRequest implements Event<MainLoopTaskRequest.Listener> {
private final Runnable task; private final Runnable task;

@ -1,7 +1,8 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Coord;
@ -10,6 +11,7 @@ import mightypork.utils.math.coord.Coord;
* *
* @author MightyPork * @author MightyPork
*/ */
@QueuedEvent
public class MouseButtonEvent implements Event<MouseButtonEvent.Listener> { public class MouseButtonEvent implements Event<MouseButtonEvent.Listener> {
public static final int BUTTON_LEFT = 0; public static final int BUTTON_LEFT = 0;

@ -1,7 +1,8 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Coord;
@ -10,6 +11,7 @@ import mightypork.utils.math.coord.Coord;
* *
* @author MightyPork * @author MightyPork
*/ */
@QueuedEvent
public class MouseMotionEvent implements Event<MouseMotionEvent.Listener> { public class MouseMotionEvent implements Event<MouseMotionEvent.Listener> {
private final Coord move; private final Coord move;

@ -2,8 +2,9 @@ package mightypork.rogue.bus.events;
import mightypork.rogue.loading.DeferredResource; import mightypork.rogue.loading.DeferredResource;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.SingularEvent; import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.control.bus.events.types.SingularEvent;
/** /**
@ -12,6 +13,7 @@ import mightypork.utils.control.bus.SingularEvent;
* @author MightyPork * @author MightyPork
*/ */
@SingularEvent @SingularEvent
@QueuedEvent
public class ResourceLoadRequest implements Event<ResourceLoadRequest.Listener> { public class ResourceLoadRequest implements Event<ResourceLoadRequest.Listener> {
private final DeferredResource resource; private final DeferredResource resource;

@ -1,10 +1,17 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.math.coord.Coord; import mightypork.utils.math.coord.Coord;
/**
* Screen resolution or mode was changed
*
* @author MightyPork
*/
@QueuedEvent
public class ScreenChangeEvent implements Event<ScreenChangeEvent.Listener> { public class ScreenChangeEvent implements Event<ScreenChangeEvent.Listener> {
private final boolean fullscreen; private final boolean fullscreen;

@ -1,8 +1,9 @@
package mightypork.rogue.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.SingularEvent; import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.control.bus.events.types.SingularEvent;
/** /**
@ -11,6 +12,7 @@ import mightypork.utils.control.bus.SingularEvent;
* @author MightyPork * @author MightyPork
*/ */
@SingularEvent @SingularEvent
@QueuedEvent
public class ScreenRequestEvent implements Event<ScreenRequestEvent.Listener> { public class ScreenRequestEvent implements Event<ScreenRequestEvent.Listener> {
private final String scrName; private final String scrName;

@ -1,7 +1,8 @@
package mightypork.utils.control.bus.events; package mightypork.rogue.bus.events;
import mightypork.utils.control.bus.Event; import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.ImmediateEvent;
import mightypork.utils.control.interf.Updateable; import mightypork.utils.control.interf.Updateable;
@ -10,6 +11,8 @@ import mightypork.utils.control.interf.Updateable;
* *
* @author MightyPork * @author MightyPork
*/ */
// sending via queue would hog the bus
@ImmediateEvent
public class UpdateEvent implements Event<Updateable> { public class UpdateEvent implements Event<Updateable> {
private final double deltaTime; private final double deltaTime;

@ -36,7 +36,7 @@ public class FontBank extends AppAdapter {
*/ */
public void loadFont(String key, DeferredFont font) public void loadFont(String key, DeferredFont font)
{ {
bus().queue(new ResourceLoadRequest(font)); bus().send(new ResourceLoadRequest(font));
fonts.put(key, font); fonts.put(key, font);
} }

@ -44,7 +44,7 @@ public class ScreenTestBouncy extends LayeredScreen {
@Override @Override
public void run() public void run()
{ {
bus().queue(new ScreenRequestEvent("test.cat")); bus().send(new ScreenRequestEvent("test.cat"));
} }
}); });
} }

@ -28,7 +28,7 @@ public class ScreenTestCat extends LayeredScreen {
public void run() public void run()
{ {
snd().fadeOutAllLoops(); snd().fadeOutAllLoops();
bus().schedule(new ActionRequest(RequestType.SHUTDOWN), 3); bus().sendDelayed(new ActionRequest(RequestType.SHUTDOWN), 3);
} }
}); });
@ -37,7 +37,7 @@ public class ScreenTestCat extends LayeredScreen {
@Override @Override
public void run() public void run()
{ {
bus().queue(new ScreenRequestEvent("test.bouncy")); bus().send(new ScreenRequestEvent("test.bouncy"));
} }
}); });
} }

@ -92,14 +92,14 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
wasMouse = true; wasMouse = true;
} }
if (wasMouse && !moveSum.isZero()) bus().queue(new MouseMotionEvent(lastPos, moveSum)); if (wasMouse && !moveSum.isZero()) bus().send(new MouseMotionEvent(lastPos, moveSum));
while (Keyboard.next()) { while (Keyboard.next()) {
onKeyEvent(); onKeyEvent();
} }
if (Display.isCloseRequested()) { if (Display.isCloseRequested()) {
bus().queue(new ActionRequest(RequestType.SHUTDOWN)); bus().send(new ActionRequest(RequestType.SHUTDOWN));
} }
} }
@ -118,7 +118,7 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
} }
if (button != -1 || wheeld != 0) { if (button != -1 || wheeld != 0) {
bus().queue(new MouseButtonEvent(pos, button, down, wheeld)); bus().send(new MouseButtonEvent(pos, button, down, wheeld));
} }
moveSum.add_ip(move); moveSum.add_ip(move);
@ -132,7 +132,7 @@ public class InputSystem extends Subsystem implements Updateable, KeyBinder {
final boolean down = Keyboard.getEventKeyState(); final boolean down = Keyboard.getEventKeyState();
final char c = Keyboard.getEventCharacter(); final char c = Keyboard.getEventCharacter();
bus().queue(new KeyboardEvent(key, c, down)); bus().send(new KeyboardEvent(key, c, down));
} }

@ -63,7 +63,10 @@ public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.L
// textures & fonts needs to be loaded in main thread // textures & fonts needs to be loaded in main thread
if (def.getClass().isAnnotationPresent(MustLoadInMainThread.class)) { if (def.getClass().isAnnotationPresent(MustLoadInMainThread.class)) {
app.bus().queue(new MainLoopTaskRequest(new Runnable() {
Log.f3("<LOADER> Loading in main thread:\n "+Log.str(def));
app.bus().send(new MainLoopTaskRequest(new Runnable() {
@Override @Override
public void run() public void run()
@ -75,6 +78,8 @@ public class AsyncResourceLoader extends Thread implements ResourceLoadRequest.L
continue; continue;
} }
Log.f3("<LOADER> Loading async:\n "+Log.str(def));
exs.submit(new Runnable() { exs.submit(new Runnable() {
@Override @Override

@ -27,28 +27,28 @@ public abstract class BaseDeferredResource implements DeferredResource, Destroya
@Override @Override
public synchronized final void load() public synchronized final void load()
{ {
if (loadAttempted) return; if (loadAttempted) return;
loadAttempted = true;
loadFailed = false; loadFailed = false;
if (isNull()) return; if (isNull()) return;
try { try {
if (resource == null) throw new NullPointerException("Resource string cannot be null for non-null resource."); if (resource == null) throw new NullPointerException("Resource string cannot be null for non-null resource.");
Log.f3("<res> Loading: " + this); Log.f3("<RES> Loading: " + this);
loadResource(resource); loadResource(resource);
Log.f3("<res> Loaded: " + this + " loaded."); Log.f3("<RES> Loaded: " + this + " loaded.");
} catch (final Exception e) { } catch (final Exception e) {
loadFailed = true; loadFailed = true;
Log.e("Failed to load resource \"" + resource + "\"", e); Log.e("<RES> Failed to load \"" + resource + "\"", e);
} }
loadAttempted = true;
} }
@Override @Override
public synchronized final boolean isLoaded() public final boolean isLoaded()
{ {
if (isNull()) return false; if (isNull()) return false;
@ -68,6 +68,7 @@ public abstract class BaseDeferredResource implements DeferredResource, Destroya
if (isLoaded()) { if (isLoaded()) {
return true; return true;
} else { } else {
Log.w("<RES> First use, not loaded yet - loading directly\n"+this);
load(); load();
} }

@ -86,7 +86,7 @@ public class DisplaySystem extends Subsystem implements ConstraintContext {
Display.update(); Display.update();
} }
bus().queue(new ScreenChangeEvent(true, Display.isFullscreen(), getSize())); bus().send(new ScreenChangeEvent(true, Display.isFullscreen(), getSize()));
} catch (final Throwable t) { } catch (final Throwable t) {
Log.e("Failed to toggle fullscreen mode.", t); Log.e("Failed to toggle fullscreen mode.", t);
@ -166,7 +166,7 @@ public class DisplaySystem extends Subsystem implements ConstraintContext {
{ {
// handle resize // handle resize
if (Display.wasResized()) { if (Display.wasResized()) {
bus().queue(new ScreenChangeEvent(false, Display.isFullscreen(), getSize())); bus().send(new ScreenChangeEvent(false, Display.isFullscreen(), getSize()));
} }
glLoadIdentity(); glLoadIdentity();

@ -225,7 +225,7 @@ public class DeferredAudio extends BaseDeferredResource {
@Override @Override
public void destroy() public void destroy()
{ {
if (!isLoaded()) return; if (!isLoaded() || backingAudio == null) return;
backingAudio.release(); backingAudio.release();
backingAudio = null; backingAudio = null;

@ -149,7 +149,7 @@ public class SoundSystem extends Subsystem implements Updateable {
private DeferredAudio getResource(String res) private DeferredAudio getResource(String res)
{ {
final DeferredAudio a = new DeferredAudio(res); final DeferredAudio a = new DeferredAudio(res);
bus().queue(new ResourceLoadRequest(a)); bus().send(new ResourceLoadRequest(a));
if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered."); if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered.");
resources.add(a); resources.add(a);

@ -58,7 +58,7 @@ public class TextureBank extends AppAdapter {
tx.setFilter(filter_min, filter_mag); tx.setFilter(filter_min, filter_mag);
tx.setWrap(wrap); tx.setWrap(wrap);
bus().queue(new ResourceLoadRequest(tx)); bus().send(new ResourceLoadRequest(tx));
textures.put(key, tx); textures.put(key, tx);
lastTx = tx; lastTx = tx;

@ -5,6 +5,10 @@ import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed; import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.ImmediateEvent;
import mightypork.utils.control.bus.events.types.QueuedEvent;
import mightypork.utils.control.bus.events.types.SingularEvent;
import mightypork.utils.control.interf.Destroyable; import mightypork.utils.control.interf.Destroyable;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@ -23,17 +27,16 @@ final public class EventBus implements Destroyable {
private final BufferedHashSet<Object> clients = new BufferedHashSet<Object>(); private final BufferedHashSet<Object> clients = new BufferedHashSet<Object>();
/** Messages queued for delivery */ /** Messages queued for delivery */
private final DelayQueue<DelayedMessage> sendQueue = new DelayQueue<DelayedMessage>(); private final DelayQueue<DelayedEvent> sendQueue = new DelayQueue<DelayedEvent>();
/** Queue polling thread */ /** Queue polling thread */
private final QueuePollingThread busThread; private final QueuePollingThread busThread;
/** Log all */
private boolean logging = false;
/** Whether the bus was destroyed */ /** Whether the bus was destroyed */
private boolean dead = false; private boolean dead = false;
public boolean logSending = false;
/** /**
* Make a new bus and start it's queue thread. * Make a new bus and start it's queue thread.
@ -44,23 +47,6 @@ final public class EventBus implements Destroyable {
} }
/**
* Enable a level of logging.
*
* @param level 0 none, 1 warning only, 2 all
*/
public void enableLogging(boolean level)
{
assertLive();
logging = level;
for (final EventChannel<?, ?> ch : channels) {
ch.enableLogging(logging);
}
}
/** /**
* Add a {@link EventChannel} to this bus.<br> * Add a {@link EventChannel} to this bus.<br>
* If a channel of matching types is already added, it is returned instead. * If a channel of matching types is already added, it is returned instead.
@ -81,25 +67,23 @@ final public class EventBus implements Destroyable {
} }
channels.add(channel); channels.add(channel);
channel.enableLogging(logging);
if (logging) Log.f3("<bus> Added chanel: " + Log.str(channel));
return channel; return channel;
} }
/** /**
* Add a channel for given message and client type. * Add a channel for given event and client type.
* *
* @param messageClass message type * @param eventClass event type
* @param clientClass client type * @param clientClass client type
* @return the created channel instance * @return the created channel instance
*/ */
public <F_EVENT extends Event<F_CLIENT>, F_CLIENT> EventChannel<?, ?> addChannel(Class<F_EVENT> messageClass, Class<F_CLIENT> clientClass) public <F_EVENT extends Event<F_CLIENT>, F_CLIENT> EventChannel<?, ?> addChannel(Class<F_EVENT> eventClass, Class<F_CLIENT> clientClass)
{ {
assertLive(); assertLive();
final EventChannel<F_EVENT, F_CLIENT> channel = EventChannel.create(messageClass, clientClass); final EventChannel<F_EVENT, F_CLIENT> channel = EventChannel.create(eventClass, clientClass);
return addChannel(channel); return addChannel(channel);
} }
@ -118,31 +102,54 @@ final public class EventBus implements Destroyable {
/** /**
* Add message to a queue * Send based on annotation.
* *
* @param message message * @param event event
*/ */
public void queue(Event<?> message) public void send(Event<?> event)
{ {
assertLive(); assertLive();
schedule(message, 0); if(event.getClass().isAnnotationPresent(QueuedEvent.class)) {
sendQueued(event);
return;
}
if(event.getClass().isAnnotationPresent(ImmediateEvent.class)) {
sendDirect(event);
return;
}
dispatch(event);
} }
/** /**
* Add message to a queue, scheduled for given time. * Add event to a queue
* *
* @param message message * @param event event
* @param delay delay before message is dispatched
*/ */
public void schedule(Event<?> message, double delay) public void sendQueued(Event<?> event)
{ {
assertLive(); assertLive();
final DelayedMessage dm = new DelayedMessage(delay, message); sendDelayed(event, 0);
}
if (logging) Log.f3("<bus> + [ Queuing: " + Log.str(message) + " ]");
/**
* Add event to a queue, scheduled for given time.
*
* @param event event
* @param delay delay before event is dispatched
*/
public void sendDelayed(Event<?> event, double delay)
{
assertLive();
final DelayedEvent dm = new DelayedEvent(delay, event);
if(logSending) Log.f3("<bus> Q "+Log.str(event)+", t = +"+delay+"s");
sendQueue.add(dm); sendQueue.add(dm);
} }
@ -153,9 +160,26 @@ final public class EventBus implements Destroyable {
* Should be used for real-time events that require immediate response, such * Should be used for real-time events that require immediate response, such
* as timing events. * as timing events.
* *
* @param message message * @param event event
*/
public void sendDirect(Event<?> event)
{
assertLive();
if(logSending) Log.f3("<bus> D "+Log.str(event));
dispatch(event);
}
/**
* Send immediately.<br>
* Should be used for real-time events that require immediate response, such
* as timing events.
*
* @param event event
*/ */
public void send(Event<?> message) private void dispatch(Event<?> event)
{ {
assertLive(); assertLive();
@ -163,29 +187,21 @@ final public class EventBus implements Destroyable {
channels.setBuffering(true); channels.setBuffering(true);
clients.setBuffering(true); clients.setBuffering(true);
if (logging) Log.f3("<bus> - [ Sending: " + Log.str(message) + " ]");
boolean sent = false; boolean sent = false;
boolean channelAccepted = false; boolean accepted = false;
final boolean singular = message.getClass().isAnnotationPresent(SingularEvent.class); final boolean singular = event.getClass().isAnnotationPresent(SingularEvent.class);
for (final EventChannel<?, ?> b : channels) { for (final EventChannel<?, ?> b : channels) {
if (b.canBroadcast(message)) { if (b.canBroadcast(event)) {
channelAccepted = true; accepted = true;
sent |= b.broadcast(message, clients); sent |= b.broadcast(event, clients);
} }
if (sent && singular) { if (sent && singular) break;
break;
}
} }
// more severe if(!accepted) Log.e("<bus> Not accepted by any channel: " + Log.str(event));
if (!channelAccepted) Log.w("<bus> Not accepted by any channel: " + Log.str(message));
// less severe
if (logging && !sent) Log.w("<bus> Not delivered to any client: " + Log.str(message));
channels.setBuffering(false); channels.setBuffering(false);
clients.setBuffering(false); clients.setBuffering(false);
@ -206,8 +222,6 @@ final public class EventBus implements Destroyable {
if (client == null) return; if (client == null) return;
clients.add(client); clients.add(client);
if (logging) Log.f3("<bus> ADDING CLIENT " + client);
} }
@ -221,8 +235,6 @@ final public class EventBus implements Destroyable {
assertLive(); assertLive();
clients.remove(client); clients.remove(client);
if (logging) Log.f3("<bus> REMOVING CLIENT " + client);
} }
@ -241,16 +253,16 @@ final public class EventBus implements Destroyable {
return false; return false;
} }
private class DelayedMessage implements Delayed { private class DelayedEvent implements Delayed {
private final long due; private final long due;
private Event<?> theMessage = null; private Event<?> evt = null;
public DelayedMessage(double seconds, Event<?> theMessage) { public DelayedEvent(double seconds, Event<?> event) {
super(); super();
this.due = System.currentTimeMillis() + (long) (seconds * 1000); this.due = System.currentTimeMillis() + (long) (seconds * 1000);
this.theMessage = theMessage; this.evt = event;
} }
@ -268,9 +280,9 @@ final public class EventBus implements Destroyable {
} }
public Event<?> getMessage() public Event<?> getEvent()
{ {
return theMessage; return evt;
} }
} }
@ -288,19 +300,19 @@ final public class EventBus implements Destroyable {
@Override @Override
public void run() public void run()
{ {
DelayedMessage dm; DelayedEvent evt;
while (!stopped) { while (!stopped) {
dm = null; evt = null;
try { try {
dm = sendQueue.take(); evt = sendQueue.take();
} catch (final InterruptedException ignored) { } catch (final InterruptedException ignored) {
// //
} }
if (dm != null) { if (evt != null) {
send(dm.getMessage()); dispatch(evt.getEvent());
} }
} }
} }

@ -6,79 +6,69 @@ import java.util.HashSet;
import mightypork.utils.control.bus.clients.DelegatingClient; import mightypork.utils.control.bus.clients.DelegatingClient;
import mightypork.utils.control.bus.clients.ToggleableClient; import mightypork.utils.control.bus.clients.ToggleableClient;
import mightypork.utils.control.bus.events.Event;
import mightypork.utils.control.bus.events.types.SingularEvent;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
/** /**
* Message channel, module of {@link EventBus} * Event delivery channel, module of {@link EventBus}
* *
* @author MightyPork * @author MightyPork
* @param <EVENT> message type * @param <EVENT> event type
* @param <CLIENT> client (subscriber) type * @param <CLIENT> client (subscriber) type
*/ */
final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> { final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
private final Class<CLIENT> clientClass; private final Class<CLIENT> clientClass;
private final Class<EVENT> messageClass; private final Class<EVENT> eventClass;
private boolean logging = false;
/** /**
* Create a channel * Create a channel
* *
* @param messageClass event class * @param eventClass event class
* @param clientClass client class * @param clientClass client class
*/ */
public EventChannel(Class<EVENT> messageClass, Class<CLIENT> clientClass) { public EventChannel(Class<EVENT> eventClass, Class<CLIENT> clientClass) {
if (messageClass == null || clientClass == null) throw new NullPointerException("Null Message or Client class."); if (eventClass == null || clientClass == null) {
throw new NullPointerException("Null Event or Client class.");
}
this.clientClass = clientClass; this.clientClass = clientClass;
this.messageClass = messageClass; this.eventClass = eventClass;
}
/**
* Enable logging of non-warning debug messages.
*
* @param logging enable logging
*/
public void enableLogging(boolean logging)
{
this.logging = logging;
} }
/** /**
* Try to broadcast a message.<br> * Try to broadcast a event.<br>
* If message is of wrong type, <code>false</code> is returned. * If event is of wrong type, <code>false</code> is returned.
* *
* @param message a message to be sent * @param event a event to be sent
* @param clients collection of clients * @param clients collection of clients
* @return true if message was sent * @return true if event was sent
*/ */
public boolean broadcast(Event<?> message, Collection<Object> clients) public boolean broadcast(Event<?> event, Collection<Object> clients)
{ {
if (!canBroadcast(message)) return false; if (!canBroadcast(event)) return false;
final EVENT evt = messageClass.cast(message); return doBroadcast(eventClass.cast(event), clients, new HashSet<Object>());
return doBroadcast(evt, clients, new HashSet<Object>());
} }
/** /**
* Send the message * Send the event
* *
* @param message sent message * @param event sent event
* @param clients subscribing clients * @param clients subscribing clients
* @param processed clients already processed * @param processed clients already processed
* @return success * @return success
*/ */
private boolean doBroadcast(final EVENT message, final Collection<Object> clients, final Collection<Object> processed) private boolean doBroadcast(final EVENT event, final Collection<Object> clients, final Collection<Object> processed)
{ {
boolean sent = false; boolean sent = false;
final boolean singular = message.getClass().isAnnotationPresent(SingularEvent.class); final boolean singular = event.getClass().isAnnotationPresent(SingularEvent.class);
for (final Object client : clients) { for (final Object client : clients) {
@ -96,13 +86,10 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
// opt-out // opt-out
if (client instanceof ToggleableClient) { if (client instanceof ToggleableClient) {
if (!((ToggleableClient) client).isListening()) { if (!((ToggleableClient) client).isListening()) continue;
if (logging) Log.f3("<bus> Client disabled: " + Log.str(client));
continue;
}
} }
sent |= sendTo(client, message); sent |= sendTo(client, event);
// singular event ain't no whore, handled once only. // singular event ain't no whore, handled once only.
if (sent && singular) return true; if (sent && singular) return true;
@ -114,11 +101,9 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
final Collection<Object> children = ((DelegatingClient) client).getChildClients(); final Collection<Object> children = ((DelegatingClient) client).getChildClients();
if (children != null && children.size() > 0) { if (children != null && children.size() > 0) {
sent |= doBroadcast(message, children, processed); sent |= doBroadcast(event, children, processed);
} }
} else {
if (logging) Log.f3("<bus> Client not delegating: " + Log.str(client));
} }
} }
} }
@ -128,18 +113,17 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
/** /**
* Send a message to a client. * Send an event to a client.
* *
* @param client target client * @param client target client
* @param message message to send * @param event event to send
* @return success * @return success
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private boolean sendTo(Object client, EVENT message) private boolean sendTo(Object client, EVENT event)
{ {
if (isClientOfType(client)) { if (isClientOfType(client)) {
if (logging) Log.f3("<bus> Delivered " + Log.str(message) + " to " + Log.str(client)); ((Event<CLIENT>) event).handleBy((CLIENT) client);
((Event<CLIENT>) message).handleBy((CLIENT) client);
return true; return true;
} }
return false; return false;
@ -147,28 +131,28 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
/** /**
* Check if the given message can be broadcasted by this * Check if the given event can be broadcasted by this
* {@link EventChannel} * {@link EventChannel}
* *
* @param message event object * @param event event object
* @return can be broadcasted * @return can be broadcasted
*/ */
public boolean canBroadcast(Event<?> message) public boolean canBroadcast(Event<?> event)
{ {
return message != null && messageClass.isInstance(message); return event != null && eventClass.isInstance(event);
} }
/** /**
* Create an instance for given types * Create an instance for given types
* *
* @param messageClass event class * @param eventClass event class
* @param clientClass client class * @param clientClass client class
* @return the broadcaster * @return the broadcaster
*/ */
public static <F_EVENT extends Event<F_CLIENT>, F_CLIENT> EventChannel<F_EVENT, F_CLIENT> create(Class<F_EVENT> messageClass, Class<F_CLIENT> clientClass) public static <F_EVENT extends Event<F_CLIENT>, F_CLIENT> EventChannel<F_EVENT, F_CLIENT> create(Class<F_EVENT> eventClass, Class<F_CLIENT> clientClass)
{ {
return new EventChannel<F_EVENT, F_CLIENT>(messageClass, clientClass); return new EventChannel<F_EVENT, F_CLIENT>(eventClass, clientClass);
} }
@ -202,7 +186,7 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
final int prime = 13; final int prime = 13;
int result = 1; int result = 1;
result = prime * result + ((clientClass == null) ? 0 : clientClass.hashCode()); result = prime * result + ((clientClass == null) ? 0 : clientClass.hashCode());
result = prime * result + ((messageClass == null) ? 0 : messageClass.hashCode()); result = prime * result + ((eventClass == null) ? 0 : eventClass.hashCode());
return result; return result;
} }
@ -217,9 +201,9 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
if (clientClass == null) { if (clientClass == null) {
if (other.clientClass != null) return false; if (other.clientClass != null) return false;
} else if (!clientClass.equals(other.clientClass)) return false; } else if (!clientClass.equals(other.clientClass)) return false;
if (messageClass == null) { if (eventClass == null) {
if (other.messageClass != null) return false; if (other.eventClass != null) return false;
} else if (!messageClass.equals(other.messageClass)) return false; } else if (!eventClass.equals(other.eventClass)) return false;
return true; return true;
} }
@ -227,6 +211,6 @@ final public class EventChannel<EVENT extends Event<CLIENT>, CLIENT> {
@Override @Override
public String toString() public String toString()
{ {
return "{ " + Log.str(messageClass) + " => " + Log.str(clientClass) + " }"; return "{ " + Log.str(eventClass) + " => " + Log.str(clientClass) + " }";
} }
} }

@ -1,4 +1,4 @@
package mightypork.utils.control.bus; package mightypork.utils.control.bus.events;
/** /**

@ -1,4 +1,4 @@
package mightypork.utils.control.bus; package mightypork.utils.control.bus.events.types;
import java.lang.annotation.*; import java.lang.annotation.*;

@ -8,7 +8,7 @@ import java.util.HashMap;
public class Log { public class Log {
/** enable static logging */ /** enable static logging */
private static boolean esl = true; private static boolean staticLogging = true;
/** /**
@ -18,7 +18,7 @@ public class Log {
*/ */
public static void f1(String msg) public static void f1(String msg)
{ {
if (esl && ready()) main.f1(msg); if (staticLogging && ready()) main.f1(msg);
} }
@ -29,7 +29,7 @@ public class Log {
*/ */
public static void f2(String msg) public static void f2(String msg)
{ {
if (esl && ready()) main.f2(msg); if (staticLogging && ready()) main.f2(msg);
} }
@ -40,7 +40,7 @@ public class Log {
*/ */
public static void f3(String msg) public static void f3(String msg)
{ {
if (esl && ready()) main.f3(msg); if (staticLogging && ready()) main.f3(msg);
} }
@ -51,7 +51,7 @@ public class Log {
*/ */
public static void i(String msg) public static void i(String msg)
{ {
if (esl && ready()) main.i(msg); if (staticLogging && ready()) main.i(msg);
} }
@ -62,7 +62,7 @@ public class Log {
*/ */
public static void w(String msg) public static void w(String msg)
{ {
if (esl && ready()) main.w(msg); if (staticLogging && ready()) main.w(msg);
} }
@ -73,7 +73,7 @@ public class Log {
*/ */
public static void e(String msg) public static void e(String msg)
{ {
if (esl && ready()) main.e(msg); if (staticLogging && ready()) main.e(msg);
} }
@ -85,7 +85,7 @@ public class Log {
*/ */
public static void e(String msg, Throwable thrown) public static void e(String msg, Throwable thrown)
{ {
if (esl && ready()) main.e(msg, thrown); if (staticLogging && ready()) main.e(msg, thrown);
} }
@ -96,13 +96,13 @@ public class Log {
*/ */
public static void e(Throwable thrown) public static void e(Throwable thrown)
{ {
if (esl && ready()) main.e(thrown); if (staticLogging && ready()) main.e(thrown);
} }
public static void enable(boolean flag) public static void enable(boolean flag)
{ {
if (esl && ready()) main.enable(flag); if (staticLogging && ready()) main.enable(flag);
} }
@ -113,7 +113,7 @@ public class Log {
*/ */
public static void enableStaticLogging(boolean flag) public static void enableStaticLogging(boolean flag)
{ {
esl = flag; staticLogging = flag;
} }
private static HashMap<String, LogInstance> logs = new HashMap<String, LogInstance>(); private static HashMap<String, LogInstance> logs = new HashMap<String, LogInstance>();

@ -38,7 +38,7 @@ public class LogInstance {
private final int logs_to_keep; private final int logs_to_keep;
/** Logs dir */ /** Logs dir */
private final File dir; private final File log_dir;
/** Logger instance. */ /** Logger instance. */
private Logger logger; private Logger logger;
@ -54,10 +54,17 @@ public class LogInstance {
private LogToSysoutMonitor sysoutMonitor; private LogToSysoutMonitor sysoutMonitor;
/**
* Log
*
* @param name log name
* @param dir log directory
* @param oldLogCount number of old log files to keep: -1 all, 0 none.
*/
public LogInstance(String name, File dir, int oldLogCount) { public LogInstance(String name, File dir, int oldLogCount) {
this.name = name; this.name = name;
this.file = new File(dir, name + getSuffix()); this.file = new File(dir, name + getSuffix());
this.dir = dir; this.log_dir = dir;
this.logs_to_keep = oldLogCount; this.logs_to_keep = oldLogCount;
init(); init();
@ -71,7 +78,7 @@ public class LogInstance {
{ {
logger = Logger.getLogger(name); logger = Logger.getLogger(name);
cleanup(); cleanLoggingDirectory();
FileHandler handler = null; FileHandler handler = null;
@ -92,26 +99,27 @@ public class LogInstance {
logger.setUseParentHandlers(false); logger.setUseParentHandlers(false);
logger.setLevel(Level.ALL); logger.setLevel(Level.ALL);
logger.info("Main logger initialized."); logger.info("Logger \""+name+"\" initialized.");
logger.info((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).format(new Date())); logger.info((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).format(new Date()));
} }
private void cleanup() private void cleanLoggingDirectory()
{ {
if (logs_to_keep == 0) return; // overwrite if (logs_to_keep == 0) return; // overwrite
// move old file
for (final File f : FileUtils.listDirectory(file.getParentFile())) { for (final File f : FileUtils.listDirectory(file.getParentFile())) {
if (!f.isFile()) continue; if (!f.isFile()) continue;
if (f.equals(file)) { if (f.equals(file)) {
final Date d = new Date(f.lastModified());
final Date d = new Date(f.lastModified());
final String fbase = name + '_' + (new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss")).format(d); final String fbase = name + '_' + (new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss")).format(d);
final String suff = getSuffix(); final String suff = getSuffix();
String cntStr = ""; String cntStr = "";
File f2; File f2;
for (int cnt = 0; (f2 = new File(dir, fbase + cntStr + suff)).exists(); cntStr = "_" + (++cnt)) {} for (int cnt = 0; (f2 = new File(log_dir, fbase + cntStr + suff)).exists(); cntStr = "_" + (++cnt)) {}
f.renameTo(f2); f.renameTo(f2);
} }
@ -119,7 +127,7 @@ public class LogInstance {
if (logs_to_keep == -1) return; // keep all if (logs_to_keep == -1) return; // keep all
final List<File> oldLogs = FileUtils.listDirectory(dir, new FileFilter() { final List<File> oldLogs = FileUtils.listDirectory(log_dir, new FileFilter() {
@Override @Override
public boolean accept(File f) public boolean accept(File f)
@ -174,6 +182,18 @@ public class LogInstance {
} }
public void setSysoutLevel(Level level)
{
sysoutMonitor.setLevel(level);
}
public void setFileLevel(Level level)
{
logger.setLevel(level);
}
/** /**
* Enable logging. * Enable logging.
* *
@ -197,6 +217,34 @@ public class LogInstance {
} }
public void log(Level level, String msg)
{
if (enabled) {
logger.log(level, msg);
String fmt = formatMessage(level, msg, null);
for (final LogMonitor mon : monitors.values()) {
mon.onMessageLogged(level, fmt);
}
}
}
public void log(Level level, String msg, Throwable t)
{
if (enabled) {
logger.log(level, msg, t);
String fmt = formatMessage(level, msg, null);
for (final LogMonitor mon : monitors.values()) {
mon.onMessageLogged(level, fmt);
}
}
}
/** /**
* Log FINE message * Log FINE message
* *
@ -204,7 +252,7 @@ public class LogInstance {
*/ */
public void f1(String msg) public void f1(String msg)
{ {
if (enabled) logger.log(Level.FINE, msg); log(Level.FINE, msg);
} }
@ -215,7 +263,7 @@ public class LogInstance {
*/ */
public void f2(String msg) public void f2(String msg)
{ {
if (enabled) logger.log(Level.FINER, msg); log(Level.FINER, msg);
} }
@ -226,7 +274,7 @@ public class LogInstance {
*/ */
public void f3(String msg) public void f3(String msg)
{ {
if (enabled) logger.log(Level.FINEST, msg); log(Level.FINEST, msg);
} }
@ -237,7 +285,7 @@ public class LogInstance {
*/ */
public void i(String msg) public void i(String msg)
{ {
if (enabled) logger.log(Level.INFO, msg); log(Level.INFO, msg);
} }
@ -248,7 +296,7 @@ public class LogInstance {
*/ */
public void w(String msg) public void w(String msg)
{ {
if (enabled) logger.log(Level.WARNING, msg); log(Level.WARNING, msg);
} }
@ -259,7 +307,7 @@ public class LogInstance {
*/ */
public void e(String msg) public void e(String msg)
{ {
if (enabled) logger.log(Level.SEVERE, msg); log(Level.SEVERE, msg);
} }
@ -271,7 +319,7 @@ public class LogInstance {
*/ */
public void e(String msg, Throwable thrown) public void e(String msg, Throwable thrown)
{ {
if (enabled) logger.log(Level.SEVERE, msg + "\n" + getStackTrace(thrown)); log(Level.SEVERE, msg);
} }
@ -282,24 +330,7 @@ public class LogInstance {
*/ */
public void e(Throwable thrown) public void e(Throwable thrown)
{ {
if (enabled) logger.log(Level.SEVERE, getStackTrace(thrown)); log(Level.SEVERE, null, thrown);
}
/**
* Get stack trace from throwable
*
* @param t
* @return trace
*/
private static String getStackTrace(Throwable t)
{
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
} }
/** /**
@ -310,83 +341,75 @@ public class LogInstance {
*/ */
private class LogFormatter extends Formatter { private class LogFormatter extends Formatter {
/** Newline string constant */
private final String nl = System.getProperty("line.separator");
@Override @Override
public String format(LogRecord record) public String format(LogRecord record)
{ {
final StringBuffer buf = new StringBuffer(180); return LogInstance.formatMessage(record.getLevel(), record.getMessage(), record.getThrown());
}
if (record.getMessage().equals("\n")) { }
return nl;
}
if (record.getMessage().charAt(0) == '\n') {
buf.append(nl);
record.setMessage(record.getMessage().substring(1));
}
final Level level = record.getLevel(); /**
String trail = "[ ? ]"; * @return log filename suffix (incl. dot)
if (level == Level.FINE) { */
trail = "[ # ] "; protected String getSuffix()
} {
if (level == Level.FINER) { return ".log";
trail = "[ - ] "; }
}
if (level == Level.FINEST) {
trail = "[ ] ";
}
if (level == Level.INFO) {
trail = "[ i ] ";
}
if (level == Level.SEVERE) {
trail = "[!E!] ";
}
if (level == Level.WARNING) {
trail = "[!W!] ";
}
record.setMessage(record.getMessage().replaceAll("\n", nl + trail));
buf.append(trail);
buf.append(formatMessage(record));
buf.append(nl); private static String formatMessage(Level level, String message, Throwable throwable)
{
final Throwable throwable = record.getThrown(); final String nl = System.getProperty("line.separator");
if (throwable != null) {
buf.append("at ");
buf.append(record.getSourceClassName());
buf.append('.');
buf.append(record.getSourceMethodName());
buf.append(nl);
final StringWriter sink = new StringWriter(); if (message.equals("\n")) {
throwable.printStackTrace(new PrintWriter(sink, true)); return nl;
buf.append(sink.toString()); }
buf.append(nl); if (message.charAt(0) == '\n') {
} message = nl + message.substring(1);
}
final String str = buf.toString(); String prefix = "[ ? ]";
if (level == Level.FINE) {
prefix = "[ # ] ";
} else if (level == Level.FINER) {
prefix = "[ - ] ";
} else if (level == Level.FINEST) {
prefix = "[ ] ";
} else if (level == Level.INFO) {
prefix = "[ i ] ";
} else if (level == Level.SEVERE) {
prefix = "[!E!] ";
} else if (level == Level.WARNING) {
prefix = "[!W!] ";
}
for (final LogMonitor mon : monitors.values()) { message = prefix + message.replaceAll("\n", nl + prefix) + nl;
mon.log(level, str);
}
return str; if (throwable != null) {
message += getStackTrace(throwable);
} }
return message;
} }
/** /**
* @return log filename suffix (incl. dot) * Get stack trace from throwable
*
* @param t
* @return trace
*/ */
protected String getSuffix() private static String getStackTrace(Throwable t)
{ {
return ".log"; final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
} }
} }

@ -4,10 +4,18 @@ package mightypork.utils.logging;
import java.util.logging.Level; import java.util.logging.Level;
/**
* Log monitor, receives all logged messages
*
* @author MightyPork
*/
public interface LogMonitor { public interface LogMonitor {
public void log(Level level, String message); /**
* Message logged;
*
public void enable(boolean enable); * @param level message level
* @param message message text, already formatted.
*/
void onMessageLogged(Level level, String message);
} }

@ -7,22 +7,29 @@ import java.util.logging.Level;
public class LogToSysoutMonitor implements LogMonitor { public class LogToSysoutMonitor implements LogMonitor {
private boolean enabled = true; private boolean enabled = true;
private Level accepted = Level.ALL;
public void setLevel(Level level)
{
this.accepted = level;
}
@Override @Override
public void log(Level level, String message) public void onMessageLogged(Level level, String message)
{ {
if (!enabled) return; if (!enabled) return;
if (accepted.intValue() > level.intValue()) return;
if (level == Level.FINE || level == Level.FINER || level == Level.FINEST || level == Level.INFO) { if (level == Level.SEVERE || level == Level.WARNING) {
System.out.print(message);
} else if (level == Level.SEVERE || level == Level.WARNING) {
System.err.print(message); System.err.print(message);
} else {
System.out.print(message);
} }
} }
@Override
public void enable(boolean enable) public void enable(boolean enable)
{ {
this.enabled = enable; this.enabled = enable;

Loading…
Cancel
Save