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 @SuppressWarnings("deprecation") 115 Object o = Class.forName("sun.security.smartcardio.SunPCSC").newInstance(); 116 sun = (Provider)o; 117 } 118 factory = TerminalFactory.getInstance(type, null, sun); 119 } catch (Exception e) { 120 // ignore 121 } 122 } 123 if (factory == null) { 124 type = "None"; 125 factory = new TerminalFactory 126 (NoneFactorySpi.INSTANCE, NoneProvider.INSTANCE, "None"); 127 } 128 defaultType = type; 129 defaultFactory = factory; 130 } 131 132 private static final class NoneProvider extends Provider { 133 134 private static final long serialVersionUID = 2745808869881593918L; 135 final static Provider INSTANCE = new NoneProvider(); 136 private NoneProvider() { 137 super("None", 1.0d, "none"); 138 } 139 } 140 141 private static final class NoneFactorySpi extends TerminalFactorySpi { 142 final static TerminalFactorySpi INSTANCE = new NoneFactorySpi(); 143 private NoneFactorySpi() { 144 // empty 145 } 146 protected CardTerminals engineTerminals() { 147 return NoneCardTerminals.INSTANCE; 148 } 149 } 150 151 private static final class NoneCardTerminals extends CardTerminals { 152 final static CardTerminals INSTANCE = new NoneCardTerminals(); 153 private NoneCardTerminals() { 154 // empty 155 } 156 public List<CardTerminal> list(State state) throws CardException { 157 if (state == null) { 158 throw new NullPointerException(); 159 } 160 return Collections.emptyList(); 161 } 162 public boolean waitForChange(long timeout) throws CardException { 163 throw new IllegalStateException("no terminals"); 164 } 165 } 166 167 private final TerminalFactorySpi spi; 168 169 private final Provider provider; 170 171 private final String type; 172 173 private TerminalFactory(TerminalFactorySpi spi, Provider provider, String type) { 174 this.spi = spi; 175 this.provider = provider; 176 this.type = type; 177 } 178 179 /** 180 * Get the default TerminalFactory type. 181 * 182 * <p>It is determined as follows: 183 * 184 * when this class is initialized, the system property 185 * <code>javax.smartcardio.TerminalFactory.DefaultType</code> 186 * is examined. If it is set, a TerminalFactory of this type is 187 * instantiated by calling the {@linkplain #getInstance 188 * getInstance(String,Object)} method passing 189 * <code>null</code> as the value for <code>params</code>. If the call 190 * succeeds, the type becomes the default type and the factory becomes 191 * the {@linkplain #getDefault default} factory. 192 * 193 * <p>If the system property is not set or the getInstance() call fails 194 * for any reason, the system defaults to an implementation specific 195 * default type and TerminalFactory. 196 * 197 * @return the default TerminalFactory type 198 */ 199 public static String getDefaultType() { 200 return defaultType; 201 } 202 203 /** 204 * Returns the default TerminalFactory instance. See 205 * {@linkplain #getDefaultType} for more information. 206 * 207 * <p>A default TerminalFactory is always available. However, depending 208 * on the implementation, it may not offer any terminals. 209 * 210 * @return the default TerminalFactory 211 */ 212 public static TerminalFactory getDefault() { 213 return defaultFactory; 214 } 215 216 /** 217 * Returns a TerminalFactory of the specified type that is initialized 218 * with the specified parameters. 219 * 220 * <p> This method traverses the list of registered security Providers, 221 * starting with the most preferred Provider. 222 * A new TerminalFactory object encapsulating the 223 * TerminalFactorySpi implementation from the first 224 * Provider that supports the specified type is returned. 225 * 226 * <p> Note that the list of registered providers may be retrieved via 227 * the {@linkplain Security#getProviders() Security.getProviders()} method. 228 * 229 * <p>The <code>TerminalFactory</code> is initialized with the 230 * specified parameters Object. The type of parameters 231 * needed may vary between different types of <code>TerminalFactory</code>s. 232 * 233 * @implNote 234 * The JDK Reference Implementation additionally uses the 235 * {@code jdk.security.provider.preferred} 236 * {@link Security#getProperty(String) Security} property to determine 237 * the preferred provider order for the specified algorithm. This 238 * may be different than the order of providers returned by 239 * {@link Security#getProviders() Security.getProviders()}. 240 * 241 * @param type the type of the requested TerminalFactory 242 * @param params the parameters to pass to the TerminalFactorySpi 243 * implementation, or null if no parameters are needed 244 * @return a TerminalFactory of the specified type 245 * 246 * @throws NullPointerException if type is null 247 * @throws NoSuchAlgorithmException if no Provider supports a 248 * TerminalFactorySpi of the specified type 249 */ 250 public static TerminalFactory getInstance(String type, Object params) 251 throws NoSuchAlgorithmException { 252 Instance instance = GetInstance.getInstance("TerminalFactory", 253 TerminalFactorySpi.class, type, params); 254 return new TerminalFactory((TerminalFactorySpi)instance.impl, 255 instance.provider, type); 256 } 257 258 /** 259 * Returns a TerminalFactory of the specified type that is initialized 260 * with the specified parameters. 261 * 262 * <p> A new TerminalFactory object encapsulating the 263 * TerminalFactorySpi implementation from the specified provider 264 * is returned. The specified provider must be registered 265 * in the security provider list. 266 * 267 * <p> Note that the list of registered providers may be retrieved via 268 * the {@linkplain Security#getProviders() Security.getProviders()} method. 269 * 270 * <p>The <code>TerminalFactory</code> is initialized with the 271 * specified parameters Object. The type of parameters 272 * needed may vary between different types of <code>TerminalFactory</code>s. 273 * 274 * @param type the type of the requested TerminalFactory 275 * @param params the parameters to pass to the TerminalFactorySpi 276 * implementation, or null if no parameters are needed 277 * @param provider the name of the provider 278 * @return a TerminalFactory of the specified type 279 * 280 * @throws NullPointerException if type is null 281 * @throws IllegalArgumentException if provider is null or the empty String 282 * @throws NoSuchAlgorithmException if a TerminalFactorySpi implementation 283 * of the specified type is not available from the specified provider 284 * @throws NoSuchAlgorithmException if no TerminalFactory of the 285 * specified type could be found 286 * @throws NoSuchProviderException if the specified provider could not 287 * be found 288 */ 289 public static TerminalFactory getInstance(String type, Object params, 290 String provider) throws NoSuchAlgorithmException, NoSuchProviderException { 291 Instance instance = GetInstance.getInstance("TerminalFactory", 292 TerminalFactorySpi.class, type, params, provider); 293 return new TerminalFactory((TerminalFactorySpi)instance.impl, 294 instance.provider, type); 295 } 296 297 /** 298 * Returns a TerminalFactory of the specified type that is initialized 299 * with the specified parameters. 300 * 301 * <p> A new TerminalFactory object encapsulating the 302 * TerminalFactorySpi implementation from the specified provider object 303 * is returned. Note that the specified provider object does not have to be 304 * registered in the provider list. 305 * 306 * <p>The <code>TerminalFactory</code> is initialized with the 307 * specified parameters Object. The type of parameters 308 * needed may vary between different types of <code>TerminalFactory</code>s. 309 * 310 * @param type the type of the requested TerminalFactory 311 * @param params the parameters to pass to the TerminalFactorySpi 312 * implementation, or null if no parameters are needed 313 * @param provider the provider 314 * @return a TerminalFactory of the specified type 315 * 316 * @throws NullPointerException if type is null 317 * @throws IllegalArgumentException if provider is null 318 * @throws NoSuchAlgorithmException if a TerminalFactorySpi implementation 319 * of the specified type is not available from the specified Provider 320 */ 321 public static TerminalFactory getInstance(String type, Object params, 322 Provider provider) throws NoSuchAlgorithmException { 323 Instance instance = GetInstance.getInstance("TerminalFactory", 324 TerminalFactorySpi.class, type, params, provider); 325 return new TerminalFactory((TerminalFactorySpi)instance.impl, 326 instance.provider, type); 327 } 328 329 /** 330 * Returns the provider of this TerminalFactory. 331 * 332 * @return the provider of this TerminalFactory. 333 */ 334 public Provider getProvider() { 335 return provider; 336 } 337 338 /** 339 * Returns the type of this TerminalFactory. This is the value that was 340 * specified in the getInstance() method that returned this object. 341 * 342 * @return the type of this TerminalFactory 343 */ 344 public String getType() { 345 return type; 346 } 347 348 /** 349 * Returns a new CardTerminals object encapsulating the terminals 350 * supported by this factory. 351 * See the class comment of the {@linkplain CardTerminals} class 352 * regarding how the returned objects can be shared and reused. 353 * 354 * @return a new CardTerminals object encapsulating the terminals 355 * supported by this factory. 356 */ 357 public CardTerminals terminals() { 358 return spi.engineTerminals(); 359 } 360 361 /** 362 * Returns a string representation of this TerminalFactory. 363 * 364 * @return a string representation of this TerminalFactory. 365 */ 366 public String toString() { 367 return "TerminalFactory for type " + type + " from provider " 368 + provider.getName(); 369 } 370 371 }