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 }