1 /*
   2  * Copyright (c) 2009, 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 package sun.net.ftp;
  26 
  27 import java.security.AccessController;
  28 import java.security.PrivilegedAction;
  29 import java.util.ServiceConfigurationError;
  30 //import java.util.ServiceLoader;
  31 
  32 /**
  33  * Service provider class for FtpClient.
  34  * Sub-classes of FtpClientProvider provide an implementation of {@link FtpClient}
  35  * and associated classes. Applications do not normally use this class directly.
  36  * See {@link #provider() } for how providers are found and loaded.
  37  *
  38  * @since 1.7
  39  */
  40 public abstract class FtpClientProvider {
  41 
  42     /**
  43      * Creates a FtpClient from this provider.
  44      *
  45      * @return The created {@link FtpClient}.
  46      */
  47     public abstract FtpClient createFtpClient();
  48     private static final Object lock = new Object();
  49     private static FtpClientProvider provider = null;
  50 
  51     /**
  52      * Initializes a new instance of this class.
  53      *
  54      * @throws SecurityException if a security manager is installed and it denies
  55      *         {@link RuntimePermission}{@code ("ftpClientProvider")}
  56      */
  57     protected FtpClientProvider() {
  58         SecurityManager sm = System.getSecurityManager();
  59         if (sm != null) {
  60             sm.checkPermission(new RuntimePermission("ftpClientProvider"));
  61         }
  62     }
  63 
  64     private static boolean loadProviderFromProperty() {
  65         String cm = System.getProperty("sun.net.ftpClientProvider");
  66         if (cm == null) {
  67             return false;
  68         }
  69         try {
  70             Class<?> c = Class.forName(cm, true, null);
  71             provider = (FtpClientProvider) c.newInstance();
  72             return true;
  73         } catch (ClassNotFoundException |
  74                  IllegalAccessException |
  75                  InstantiationException |
  76                  SecurityException x) {
  77             throw new ServiceConfigurationError(x.toString());
  78         }
  79     }
  80 
  81     private static boolean loadProviderAsService() {
  82 //        Iterator<FtpClientProvider> i =
  83 //                ServiceLoader.load(FtpClientProvider.class,
  84 //                                   ClassLoader.getSystemClassLoader()).iterator();
  85 //
  86 //        while (i.hasNext()) {
  87 //            try {
  88 //                provider = i.next();
  89 //                return true;
  90 //            } catch (ServiceConfigurationError sce) {
  91 //                if (sce.getCause() instanceof SecurityException) {
  92 //                    // Ignore, try next provider, if any
  93 //                    continue;
  94 //                }
  95 //                throw sce;
  96 //            }
  97 //        }
  98         return false;
  99     }
 100 
 101     /**
 102      * Returns the system wide default FtpClientProvider for this invocation of
 103      * the Java virtual machine.
 104      *
 105      * <p> The first invocation of this method locates the default provider
 106      * object as follows: </p>
 107      *
 108      * <ol>
 109      *
 110      *   <li><p> If the system property
 111      *   {@code java.net.FtpClientProvider} is defined then it is
 112      *   taken to be the fully-qualified name of a concrete provider class.
 113      *   The class is loaded and instantiated; if this process fails then an
 114      *   unspecified unchecked error or exception is thrown.  </p></li>
 115      *
 116      *   <li><p> If a provider class has been installed in a jar file that is
 117      *   visible to the system class loader, and that jar file contains a
 118      *   provider-configuration file named
 119      *   {@code java.net.FtpClientProvider} in the resource
 120      *   directory {@code META-INF/services}, then the first class name
 121      *   specified in that file is taken.  The class is loaded and
 122      *   instantiated; if this process fails then an unspecified unchecked error or exception is
 123      *   thrown.  </p></li>
 124      *
 125      *   <li><p> Finally, if no provider has been specified by any of the above
 126      *   means then the system-default provider class is instantiated and the
 127      *   result is returned.  </p></li>
 128      *
 129      * </ol>
 130      *
 131      * <p> Subsequent invocations of this method return the provider that was
 132      * returned by the first invocation.  </p>
 133      *
 134      * @return  The system-wide default FtpClientProvider
 135      */
 136     public static FtpClientProvider provider() {
 137         synchronized (lock) {
 138             if (provider != null) {
 139                 return provider;
 140             }
 141             return (FtpClientProvider) AccessController.doPrivileged(
 142                     new PrivilegedAction<Object>() {
 143 
 144                         public Object run() {
 145                             if (loadProviderFromProperty()) {
 146                                 return provider;
 147                             }
 148                             if (loadProviderAsService()) {
 149                                 return provider;
 150                             }
 151                             provider = new sun.net.ftp.impl.DefaultFtpClientProvider();
 152                             return provider;
 153                         }
 154                     });
 155         }
 156     }
 157 }