import de.javapos.example.queue.JposEventQueue;
public class ThreadFireEvent extends Thread {
+ private boolean isDataEventEnabled = true;
private final JposEventQueue jposEventQueue;
- private boolean isDataEventEnabled;
private final EventCallbacks eventCallbacks;
+ private final ThreadGate freezeEventsGate = new ThreadGate();
public ThreadFireEvent (JposEventQueue jposEventQueue,
- boolean isDataEventEnabled, EventCallbacks eventCallbacks) {
+ boolean isDataEventEnabled, EventCallbacks eventCallbacks) {
this.jposEventQueue = jposEventQueue;
- this.isDataEventEnabled = isDataEventEnabled;
this.eventCallbacks = eventCallbacks;
}
while (true) {
if (this.jposEventQueue.getNumberOfEvents() != 0) {
+
+ try {
+ this.freezeEventsGate.await();
+ } catch (InterruptedException e1) {
+ //We are implementing the interruption policy in this class
+ //for this thread. So, this is permitted.
+ //End of thread.
+ break;
+ }
+
//PROBLEMA: si DataEventEnabled es false y lo unico que hay en la cola son eventos de datos
//me meto en un bucle que va a dejar la CPU frita... :/
if (this.isDataEventEnabled) {
try {
jposEvent = this.jposEventQueue.getEvent();
} catch (InterruptedException e) {
- //restore interrupt status.
- Thread.currentThread().interrupt();
+ //We are implementing the interruption policy in this class
+ //for this thread. So, this is permitted.
//End of thread.
break;
}
}
}
- //TODO: Bloquearme hasta que freezeEvent sea false
if (jposEvent instanceof DataEvent) {
this.eventCallbacks.fireDataEvent((DataEvent)jposEvent);
}
}
}
+
+ public void setFreezeEvents (boolean freezeEvents) {
+ if (freezeEvents) {
+ this.freezeEventsGate.close();
+ }
+ else {
+ this.freezeEventsGate.open();
+ }
+ }
+
+ public void setDataEventEnabled (boolean dataEventEnabled) {
+ this.isDataEventEnabled = dataEventEnabled;
+ }
}
--- /dev/null
+package de.javapos.example.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+
+/*
+ * Copyright (c) 2005 Brian Goetz
+ * Released under the Creative Commons Attribution License
+ * (http://creativecommons.org/licenses/by/2.5)
+ * Official home: http://www.jcip.net
+ */
+
+/**
+ * GuardedBy
+ *
+ * The field or method to which this annotation is applied can only be accessed
+ * when holding a particular lock, which may be a built-in (synchronization)
+ * lock, or may be an explicit java.util.concurrent.Lock.
+ *
+ * The argument determines which lock guards the annotated field or method: this :
+ * The string literal "this" means that this field is guarded by the class in
+ * which it is defined. class-name.this : For inner classes, it may be necessary
+ * to disambiguate 'this'; the class-name.this designation allows you to specify
+ * which 'this' reference is intended itself : For reference fields only; the
+ * object to which the field refers. field-name : The lock object is referenced
+ * by the (instance or static) field specified by field-name.
+ * class-name.field-name : The lock object is reference by the static field
+ * specified by class-name.field-name. method-name() : The lock object is
+ * returned by calling the named nil-ary method. class-name.class : The Class
+ * object for the specified class should be used as the lock object.
+ */
+@Target( { ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.CLASS)
+public @interface GuardedBy {
+ String value();
+}
\ No newline at end of file
private FileChannel fileChannelLock;
private DataInputStream device;
private boolean isClaimed;
+ private boolean isEnabled;
//Usando volatile porque cumplo las condiciones de uso. Ver Java Concurrency in Practice PAG????
private volatile boolean autoDisable;
private JposEventListener eventListener;
@Override
public void claim(int time) throws JposException {
FileLock lock = null;
+ FileChannel fileChannelLock = null;
if (this.isClaimed) {
return;
}
try {
- this.fileChannelLock = new FileOutputStream(javaposKeyBoardLock).getChannel();
+ fileChannelLock = new FileOutputStream(javaposKeyBoardLock).getChannel();
} catch (FileNotFoundException e) {
throw new JposException(JposConst.JPOS_E_NOTCLAIMED, "File not found.",e);
}
if (time == -1) {
try {
//This method is not aware interrupt. :(
- lock = this.fileChannelLock.lock();
+ lock = fileChannelLock.lock();
//I do not like catching RunTimeExceptions but I have no choice...
} catch (OverlappingFileLockException e) {
logger.warn("Concurrent access in claim method not supported without synchronization or you have" +
"more than one instances of the KeyBoardDeviceLinux class", e);
+ try {
+ fileChannelLock.close();
+ } catch (IOException e1) {
+ //The first exception is more important.
+ logger.warn("Error while closing the file lock", e1);
+ }
} catch (IOException e) {
+ try {
+ fileChannelLock.close();
+ } catch (IOException e1) {
+ //The first exception is more important.
+ logger.warn("Error while closing the file lock", e1);
+ }
throw new JposException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e);
}
}
//Espera activa. ¿Alguna idea de cómo hacer esto sin espera activa? :(
while((System.nanoTime() <= lastTime) && (lock == null)) {
try {
- if ((lock = this.fileChannelLock.tryLock()) != null) {
+ if ((lock = fileChannelLock.tryLock()) != null) {
break;
}
+ this.wait(250);
//I do not like catching RunTimeExceptions but I have no choice...
} catch (OverlappingFileLockException e) {
logger.warn("Concurrent access in claim method not supported without synchronization or you have" +
"more than one instances of the KeyBoardDeviceLinux class", e);
+ try {
+ fileChannelLock.close();
+ } catch (IOException e1) {
+ //The first exception is more important.
+ logger.warn("Error while closing the file lock", e1);
+ }
} catch (IOException e) {
- throw new JposException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e);
- }
- try {
- this.wait(250);
+ try {
+ fileChannelLock.close();
+ } catch (IOException e1) {
+ //The first exception is more important.
+ logger.warn("Error while closing the file lock", e1);
+ }
+ throw new JposException(JposConst.JPOS_E_CLAIMED, "Error while trying to claim device.",e);
} catch(InterruptedException e) {
- //restore interrupt status.
+ try {
+ fileChannelLock.close();
+ } catch (IOException e1) {
+ //The first exception is more important.
+ logger.warn("Error while closing the file lock", e1);
+ }
+ //restore interrupt status.
Thread.currentThread().interrupt();
- }
+ throw new JposException(JposConst.JPOSERR, "Interrupt exception detected.", e);
+ }
}
if (lock == null) {
- throw new JposException(JposConst.JPOS_E_TIMEOUT, "Timeout while trying to claim device.", null);
+ try {
+ fileChannelLock.close();
+ } catch (IOException e) {
+ //The timeout exception is more important.
+ logger.warn("Error while closing the file lock", e);
+ }
+ throw new JposException(JposConst.JPOS_E_TIMEOUT, "Timeout while trying to claim device.");
}
}
if (lock != null) {
- //Just when concurrent access without synchronization (this method is not tread-safe) you could see
- //null value. claim does not support concurrent access in itself anyway I take counter measures in case
+ //Just when concurrent access without synchronization (this method is not tread-safe) or having more
+ //than one instances of this class you could see null value.
+ //claim does not support concurrent access in itself. Anyway I take counter measures in case
//of someone forgets it.
this.lock = lock;
+ this.fileChannelLock = fileChannelLock;
this.isClaimed = true;
}
}
*/
@Override
public void enable() throws JposException {
+ if (this.isEnabled) {
+ return;
+ }
if (this.deviceName == null) {
throw new JposException(JposConst.JPOSERR, "There is not an assigned device",
new NullPointerException("The deviceName field has null value"));
//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 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()) {
- throw new JposException(JposConst.JPOSERR, "The device was not disabled.", null);
- }
- else {
+ if (!this.thread.isAlive()) {
try {
this.device = new DataInputStream(Channels.newInputStream(new FileInputStream(this.deviceName).getChannel()));
} catch (FileNotFoundException e) {
this.thread = new Thread (task, "KeyBoardDeviceLinux-Thread");
this.thread.setUncaughtExceptionHandler(new DriverHWUncaughtExceptionHandler());
this.thread.start();
+ this.isEnabled = true;
}
}
@Override
public void disable() throws JposException {
+
+ if (!this.isEnabled) {
+ return;
+ }
+
//This method releases the Java NIO channel. It is thread safety. :) see: Interruptible
this.thread.interrupt();
try {
this.thread.join();
} 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();
+ Thread.currentThread().interrupt();
+ throw new JposException(JposConst.JPOSERR, "Interrupt exception detected.", e);
}
+
+ this.isEnabled = false;
}
@Override
public boolean isEnabled() {
- return this.thread.isAlive();
+ return this.isEnabled;
}
@Override
value = ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
if (type == KeyBoardDeviceLinux.EV_KEY) {
- eventListener.inputAvailable(code);
+ //Problema aqui con eventListener y que vea != null y luego justo dentro del if
+ //otro hilo me lo quite...
+ if (eventListener != null) {
+ eventListener.inputAvailable(code);
+ }
+
logger.debug("Captured key " + "type: " + type + " code: " + code + " value: " + value);
if (autoDisable) {
break;
//logger.debug or logger.error if it was an error I am not going to log it... :/
logger.debug("Finished KeyBoardDeviceLinux Thread", e);
} finally {
- //This method releases the Java NIO channels. It is thread safety :) see: Interruptible
+ //This method releases the Java NIO channels (this.device). It is thread safety :) see: Interruptible
this.thread.interrupt();
+ this.device = null; //¿Realmente esto es necesario? (no lo creo :/ )
//SI EL HILO MUERE ¿ESTOY DEJANDO EL ESTADO DEL DISPOSITIVO LOGICO JAVAPOS
//EN UN MODO CONSISTENTE?
//liberar el LOCK SI EL HILO MUERE DE FORMA INESPERADA???? NO, JavaPOS no dice nada.