1 /* 2 * Copyright (c) 2005, 2011, 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 import java.security.*; 31 32 import sun.security.jca.*; 33 import sun.security.jca.GetInstance.*; 34 35 import sun.security.action.GetPropertyAction; 36 37 /** 38 * A factory for CardTerminal objects. 39 * 40 * It allows an application to 41 * <ul> 42 * <li>obtain a TerminalFactory by calling 43 * one of the static factory methods in this class 44 * ({@linkplain #getDefault} or {@linkplain #getInstance getInstance()}). 45 * <li>use this TerminalFactory object to access the CardTerminals by 46 * calling the {@linkplain #terminals} method. 47 * </ul> 48 * 49 * <p>Each TerminalFactory has a <code>type</code> indicating how it 50 * was implemented. It must be specified when the implementation is obtained 51 * using a {@linkplain #getInstance getInstance()} method and can be retrieved 52 * via the {@linkplain #getType} method. 53 * 54 * <P>The following standard type names have been defined: 55 * <dl> 56 * <dt><code>PC/SC</code> 57 * <dd>an implementation that calls into the PC/SC Smart Card stack 58 * of the host platform. 59 * Implementations do not require parameters and accept "null" as argument 60 * in the getInstance() calls. 61 * <dt><code>None</code> 62 * <dd>an implementation that does not supply any CardTerminals. On platforms 63 * that do not support other implementations, 64 * {@linkplain #getDefaultType} returns <code>None</code> and 65 * {@linkplain #getDefault} returns an instance of a <code>None</code> 66 * TerminalFactory. Factories of this type cannot be obtained by calling the 67 * <code>getInstance()</code> methods. 68 * </dl> 69 * Additional standard types may be defined in the future. 70 * 71 * <p><strong>Note:</strong> 72 * Provider implementations that accept initialization parameters via the 73 * <code>getInstance()</code> methods are strongly 74 * encouraged to use a {@linkplain java.util.Properties} object as the 75 * representation for String name-value pair based parameters whenever 76 * possible. This allows applications to more easily interoperate with 77 * multiple providers than if each provider used different provider 78 * specific class as parameters. 79 * 80 * <P>TerminalFactory utilizes an extensible service provider framework. 81 * Service providers that wish to add a new implementation should see the 82 * {@linkplain TerminalFactorySpi} class for more information. 83 * 84 * @see CardTerminals 85 * @see Provider 86 * 87 * @since 1.6 88 * @author Andreas Sterbenz 89 * @author JSR 268 Expert Group 90 */ 91 public final class TerminalFactory { 92 93 private final static String PROP_NAME = 94 "javax.smartcardio.TerminalFactory.DefaultType"; 95 96 private final static String defaultType; 97 98 private final static TerminalFactory defaultFactory; 99 100 static { 101 // lookup up the user specified type, default to PC/SC 102 String type = AccessController.doPrivileged 103 (new GetPropertyAction(PROP_NAME, "PC/SC")).trim(); 104 TerminalFactory factory = null; 105 try { 106 factory = TerminalFactory.getInstance(type, null); 107 } catch (Exception e) { 108 // ignore 109 } 110 if (factory == null) { 111 // if that did not work, try the Sun PC/SC factory 112 try { 113 type = "PC/SC"; 114 Provider sun = Security.getProvider("SunPCSC"); 115 if (sun == null) { 116 Class<?> clazz = Class.forName("sun.security.smartcardio.SunPCSC"); 117 sun = (Provider)clazz.newInstance(); 118 } 119 factory = TerminalFactory.getInstance(type, null, sun); 120 } catch (Exception e) { 121 // ignore 122 } 123 } 124 if (factory == null) { 125 type = "None"; 126 factory = new TerminalFactory 127 (NoneFactorySpi.INSTANCE, NoneProvider.INSTANCE, "None"); 128 } 129 defaultType = type; 130 defaultFactory = factory; 131 } 132 133 private static final class NoneProvider extends Provider { 134 135 private static final long serialVersionUID = 2745808869881593918L; 136 final static Provider INSTANCE = new NoneProvider(); 137 private NoneProvider() { 138 super("None", 1.0d, "none"); 139 } 140 } 141 142 private static final class NoneFactorySpi extends TerminalFactorySpi { 143 final static TerminalFactorySpi INSTANCE = new NoneFactorySpi(); 144 private NoneFactorySpi() { 145 // empty 146 } 147 protected CardTerminals engineTerminals() { 148 return NoneCardTerminals.INSTANCE; 149 } 150 } 151 152 private static final class NoneCardTerminals extends CardTerminals { 153 final static CardTerminals INSTANCE = new NoneCardTerminals(); 154 private NoneCardTerminals() { 155 // empty 156 } 157 public List<CardTerminal> list(State state) throws CardException { 158 if (state == null) { 159 throw new NullPointerException(); 160 } 161 return Collections.emptyList(); 162 } 163 public boolean waitForChange(long timeout) throws CardException { 164 throw new IllegalStateException("no terminals"); 165 } 166 } 167 168 private final TerminalFactorySpi spi; 169 170 private final Provider provider; 171 172 private final String type; 173 174 private TerminalFactory(TerminalFactorySpi spi, Provider provider, String type) { 175 this.spi = spi; 176 this.provider = provider; 177 this.type = type; 178 } 179 180 /** 181 * Get the default TerminalFactory type. 182 * 183 * <p>It is determined as follows: 184 * 185 * when this class is initialized, the system property 186 * <code>javax.smartcardio.TerminalFactory.DefaultType</code> 187 * is examined. If it is set, a TerminalFactory of this type is 188 * instantiated by calling the {@linkplain #getInstance 189 * getInstance(String,Object)} method passing 190 * <code>null</code> as the value for <code>params</code>. If the call 191 * succeeds, the type becomes the default type and the factory becomes 192 * the {@linkplain #getDefault default} factory. 193 * 194 * <p>If the system property is not set or the getInstance() call fails 195 * for any reason, the system defaults to an implementation specific 196 * default type and TerminalFactory. 197 * 198 * @return the default TerminalFactory type 199 */ 200 public static String getDefaultType() { 201 return defaultType; 202 } 203 204 /** 205 * Returns the default TerminalFactory instance. See 206 * {@linkplain #getDefaultType} for more information. 207 * 208 * <p>A default TerminalFactory is always available. However, depending 209 * on the implementation, it may not offer any terminals. 210 * 211 * @return the default TerminalFactory 212 */ 213 public static TerminalFactory getDefault() { 214 return defaultFactory; 215 } 216 217 /** 218 * Returns a TerminalFactory of the specified type that is initialized 219 * with the specified parameters. 220 * 221 * <p> This method traverses the list of registered security Providers, 222 * starting with the most preferred Provider. 223 * A new TerminalFactory object encapsulating the 224 * TerminalFactorySpi implementation from the first 225 * Provider that supports the specified type is returned. 226 * 227 * <p> Note that the list of registered providers may be retrieved via 228 * the {@linkplain Security#getProviders() Security.getProviders()} method. 229 * 230 * <p>The <code>TerminalFactory</code> is initialized with the 231 * specified parameters Object. The type of parameters 232 * needed may vary between different types of <code>TerminalFactory</code>s. 233 * 234 * @param type the type of the requested TerminalFactory 235 * @param params the parameters to pass to the TerminalFactorySpi 236 * implementation, or null if no parameters are needed 237 * @return a TerminalFactory of the specified type 238 * 239 * @throws NullPointerException if type is null 240 * @throws NoSuchAlgorithmException if no Provider supports a 241 * TerminalFactorySpi of the specified type 242 */ 243 public static TerminalFactory getInstance(String type, Object params) 244 throws NoSuchAlgorithmException { 245 Instance instance = GetInstance.getInstance("TerminalFactory", 246 TerminalFactorySpi.class, type, params); 247 return new TerminalFactory((TerminalFactorySpi)instance.impl, 248 instance.provider, type); 249 } 250 251 /** 252 * Returns a TerminalFactory of the specified type that is initialized 253 * with the specified parameters. 254 * 255 * <p> A new TerminalFactory object encapsulating the 256 * TerminalFactorySpi implementation from the specified provider 257 * is returned. The specified provider must be registered 258 * in the security provider list. 259 * 260 * <p> Note that the list of registered providers may be retrieved via 261 * the {@linkplain Security#getProviders() Security.getProviders()} method. 262 * 263 * <p>The <code>TerminalFactory</code> is initialized with the 264 * specified parameters Object. The type of parameters 265 * needed may vary between different types of <code>TerminalFactory</code>s. 266 * 267 * @param type the type of the requested TerminalFactory 268 * @param params the parameters to pass to the TerminalFactorySpi 269 * implementation, or null if no parameters are needed 270 * @param provider the name of the provider 271 * @return a TerminalFactory of the specified type 272 * 273 * @throws NullPointerException if type is null 274 * @throws IllegalArgumentException if provider is null or the empty String 275 * @throws NoSuchAlgorithmException if a TerminalFactorySpi implementation 276 * of the specified type is not available from the specified provider 277 * @throws NoSuchAlgorithmException if no TerminalFactory of the 278 * specified type could be found 279 * @throws NoSuchProviderException if the specified provider could not 280 * be found 281 */ 282 public static TerminalFactory getInstance(String type, Object params, 283 String provider) throws NoSuchAlgorithmException, NoSuchProviderException { 284 Instance instance = GetInstance.getInstance("TerminalFactory", 285 TerminalFactorySpi.class, type, params, provider); 286 return new TerminalFactory((TerminalFactorySpi)instance.impl, 287 instance.provider, type); 288 } 289 290 /** 291 * Returns a TerminalFactory of the specified type that is initialized 292 * with the specified parameters. 293 * 294 * <p> A new TerminalFactory object encapsulating the 295 * TerminalFactorySpi implementation from the specified provider object 296 * is returned. Note that the specified provider object does not have to be 297 * registered in the provider list. 298 * 299 * <p>The <code>TerminalFactory</code> is initialized with the 300 * specified parameters Object. The type of parameters 301 * needed may vary between different types of <code>TerminalFactory</code>s. 302 * 303 * @param type the type of the requested TerminalFactory 304 * @param params the parameters to pass to the TerminalFactorySpi 305 * implementation, or null if no parameters are needed 306 * @param provider the provider 307 * @return a TerminalFactory of the specified type 308 * 309 * @throws NullPointerException if type is null 310 * @throws IllegalArgumentException if provider is null 311 * @throws NoSuchAlgorithmException if a TerminalFactorySpi implementation 312 * of the specified type is not available from the specified Provider 313 */ 314 public static TerminalFactory getInstance(String type, Object params, 315 Provider provider) throws NoSuchAlgorithmException { 316 Instance instance = GetInstance.getInstance("TerminalFactory", 317 TerminalFactorySpi.class, type, params, provider); 318 return new TerminalFactory((TerminalFactorySpi)instance.impl, 319 instance.provider, type); 320 } 321 322 /** 323 * Returns the provider of this TerminalFactory. 324 * 325 * @return the provider of this TerminalFactory. 326 */ 327 public Provider getProvider() { 328 return provider; 329 } 330 331 /** 332 * Returns the type of this TerminalFactory. This is the value that was 333 * specified in the getInstance() method that returned this object. 334 * 335 * @return the type of this TerminalFactory 336 */ 337 public String getType() { 338 return type; 339 } 340 341 /** 342 * Returns a new CardTerminals object encapsulating the terminals 343 * supported by this factory. 344 * See the class comment of the {@linkplain CardTerminals} class 345 * regarding how the returned objects can be shared and reused. 346 * 347 * @return a new CardTerminals object encapsulating the terminals 348 * supported by this factory. 349 */ 350 public CardTerminals terminals() { 351 return spi.engineTerminals(); 352 } 353 354 /** 355 * Returns a string representation of this TerminalFactory. 356 * 357 * @return a string representation of this TerminalFactory. 358 */ 359 public String toString() { 360 return "TerminalFactory for type " + type + " from provider " 361 + provider.getName(); 362 } 363 364 }