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