1/*
2 * Copyright (c) 2006, 2015, 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
26package javax.smartcardio;
27
28import 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 */
51public 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     *   state.
98     *
99     * @throws NullPointerException if state 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}
221