From f6a1369fda49631f1e6d5dcd2a418434c26a0a4a Mon Sep 17 00:00:00 2001 From: gumartinm Date: Wed, 4 Apr 2012 09:42:26 +0200 Subject: [PATCH] Messing around with JavaNIO Channels and Locks. Trying to use JavaNIO in the JavaPOS keyboard driver. --- .../threadoldway/MyUncaughtExceptionHandler.java | 2 +- .../de/test/thread/threadoldway/ThreadTest.java | 2 +- .../example/hardware/KeyBoardDeviceLinux.java | 94 +++++++++++++++++----- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/MyUncaughtExceptionHandler.java b/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/MyUncaughtExceptionHandler.java index 63e56f4..d231e23 100644 --- a/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/MyUncaughtExceptionHandler.java +++ b/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/MyUncaughtExceptionHandler.java @@ -13,7 +13,7 @@ public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { - //System.out.println("MyUncaughtExceptionHandler " + t.getName() + " " + e); + System.out.println("MyUncaughtExceptionHandler " + t.getName() + " " + e); e.printStackTrace(); } } diff --git a/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/ThreadTest.java b/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/ThreadTest.java index 0824805..397def1 100644 --- a/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/ThreadTest.java +++ b/Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/ThreadTest.java @@ -30,7 +30,7 @@ public class ThreadTest implements Runnable { // IF THERE IS NO ONE, A DEFAULT EXCEPTION HANDLER IS RUN BY THE JVM. Typically it will be enough for your requirements. // //In my example I am in the first case where the handler is in the parent code. It is in the parent code but - //the code is executed by the sibling. What means thread1 will run the defined handler exception in thread main. + //the code is executed by the sibling. What means thread1 will run el manejador de excepcion que fue definido en el hilo main. Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); //So, in my example the ExceptionHandler is in the parent thread. When thread1 throws RuntimeException //the thread1 will search an exception handler finding this one in the parent. See the Thread constructor, diff --git a/JavaPOS/KeyBoardDriver/src/main/java/de/javapos/example/hardware/KeyBoardDeviceLinux.java b/JavaPOS/KeyBoardDriver/src/main/java/de/javapos/example/hardware/KeyBoardDeviceLinux.java index 0aa3330..f1b2dee 100644 --- a/JavaPOS/KeyBoardDriver/src/main/java/de/javapos/example/hardware/KeyBoardDeviceLinux.java +++ b/JavaPOS/KeyBoardDriver/src/main/java/de/javapos/example/hardware/KeyBoardDeviceLinux.java @@ -1,9 +1,13 @@ package de.javapos.example.hardware; -import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.lang.Thread.UncaughtExceptionHandler; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.Semaphore; import jpos.JposConst; @@ -19,10 +23,13 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { private Semaphore mutex = new Semaphore(1, true); //No me gusta nada esto, simplemente es para evitar mirar si thread es null la primera vez en el metodo enable... private Thread thread = new Thread ("KeyBoardDeviceLinux-Thread"); - private DataInputStream device; + private InputStream device; + private FileChannel fileChannel; private boolean isClaimed; private boolean autoDisable; + private boolean isEnabled; private JposEventListener eventListener; + private FileLock lock; @Override public boolean isOpened() { @@ -43,14 +50,35 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { @Override public void claim(int paramInt) throws JposException { - - + if (paramInt == -1) { + try { + this.lock = this.fileChannel.lock(); + } catch (IOException e) { + throw new JposException(JposConst.JPOS_E_CLAIMED, "Device not found.",e); + } + } + else { + long initTime = System.currentTimeMillis(); + do { + try { + this.lock = this.fileChannel.tryLock(); + } catch (IOException e) { + throw new JposException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e); + } + } while (((System.currentTimeMillis() - initTime) < paramInt) && (this.lock == null)); + if (this.lock == null) { + throw new JposException(JposConst.JPOS_E_TIMEOUT, "Timeout while trying to claim device."); + } + } } @Override public void release() throws JposException { - // TODO Auto-generated method stub - + try { + this.lock.release(); + } catch (IOException e) { + throw new JposException(JposConst.JPOSERR, "Device not found.",e); + } } @Override @@ -67,25 +95,38 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { */ @Override public void enable() throws JposException { + if (this.device == null) { throw new JposException(JposConst.JPOSERR, "There is not an assigned device", - new NullPointerException("The device field has null value")); + new NullPointerException("The device field has null value")); } - if (!this.thread.isAlive()) { - this.thread = new Thread (new HardwareLoop(this.device), "KeyBoardDeviceLinux-Thread"); - this.thread.start(); + if (this.isEnabled) { + throw new JposException(JposConst.JPOSERR, "The device was not disabled."); + } + else { + if (this.thread.isAlive()) { + throw new JposException(JposConst.JPOSERR, "The device was disabled but the hardware " + + "thread is still running. Is your CPU/CPUs overloaded?"); + } + else { + this.thread = new Thread (new HardwareLoop(this.device), "KeyBoardDeviceLinux-Thread"); + this.thread.setUncaughtExceptionHandler(new DriverHWUncaughtExceptionHandler()); + this.thread.start(); + this.isEnabled = true; + } } } @Override public void disable() throws JposException { this.thread.interrupt(); + this.isEnabled = false; } @Override public boolean isEnabled() { - return this.thread.isAlive(); + return this.isEnabled; } @Override @@ -147,7 +188,8 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { @Override public void device(String device) throws JposException { try { - this.device = new DataInputStream(new FileInputStream(device)); + this.fileChannel = new FileInputStream(device).getChannel(); + this.device = Channels.newInputStream(this.fileChannel); } catch (FileNotFoundException e) { throw new JposException(JposConst.JPOS_E_NOHARDWARE, "Device not found.",e); } @@ -155,9 +197,9 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { @ThreadSafe private class HardwareLoop implements Runnable { - private final DataInputStream device; + private final InputStream device; - private HardwareLoop (DataInputStream device) { + private HardwareLoop (InputStream device) { this.device = device; } @@ -166,7 +208,7 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { //Para 32 bits //En 64 bits me parece que struct timeval tiene un valor diferente. Averigüar valor de //struct timeval en 64 bits :( - byte []buffer = new byte[16]; + byte []buffer = new byte[32]; short code = 0; short type = 0; int value = 0; @@ -178,7 +220,7 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { try { while (!Thread.currentThread().isInterrupted()) { //using command: evtest /dev/input/event4 - this.device.readFully(buffer); + this.device.read(buffer); ch1 = buffer[11]; ch2 = buffer[10]; code = (short)((ch1 << 8) + (ch2 << 0)); @@ -199,33 +241,47 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { System.out.println("type: " + type + " code: " + code + " value: " + value); } } + System.out.println("KeyBoardDeviceLinux: Hardware's thread finished."); + //logger.debug("KeyBoardDeviceLinux: Hardware's thread finished."); } catch (IOException e) { - logger.error("KeyBoardDeviceLinux:", e); + //logger.error("KeyBoardDeviceLinux:", e); + e.printStackTrace(); } finally { try { this.device.close(); //SI EL HILO MUERE ¿DEBERÍA DEJAR EL ESTADO DEL DISPOSITIVO LOGICO JAVAPOS //EN UN MODO CONSISTENTE? } catch (IOException e1) { - logger.warn("KeyBoardDeviceLinux:", e1); + e1.printStackTrace(); + //logger.warn("KeyBoardDeviceLinux:", e1); } } } } + private class DriverHWUncaughtExceptionHandler implements UncaughtExceptionHandler { + + @Override + public void uncaughtException(Thread t, Throwable e) { + System.out.println("Thread " + t.getName() + " " + e); + //logger.warn("Exception not expected while running thread " + t.getName() , e); + e.printStackTrace(); + } + } public static void main(String[] param) throws InterruptedException { //Because I do not have a POS I am going to use the keyboard of my computer. //see: /dev/input/by-path/ //And the Keyborad scancode is for USB devices. - String device ="/dev/input/event5"; + String device ="/dev/input/event4"; KeyBoardDeviceLinux driver = new KeyBoardDeviceLinux(); System.out.println("Main test of KeyBoardDeviceLinux class"); try { driver.device(device); + driver.claim(); driver.enable(); Thread.sleep(5000); driver.disable(); -- 2.1.4