Search code examples
javamultithreadingpolling

How to check smartcard presence by polling


I need to check the presence of a smartcard in my Java application to generate something like an "event" on smartcard removal.

I have a simple method to test it:

public boolean isCardIn(){};

What is the best way to poll this? In this case, should I use a java.utils.Timer.Timer() or an ExecutorService()?


This my current implementation:

To start polling

checkTimer.schedule(new CheckCard(), delay,delay);

And this is the timer's execution:

private class CheckCard extends TimerTask{   

    @Override
    public void run() {
        try{
            if(!SmartcardApi.isCardIn(slot)){
                 // fire event
            }
        }catch(Exception e){
        }
    }

}

Solution

  • I'd take a look on StackOverflow some more because I think your question's been answered: Java Timer vs ExecutorService?

    I think generally, it's better to use newer API, which in this case is the ExecutorService. Here's how I'd do it:

    Main method

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
        SmartCardApi smartCardApi = new SmartCardApi();
    
        // Polling job.
        Runnable job = new Runnable() {
            @Override
            public void run() {
                System.out.println("Is card in slot? " + smartCardApi.isCardInSlot());
            }
        };
        
        // Schedule the check every second.
        scheduledExecutor.scheduleAtFixedRate(job, 1000, 1000, TimeUnit.MILLISECONDS);
        
        // After 3.5 seconds, insert the card using the API.
        Thread.sleep(3500);
        smartCardApi.insert(1);
        
        // After 4 seconds, eject the card using the API.
        Thread.sleep(4000);
        smartCardApi.eject();
    
        // Shutdown polling job.
        scheduledExecutor.shutdown();
        
        // Verify card status.
        System.out.println("Program is exiting. Is card still in slot? " + smartCardApi.isCardInSlot());
    }
    

    SmartCardApi

    package test;
    
    import java.util.concurrent.atomic.AtomicBoolean;
    
    public class SmartCardApi {
        private AtomicBoolean inSlot = new AtomicBoolean(false);
        
        public boolean isCardInSlot() {
            return inSlot.get();
        }
        
        public void insert(int slot) {
            System.out.println("Inserted into " + slot);
            inSlot.set(true);
        }
    
        public void eject() {
            System.out.println("Ejected card.");
            inSlot.set(false);
        }
    }
    

    Program Output

    Is card in slot? false
    Is card in slot? false
    Is card in slot? false
    Inserted into 1
    Is card in slot? true
    Is card in slot? true
    Is card in slot? true
    Is card in slot? true
    Ejected card.
    Program is exiting. Is card still in slot? false
    

    In this case, I'm using a simple Runnable which could call another object in order to fire its event. You could also use a FutureTask instead of this Runnable, but that's just based on your preference for how you want this event to fired..