I have a login form that extends JDialog, the user can login via card swipe or by typing in a username and password.
I created a Runnable
daemon that communicates to a magnetic stripe reader, when started it will request a card swipe and it will wait until a card is swiped. If the application needs to cancel the request to do something else then it will produce an event that this thread will catch thus cancelling the request for waiting for a card swipe.
When the user swipes the card, the application will read the track for the user ID and validates it, if the authentication is successful, a stop command would be sent to the card swipe daemon and stops the thread.
When the user enters a username and password, the swing package would access a thread (AWT-EventQueue-0) that responds to the click event of the login button and proceeds to evaluate the login credentials.
My problem is whenever the application is on this AWT-EventQueue-0 thread, sending a stop event to the card swipe daemon would not work and the daemon would stay on the thread stack.
EDIT 1: The stop command works perfectly fine on the card swipe login. It ends the card swipe thread gracefully. On this scenario, the current thread scope is on the CardSwipeThread.
The problem happens on the manual login, when the user clicks the login button, the current scoped thread would be the AWT-EventQueue-0 or Event Dispatch Thread. Updating the volatile boolean of the CardSwipeThread to false does not stop it from running.
EDIT 2: The only time the reader would communicate with the application is when a card is swiped, and the problem happens on the manual login which doesn't require a swipe. So there are no issues with the CardSwipeThread not ending properly because of a blocked IO operation. Turns out there's one hiding behind the bushes.
This is a part of my code:
LoginDialog.java
public class LoginDialog extends JDialog implements ActionListener, WindowListener
{
public LoginDialog()
{
super();
// ..More code that instantiates the objects of this JDialog.
SwipeReader.getInstance().enable(true);
}
class SymAction implements java.awt.event.ActionListener
{
public void actionPerformed(java.awt.event.ActionEvent event)
{
Object object = event.getSource();
if (object == logonButton)
{
logonButton_actionPerformed(event);
}
// ..More conditions for other objects.
}
}
// The keyboard login method, does not terminate the card swipe daemon thread.
void logonButton_actionPerformed(java.awt.event.ActionEvent event)
{
try
{
// ..More code that will evaluate login information.
if (authenticate == -1)
{
// Notify for failed login.
}
else if (authenticate == 0)
{
SwipeReader.getInstance().enable(false);
}
}
catch (Exception e)
{
// Error logger.
}
}
// The card swipe listener used for card login.
public void deviceDataReceived(Object object)
{
try
{
// ..More code that will evaluate login information.
if (authenticate == -1)
{
// Notify for failed login.
}
if (authenticate == 0)
{
SwipeReader.getInstance().enable(false);
}
}
catch (Exception e)
{
// Error logger.
}
}
}
SwipeReader.java
public class SwipeReader
{
// This is a singleton class that creates the thread for the daemon.
CardSwipeDaemon cardSwipeDaemon;
Thread cardSwipeThread;
SwipeReader instance;
private SwipeReader() {}
public static SwipeReader getInstance()
{
if (instance == null) { instance = new SwipeReader(); }
return instance;
}
public void enable (boolean isEnabled)
{
if (isEnabled)
{
cardSwipeDaemon = new CardSwipeDaemon();
cardSwipeThread = new Thread(cardSwipeDaemon, "CardSwipeThread");
cardSwipeThread.start();
}
else
{
cardSwipeDaemon.stop();
cardSwipeThread = null;
}
}
}
CardSwipeDaemon.java
public class CardSwipeDaemon implements Runnable
{
CardSwipeDaemon instance;
private static volatile boolean listenforswipe = true;
public CardSwipeDaemon() {}
public static synchronized CardSwipeDaemon getInstance()
{
if (instance == null) { instance = new CardSwipeDaemon(); }
return instance;
}
public run()
{
listenforswipe = true;
while (listenforswipe)
{
// Code for reading the magnetic stripe data.
}
}
public void stop()
{
listenforswipe = false;
}
}