From: gumartinm Date: Wed, 11 Apr 2012 05:50:08 +0000 (+0200) Subject: JavaPOS keyboard driver. Some improvements. X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=bb1ff7d60f14aa017bab5ed2e64e4a185ef539ba;p=JavaForFun JavaPOS keyboard driver. Some improvements. 1. claim 2. release 3. If I want to reach the second level of Exception Safety, it must be done in the upper layer of my JavaPOS driver using try/finally not in the hardware layer. 4. Spanish comments that must be removed when the driver is finished (I am still working on it) --- 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 d8b0c50..a30456a 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 @@ -75,24 +75,37 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { public void claim(int time) throws JposException { FileLock lock = null; - if (this.fileChannelLock == null) { - try { - //Problema tocho tocho tocho ¿cuando cierro este archivo/canal? ¿¿¿la fastidié??? :( Si Java tuviera destructores... :( - //Mierda mierda si no lo cierro nunca me voy a quedar sin file descriptors en el sistema operativo LOL - this.fileChannelLock = new FileOutputStream(javaposKeyBoardLock).getChannel(); - } catch (FileNotFoundException e) { - this.throwException(JposConst.JPOS_E_NOTCLAIMED, "File not found.",e); - } + if (this.isClaimed) { + return; } - + + try { + this.fileChannelLock = new FileOutputStream(javaposKeyBoardLock).getChannel(); + } catch (FileNotFoundException e) { + throw new JposException(JposConst.JPOS_E_NOTCLAIMED, "File not found.",e); + } + if (time == -1) { try { lock = this.fileChannelLock.lock(); //I do not like catching RunTimeExceptions but I have no choice... } catch (OverlappingFileLockException e) { - this.throwException(JposConst.JPOS_E_CLAIMED, "Some thread from this process already claimed this device.",e); + //¿esta cosa se entera si hay otra instancia de esta clase manejada desde otro thread? + //otro open del mismo archivo devuelve un file descriptor distinto. ¿Cómo Java se enteraría + //de que otro hilo que creó otra instancia de esta clase KeyBoardDeviceLinux está intentando bloquear + //el mismo archivo? + //WOW Java sí se entera si creo dos instancias de esta clase desde varios hilos y ambos + //intentan bloquear el mismo archivo incluso aunque los file descriptor sean distintos. + //Usa un objecto llamado FileKey.java que contiene entre otras cosas 2 campos: st_dev y st_ino + //esos campos los consigue con FileKey.init que llama a fstat64!!!! WOWOWOWOWOW + //así incluso si tenemos 2 instancias del objecto KeyBoardDeviceLinux usadas por 2 hilos distintos podemos + //saber si el hilo fue bloqueado ya. + //CON ESTA IMPLEMENTACION SOLO SALTARIA OverlappingFileLockException SI OTRO HILO CREA UNA NUEVA + //INSTANCIA DE ESTA CLASE E INTENTA HACER UN claim. CON HILOS USANDO LA MISMA INSTANCIA DE LA CLASE + //DEBERIAN VER LA PROPIEDAD isClaimed A TRUE Y POR TANTO NUNCA LLEGARIAN AQUI. + throw new JposException(JposConst.JPOS_E_CLAIMED, "Some thread from this process already claimed this device.",e); } catch (IOException e) { - this.throwException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e); + throw new JposException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e); } } else { @@ -105,9 +118,9 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { } //I do not like catching RunTimeExceptions but I have no choice... } catch (OverlappingFileLockException e) { - this.throwException(JposConst.JPOS_E_CLAIMED, "Some thread from this process already claimed this device.",e); + throw new JposException(JposConst.JPOS_E_CLAIMED, "Some thread from this process already claimed this device.",e); } catch (IOException e) { - this.throwException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e); + throw new JposException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e); } try { this.wait(250); @@ -118,7 +131,7 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { } if (lock == null) { - this.throwException(JposConst.JPOS_E_TIMEOUT, "Timeout while trying to claim device.", null); + throw new JposException(JposConst.JPOS_E_TIMEOUT, "Timeout while trying to claim device.", null); } else { this.lock = lock; @@ -129,17 +142,28 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { @Override public void release() throws JposException { this.isClaimed = false; + if (this.lock != null) { try { + //SI LLAMO A ESTO PERO FALLO AL INTENTAR LOCK NO CIERRO NI LIBERO EL LOCK REALIZADO + //DESDE OTRO HILO :) this.lock.release(); } catch (IOException e) { - this.throwException(JposConst.JPOSERR, "Error when releasing the keyboard file lock",e); + //NO PUEDO LLAMAR A ESTO AQUI PORQUE ME METO EN UN BUCLE INFERNAL + throw new JposException(JposConst.JPOSERR, "Error when releasing the keyboard file lock",e); } } - try { - this.fileChannelLock.close(); - } catch (IOException e) { - this.throwException(JposConst.JPOSERR, "Error when closing the keyboard file lock", e); + + if (this.fileChannelLock != null) { + try { + //NO HAY PROBLEMA EN LLAMAR A ESTO, CADA HILO CIERRA SU fd. CADA HILO TIENE + //SU PROPIO file descriptor QUE ES LO QUE CIERRA :) + this.fileChannelLock.close(); + this.fileChannelLock = null; + } catch (IOException e) { + //NO PUEDO LLAMAR A ESTO AQUI PORQUE ME METO EN UN BUCLE INFERNAL + throw new JposException(JposConst.JPOSERR, "Error when closing the keyboard file lock", e); + } } } @@ -158,7 +182,7 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { @Override public void enable() throws JposException { if (this.deviceName == null) { - this.throwException(JposConst.JPOSERR, "There is not an assigned device", + throw new JposException(JposConst.JPOSERR, "There is not an assigned device", new NullPointerException("The deviceName field has null value")); } @@ -182,16 +206,16 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { //que tarde en morir el hilo. //PROBLEMA OTRA VEZ, ¿y si el hilo murio por alguna cosa inesperada como por ejemplo que el archivo del //dispositivo del SO se borro o cualquier otra cosa? Aqui veria el hilo muerto pero en realidad el - //dispositivo no fue deshabilitado si no que el hilo murio de forma inesperada... Si soluciono este - //ultimo escollo sí me podre basar en si el hilo está o no muerto. + //dispositivo no fue deshabilitado si no que el hilo murio de forma inesperada Y NO SE CERRO this.device!!!... + //Si soluciono este ultimo escollo sí me podre basar en si el hilo está o no muerto. if (this.thread.isAlive()) { - this.throwException(JposConst.JPOSERR, "The device was not disabled.", null); + throw new JposException(JposConst.JPOSERR, "The device was not disabled.", null); } else { try { this.device = new DataInputStream(Channels.newInputStream(new FileInputStream(this.deviceName).getChannel())); } catch (FileNotFoundException e) { - this.throwException(JposConst.JPOS_E_NOHARDWARE, "Device not found.",e); + throw new JposException(JposConst.JPOS_E_NOHARDWARE, "Device not found.",e); } this.thread = new Thread (new HardwareLoop(this.device, this.eventListener), "KeyBoardDeviceLinux-Thread"); this.thread.setUncaughtExceptionHandler(new DriverHWUncaughtExceptionHandler()); @@ -207,9 +231,14 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { this.device.close(); } catch (InterruptedException e) { //restore interrupt status. + //QUE PASA SIN LLAMAN A INTERRUPT EN JOIN Y EL HILO NUNCA MURIERA + //TAL Y COMO ESTA HECHO EL HILO NO TARDARA MUCHO EN MORIR (espero) ASI QUE + //AUNQUE ALGO ME INTERRUMPA NO DEBERIA PASAR GRAN COSA, LO UNICO QUE SI OTRO HILO + //JUSTO AQUI INTENTA HACER ENABLE PUEDE QUE VEA EL HILO TODAVIA VIVO AUNQUE YA SE HABIA + //PASADO POR EL DISABLE, PERO TAN POCO ES UN GRAN PROBLEMA ESO. LUEGO PARA MÍ QUE ESTO ESTA OK!!! :) Thread.currentThread().interrupt(); } catch (IOException e) { - this.throwException(JposConst.JPOSERR, "Error when closing the keyboard device file", e); + throw new JposException(JposConst.JPOSERR, "Error when closing the keyboard device file", e); } } @@ -272,31 +301,6 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { this.deviceName = device; } - /** - * Trying to reach the second level :/ - * Para mi que este objetivo no debo alcanzarlo aqui si no en el codigo superior en MyPOSKeyboard... :( - */ - private void exceptionSafety() { - try { - this.release(); - } catch (JposException e) { - // Log this exception. The original exception (if there is one) is more - // important and will be thrown to the caller. - logger.warn("Error consuming content after an exception.", e); - } - try { - this.disable(); - } catch (JposException e) { - // Log this exception. The original exception (if there is one) is more - // important and will be thrown to the caller. - logger.warn("Error consuming content after an exception.", e); - } - } - - private void throwException(int jposConst, String message, Exception exception) throws JposException { - this.exceptionSafety(); - throw new JposException (jposConst, message, exception); - } @ThreadSafe private class HardwareLoop implements Runnable { @@ -356,7 +360,8 @@ public class KeyBoardDeviceLinux implements BaseKeyBoardDriver { logger.debug("Captured key " + "type: " + type + " code: " + code + " value: " + value); if (KeyBoardDeviceLinux.this.autoDisable) { - Thread.currentThread().interrupt(); + //CERRAR this.device.close(); NO SE COMO HACER ESTO CORRECTAMENTE :( + break; } } }