1 /*
   2  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.smartcardio;
  27 
  28 import java.util.*;
  29 
  30 /**
  31  * The set of terminals supported by a TerminalFactory.
  32  * This class allows applications to enumerate the available CardTerminals,
  33  * obtain a specific CardTerminal, or wait for the insertion or removal of
  34  * cards.
  35  *
  36  * <p>This class is multi-threading safe and can be used by multiple
  37  * threads concurrently. However, this object keeps track of the card
  38  * presence state of each of its terminals. Multiple objects should be used
  39  * if independent calls to {@linkplain #waitForChange} are required.
  40  *
  41  * <p>Applications can obtain instances of this class by calling
  42  * {@linkplain TerminalFactory#terminals}.
  43  *
  44  * @see TerminalFactory
  45  * @see CardTerminal
  46  *
  47  * @since   1.6
  48  * @author  Andreas Sterbenz
  49  * @author  JSR 268 Expert Group
  50  */
  51 public abstract class CardTerminals {
  52 
  53     /**
  54      * Constructs a new CardTerminals object.
  55      *
  56      * <p>This constructor is called by subclasses only. Application should
  57      * call {@linkplain TerminalFactory#terminals}
  58      * to obtain a CardTerminals object.
  59      */
  60     protected CardTerminals() {
  61         // empty
  62     }
  63 
  64     /**
  65      * Returns an unmodifiable list of all available terminals.
  66      *
  67      * @return an unmodifiable list of all available terminals.
  68      *
  69      * @throws CardException if the card operation failed
  70      */
  71     public List<CardTerminal> list() throws CardException {
  72          return list(State.ALL);
  73     }
  74 
  75     /**
  76      * Returns an unmodifiable list of all terminals matching the specified
  77      * state.
  78      *
  79      * <p>If state is {@link State#ALL State.ALL}, this method returns
  80      * all CardTerminals encapsulated by this object.
  81      * If state is {@link State#CARD_PRESENT State.CARD_PRESENT} or
  82      * {@link State#CARD_ABSENT State.CARD_ABSENT}, it returns all
  83      * CardTerminals where a card is currently present or absent, respectively.
  84      *
  85      * <p>If state is {@link State#CARD_INSERTION State.CARD_INSERTION} or
  86      * {@link State#CARD_REMOVAL State.CARD_REMOVAL}, it returns all
  87      * CardTerminals for which an insertion (or removal, respectively)
  88      * was detected during the last call to {@linkplain #waitForChange}.
  89      * If <code>waitForChange()</code> has not been called on this object,
  90      * <code>CARD_INSERTION</code> is equivalent to <code>CARD_PRESENT</code>
  91      * and <code>CARD_REMOVAL</code> is equivalent to <code>CARD_ABSENT</code>.
  92      * For an example of the use of <code>CARD_INSERTION</code>,
  93      * see {@link #waitForChange}.
  94      *
  95      * @param state the State
  96      * @return an unmodifiable list of all terminals matching the specified
  97      *   attribute.
  98      *
  99      * @throws NullPointerException if attr is null
 100      * @throws CardException if the card operation failed
 101      */
 102     public abstract List<CardTerminal> list(State state) throws CardException;
 103 
 104     /**
 105      * Returns the terminal with the specified name or null if no such
 106      * terminal exists.
 107      *
 108      * @param name the terminal name
 109      * @return the terminal with the specified name or null if no such
 110      * terminal exists.
 111      *
 112      * @throws NullPointerException if name is null
 113      */
 114     public CardTerminal getTerminal(String name) {
 115         if (name == null) {
 116             throw new NullPointerException();
 117         }
 118         try {
 119             for (CardTerminal terminal : list()) {
 120                 if (terminal.getName().equals(name)) {
 121                     return terminal;
 122                 }
 123             }
 124             return null;
 125         } catch (CardException e) {
 126             return null;
 127         }
 128     }
 129 
 130     /**
 131      * Waits for card insertion or removal in any of the terminals of this
 132      * object.
 133      *
 134      * <p>This call is equivalent to calling
 135      * {@linkplain #waitForChange(long) waitForChange(0)}.
 136      *
 137      * @throws IllegalStateException if this <code>CardTerminals</code>
 138      *   object does not contain any terminals
 139      * @throws CardException if the card operation failed
 140      */
 141     public void waitForChange() throws CardException {
 142         waitForChange(0);
 143     }
 144 
 145     /**
 146      * Waits for card insertion or removal in any of the terminals of this
 147      * object or until the timeout expires.
 148      *
 149      * <p>This method examines each CardTerminal of this object.
 150      * If a card was inserted into or removed from a CardTerminal since the
 151      * previous call to <code>waitForChange()</code>, it returns
 152      * immediately.
 153      * Otherwise, or if this is the first call to <code>waitForChange()</code>
 154      * on this object, it blocks until a card is inserted into or removed from
 155      * a CardTerminal.
 156      *
 157      * <p>If <code>timeout</code> is greater than 0, the method returns after
 158      * <code>timeout</code> milliseconds even if there is no change in state.
 159      * In that case, this method returns <code>false</code>; otherwise it
 160      * returns <code>true</code>.
 161      *
 162      * <p>This method is often used in a loop in combination with
 163      * {@link #list(CardTerminals.State) list(State.CARD_INSERTION)},
 164      * for example:
 165      * <pre>
 166      *  TerminalFactory factory = ...;
 167      *  CardTerminals terminals = factory.terminals();
 168      *  while (true) {
 169      *      for (CardTerminal terminal : terminals.list(CARD_INSERTION)) {
 170      *          // examine Card in terminal, return if it matches
 171      *      }
 172      *      terminals.waitForChange();
 173      *  }</pre>
 174      *
 175      * @param timeout if positive, block for up to <code>timeout</code>
 176      *   milliseconds; if zero, block indefinitely; must not be negative
 177      * @return false if the method returns due to an expired timeout,
 178      *   true otherwise.
 179      *
 180      * @throws IllegalStateException if this <code>CardTerminals</code>
 181      *   object does not contain any terminals
 182      * @throws IllegalArgumentException if timeout is negative
 183      * @throws CardException if the card operation failed
 184      */
 185     public abstract boolean waitForChange(long timeout) throws CardException;
 186 
 187     /**
 188      * Enumeration of attributes of a CardTerminal.
 189      * It is used as a parameter to the {@linkplain CardTerminals#list} method.
 190      *
 191      * @since 1.6
 192      */
 193     public static enum State {
 194         /**
 195          * All CardTerminals.
 196          */
 197         ALL,
 198         /**
 199          * CardTerminals in which a card is present.
 200          */
 201         CARD_PRESENT,
 202         /**
 203          * CardTerminals in which a card is not present.
 204          */
 205         CARD_ABSENT,
 206         /**
 207          * CardTerminals for which a card insertion was detected during the
 208          * latest call to {@linkplain State#waitForChange waitForChange()}
 209          * call.
 210          */
 211         CARD_INSERTION,
 212         /**
 213          * CardTerminals for which a card removal was detected during the
 214          * latest call to {@linkplain State#waitForChange waitForChange()}
 215          * call.
 216          */
 217         CARD_REMOVAL,
 218     }
 219 
 220 }