Messing around with JavaNIO Channels and Locks.
authorgumartinm <gustavo@gumartinm.name>
Wed, 4 Apr 2012 07:42:26 +0000 (09:42 +0200)
committergumartinm <gustavo@gumartinm.name>
Wed, 4 Apr 2012 07:42:26 +0000 (09:42 +0200)
Trying to use JavaNIO in the JavaPOS keyboard driver.

Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/MyUncaughtExceptionHandler.java
Allgemeines/Threads/ThreadsOldWay/src/de/test/thread/threadoldway/ThreadTest.java
JavaPOS/KeyBoardDriver/src/main/java/de/javapos/example/hardware/KeyBoardDeviceLinux.java

index 63e56f4..d231e23 100644 (file)
@@ -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();
        }
 }
index 0824805..397def1 100644 (file)
@@ -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,
index 0aa3330..f1b2dee 100644 (file)
@@ -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();