|
@@ -9,7 +9,13 @@ package net.ranides.assira.io;
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
import java.io.InputStream;
|
|
|
import java.io.OutputStream;
|
|
import java.io.OutputStream;
|
|
|
|
|
+import net.ranides.assira.annotations.Meta;
|
|
|
import net.ranides.assira.events.EventListener;
|
|
import net.ranides.assira.events.EventListener;
|
|
|
|
|
+import net.ranides.assira.events.EventRouter;
|
|
|
|
|
+import net.ranides.assira.events.EventRouterThread;
|
|
|
|
|
+import net.ranides.assira.events.ReflectEventListener;
|
|
|
|
|
+import net.ranides.assira.trace.AdvLogger;
|
|
|
|
|
+import net.ranides.assira.trace.LoggerUtils;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
*
|
|
*
|
|
@@ -17,123 +23,88 @@ import net.ranides.assira.events.EventListener;
|
|
|
*/
|
|
*/
|
|
|
public final class AsyncStream {
|
|
public final class AsyncStream {
|
|
|
|
|
|
|
|
- // InputDevice handle(IORequest) -> stream.read
|
|
|
|
|
- //
|
|
|
|
|
- // InputDriver read -> handle(IORequest)
|
|
|
|
|
- //
|
|
|
|
|
- // InputListener read -> stream.read -> handle(IOEvent)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // OutputDevice handle(IORequest) -> stream.write
|
|
|
|
|
- //
|
|
|
|
|
- // OutputDriver write -> handle(IORequest)
|
|
|
|
|
- //
|
|
|
|
|
- // OutputListener write -> stream.write -> handle(IOEvent)
|
|
|
|
|
-
|
|
|
|
|
- // komentarz: to chyba jest bez sensu, bo stream nie ma zaimplementowanego
|
|
|
|
|
- // interfejsu w taki sposób, żeby działał w tle (np metody powinny zwracać
|
|
|
|
|
- // wyniki).
|
|
|
|
|
-
|
|
|
|
|
- // W praktyce InputListener oraz OutputListener mają sens w 100%.
|
|
|
|
|
-
|
|
|
|
|
- // OutputDriver oraz OutputDevice mają sens w 75% (obsługa błędów leży)
|
|
|
|
|
- // 1. OutputDriver nie rzuca wyjątków
|
|
|
|
|
- // 2. OutputDevice nie wie, komu przesłać zdarzenia o wyjątkach
|
|
|
|
|
-
|
|
|
|
|
- // InputDriver oraz InputDevice mają sens w 25% (obsługa wszystkiego leży)
|
|
|
|
|
- // 3. InputDriver nie rzuca wyjątków
|
|
|
|
|
- // 4. InputDriver nie zwraca sensownych wyników
|
|
|
|
|
- // 5. InputDevice nie wie komu przesłać zdarzenia o wyjątkach
|
|
|
|
|
- // 6. InputDevice nie wie komu zwrócić wyniki
|
|
|
|
|
- // 7. kto ma tworzyć bufor na czytane dane ???
|
|
|
|
|
- //
|
|
|
|
|
- // W zasadzie to działa rozsądnie tylko dla układu:
|
|
|
|
|
- // InputDriver -> InputDevice -> InputListener -> InputStream
|
|
|
|
|
- //
|
|
|
|
|
- // A poniższy układ do niczego się nie nadaje:
|
|
|
|
|
- // InputDriver -> InputDevice -> InputStream
|
|
|
|
|
-
|
|
|
|
|
- // Może więc tworzenie Device będzie możliwie tylko dla Listener'a?
|
|
|
|
|
- // A dopiero Listener by był tworzony ze stream'a?
|
|
|
|
|
- // To by rozwiązało problemy 2, 5, 6.
|
|
|
|
|
-
|
|
|
|
|
- // Problem 7 powinno się rozwiązać alokując pamięć ZAWSZE. W końcu ten, co wywołał
|
|
|
|
|
- // metodę, to chuj wie co będzie z tą tablicą za moment robić...
|
|
|
|
|
-
|
|
|
|
|
private AsyncStream() {
|
|
private AsyncStream() {
|
|
|
// utility class
|
|
// utility class
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Uwaga! Wszystkie metody zwracają bezużyteczne wyniki. W zasadzie Bóg jeden
|
|
|
|
|
- * wie po licho w ogóle implementujemy {@link InputStream}, bo i tak tego
|
|
|
|
|
- * nie można nigdzie do normalnych metod przekazać.
|
|
|
|
|
- *
|
|
|
|
|
- * read -> handle(IORequest)
|
|
|
|
|
- */
|
|
|
|
|
- public static abstract class InputDriver extends InputStream implements EventListener<IORequest> {
|
|
|
|
|
-
|
|
|
|
|
- public InputDriver() {
|
|
|
|
|
- // do nothing
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public abstract void handleEvent(IORequest event);
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public int read() throws IOException {
|
|
|
|
|
- handleEvent(IORequest.read());
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public int read(byte array[]) throws IOException {
|
|
|
|
|
- handleEvent(IORequest.read(array.length));
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public int read(byte array[], int offset, int length) throws IOException {
|
|
|
|
|
- handleEvent(IORequest.read(length));
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public long skip(long delta) throws IOException {
|
|
|
|
|
- handleEvent(IORequest.skip(delta));
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public int available() throws IOException {
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public void close() throws IOException {
|
|
|
|
|
- handleEvent(IORequest.close());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public synchronized void mark(int readlimit) {
|
|
|
|
|
- handleEvent(IORequest.mark(readlimit));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public synchronized void reset() throws IOException {
|
|
|
|
|
- handleEvent(IORequest.reset());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public boolean markSupported() {
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ public static OutputStream create(OutputStream ostream, String logger) {
|
|
|
|
|
+ return create(ostream, LoggerUtils.getLogger(logger));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static OutputStream create(OutputStream ostream, final AdvLogger logger) {
|
|
|
|
|
+ return create(ostream, new OutputListener(ostream) {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(IOEvent event) {
|
|
|
|
|
+ if(event instanceof IOEvent.Failure) {
|
|
|
|
|
+ logger.error( ((IOEvent.Failure)event).cause() );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static OutputStream create(OutputStream ostream, final EventListener<? super IOEvent> listener) {
|
|
|
|
|
+ return create(new OutputListener(ostream) {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(IOEvent event) {
|
|
|
|
|
+ listener.handleEvent(event);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static OutputStream create(OutputListener listener) {
|
|
|
|
|
+
|
|
|
|
|
+ final EventRouter router = EventRouterThread.newInstance("OutputStreamer", Integer.MAX_VALUE, Integer.MAX_VALUE);
|
|
|
|
|
+
|
|
|
|
|
+ router.addEventListener(IORequest.class, new OutputDevice(listener));
|
|
|
|
|
+
|
|
|
|
|
+ return new OutputDriver() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(IORequest event) {
|
|
|
|
|
+ router.handleEvent(event);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static InputStream create(final InputStream ostream, String logger) {
|
|
|
|
|
+ return create(ostream, LoggerUtils.getLogger(logger));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static InputStream create(final InputStream ostream, final AdvLogger logger) {
|
|
|
|
|
+ return create(ostream, new InputListener(ostream) {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(IOEvent event) {
|
|
|
|
|
+ if(event instanceof IOEvent.Failure) {
|
|
|
|
|
+ logger.error( ((IOEvent.Failure)event).cause() );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
|
+ public static InputStream create(final InputStream ostream, final EventListener<? super IOEvent> listener) {
|
|
|
|
|
+ return create(new InputListener(ostream) {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(IOEvent event) {
|
|
|
|
|
+ listener.handleEvent(event);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static InputStream create(InputListener listener) {
|
|
|
|
|
+
|
|
|
|
|
+ final EventRouter router = EventRouterThread.newInstance("OutputStreamer", Integer.MAX_VALUE, Integer.MAX_VALUE);
|
|
|
|
|
+
|
|
|
|
|
+ router.addEventListener(IORequest.class, new InputDevice(listener));
|
|
|
|
|
+
|
|
|
|
|
+ return new InputDriver() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void handleEvent(IORequest event) {
|
|
|
|
|
+ router.handleEvent(event);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
- * read -> stream.read -> handle(IOEvent)
|
|
|
|
|
|
|
+ * Transformacja: {@code read -> stream.read -> handle(IOEvent)}
|
|
|
*/
|
|
*/
|
|
|
public static abstract class InputListener extends InputStream implements EventListener<IOEvent> {
|
|
public static abstract class InputListener extends InputStream implements EventListener<IOEvent> {
|
|
|
|
|
|
|
@@ -237,17 +208,164 @@ public final class AsyncStream {
|
|
|
return istream.markSupported();
|
|
return istream.markSupported();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Transformacja: {@code read -> handle(IORequest)}
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * Uwaga! Klasy {@code InputStream} nie zaprojektowano w taki sposób, aby
|
|
|
|
|
+ * działała w tle. W efekcie poniższa klasa z semantycznego punktu widzenia
|
|
|
|
|
+ * całkowicie nie spełnia kontraktu. W zasadzie Bóg jeden wie po licho
|
|
|
|
|
+ * w ogóle implementujemy {@link InputStream}, bo i tak strach tę klasę do
|
|
|
|
|
+ * normalnych metod przekazać.
|
|
|
|
|
+ * </p>
|
|
|
|
|
+ * <ul>
|
|
|
|
|
+ * <li>metody zwracają bezużyteczne wyniki</li>
|
|
|
|
|
+ * <li>metody nie sygnalizują błędów wyjątkami</li>
|
|
|
|
|
+ * <li>błędy są sygnalizowane jako {@link IOEvent.Failure IOEvent.Failure}</li>
|
|
|
|
|
+ * </ul>
|
|
|
|
|
+ */
|
|
|
|
|
+ public static abstract class InputDriver extends InputStream implements EventListener<IORequest> {
|
|
|
|
|
|
|
|
|
|
+ public InputDriver() {
|
|
|
|
|
+ // do nothing
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public abstract void handleEvent(IORequest event);
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int read() {
|
|
|
|
|
+ handleEvent(IORequest.read());
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public int read(int size) {
|
|
|
|
|
+ handleEvent(IORequest.read(size));
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int read(byte array[]) {
|
|
|
|
|
+ handleEvent(IORequest.read(array.length));
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int read(byte array[], int offset, int length) {
|
|
|
|
|
+ handleEvent(IORequest.read(length));
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long skip(long delta) {
|
|
|
|
|
+ handleEvent(IORequest.skip(delta));
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int available() {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void close() {
|
|
|
|
|
+ handleEvent(IORequest.close());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public synchronized void mark(int readlimit) {
|
|
|
|
|
+ handleEvent(IORequest.mark(readlimit));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public synchronized void reset() {
|
|
|
|
|
+ handleEvent(IORequest.reset());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean markSupported() {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * write -> stream.write -> handle(IOEvent)
|
|
|
|
|
|
|
+ * Transformacja: {@code handle(IORequest) -> stream.read}
|
|
|
|
|
+ */
|
|
|
|
|
+ public static class InputDevice extends ReflectEventListener<IORequest> {
|
|
|
|
|
+
|
|
|
|
|
+ private final InputListener device;
|
|
|
|
|
+
|
|
|
|
|
+ public InputDevice(InputListener device) {
|
|
|
|
|
+ this.device = device;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.ReadByte event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.read();
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.ReadByteArray event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ byte[] target = new byte[event.count()];
|
|
|
|
|
+ device.read(target);
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.Skip event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.skip(event.delta());
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.Close event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.close();
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.Mark event) {
|
|
|
|
|
+ device.mark(event.limit());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.Reset event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.reset();
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IOEvent.Failure event) {
|
|
|
|
|
+ device.handleEvent(event);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Transformacja: {@code write -> stream.write -> handle(IOEvent)}
|
|
|
*/
|
|
*/
|
|
|
public static abstract class OutputListener extends OutputStream implements EventListener<IOEvent> {
|
|
public static abstract class OutputListener extends OutputStream implements EventListener<IOEvent> {
|
|
|
|
|
|
|
|
private final OutputStream ostream;
|
|
private final OutputStream ostream;
|
|
|
|
|
|
|
|
- public OutputListener(OutputStream istream) {
|
|
|
|
|
- this.ostream = istream;
|
|
|
|
|
|
|
+ public OutputListener(OutputStream ostream) {
|
|
|
|
|
+ this.ostream = ostream;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -308,5 +426,113 @@ public final class AsyncStream {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Transformacja: {@code write -> handle(IORequest)}
|
|
|
|
|
+ * <ul>
|
|
|
|
|
+ * <li>metody nie sygnalizują błędów wyjątkami</li>
|
|
|
|
|
+ * <li>błędy są sygnalizowane jako {@link IOEvent.Failure IOEvent.Failure}</li>
|
|
|
|
|
+ * </ul>
|
|
|
|
|
+ */
|
|
|
|
|
+ public static abstract class OutputDriver extends OutputStream implements EventListener<IORequest> {
|
|
|
|
|
+
|
|
|
|
|
+ public OutputDriver() {
|
|
|
|
|
+ // do nothing
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public abstract void handleEvent(IORequest event);
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(int value) {
|
|
|
|
|
+ handleEvent(IORequest.write(value));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(byte array[]) {
|
|
|
|
|
+ handleEvent(IORequest.write(array));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(byte array[], int offset, int length) {
|
|
|
|
|
+ handleEvent(IORequest.write(array, offset, length));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void flush() {
|
|
|
|
|
+ handleEvent(IORequest.flush());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void close() {
|
|
|
|
|
+ handleEvent(IORequest.close());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Transformacja: {@code handle(IORequest) -> stream.write}
|
|
|
|
|
+ */
|
|
|
|
|
+ public static class OutputDevice extends ReflectEventListener<IORequest> {
|
|
|
|
|
+
|
|
|
|
|
+ private final OutputListener device;
|
|
|
|
|
+
|
|
|
|
|
+ public OutputDevice(OutputListener ostream) {
|
|
|
|
|
+ this.device = ostream;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.WriteByte event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.write(event.data());
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.WriteByteArray event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.write(event.data());
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.Flush event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.flush();
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IORequest.Close event) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ device.close();
|
|
|
|
|
+ } catch(IOException cause) {
|
|
|
|
|
+ device.handleEvent(IOEvent.failure(cause));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Meta.EventHandler
|
|
|
|
|
+ void onEvent(IOEvent.Failure event) {
|
|
|
|
|
+ device.handleEvent(event);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static abstract class ErrorListener implements EventListener<IOEvent> {
|
|
|
|
|
+
|
|
|
|
|
+ public abstract void onError(IOException cause);
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public final void handleEvent(IOEvent event) {
|
|
|
|
|
+ if (event instanceof IOEvent.Failure) {
|
|
|
|
|
+ onError( ((IOEvent.Failure)event).cause() );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
}
|
|
}
|