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             @SuppressWarnings("deprecation")
  71             Object o = Class.forName(cm, true, null).newInstance();
  72             provider = (FtpClientProvider)o;
  73             return true;
  74         } catch (ClassNotFoundException |
  75                  IllegalAccessException |
  76                  InstantiationException |
  77                  SecurityException x) {
  78             throw new ServiceConfigurationError(x.toString());
  79         }
  80     }
  81 
  82     private static boolean loadProviderAsService() {
  83 //        Iterator<FtpClientProvider> i =
  84 //                ServiceLoader.load(FtpClientProvider.class,
  85 //                                   ClassLoader.getSystemClassLoader()).iterator();
  86 //
  87 //        while (i.hasNext()) {
  88 //            try {
  89 //                provider = i.next();
  90 //                return true;
  91 //            } catch (ServiceConfigurationError sce) {
  92 //                if (sce.getCause() instanceof SecurityException) {
  93 //                    // Ignore, try next provider, if any
  94 //                    continue;
  95 //                }
  96 //                throw sce;
  97 //            }
  98 //        }
  99         return false;
 100     }
 101 
 102     /**
 103      * Returns the system wide default FtpClientProvider for this invocation of
 104      * the Java virtual machine.
 105      *
 106      * <p> The first invocation of this method locates the default provider
 107      * object as follows: </p>
 108      *
 109      * <ol>
 110      *
 111      *   <li><p> If the system property
 112      *   {@code java.net.FtpClientProvider} is defined then it is
 113      *   taken to be the fully-qualified name of a concrete provider class.
 114      *   The class is loaded and instantiated; if this process fails then an
 115      *   unspecified unchecked error or exception is thrown.  </p></li>
 116      *
 117      *   <li><p> If a provider class has been installed in a jar file that is
 118      *   visible to the system class loader, and that jar file contains a
 119      *   provider-configuration file named
 120      *   {@code java.net.FtpClientProvider} in the resource
 121      *   directory {@code META-INF/services}, then the first class name
 122      *   specified in that file is taken.  The class is loaded and
 123      *   instantiated; if this process fails then an unspecified unchecked error or exception is
 124      *   thrown.  </p></li>
 125      *
 126      *   <li><p> Finally, if no provider has been specified by any of the above
 127      *   means then the system-default provider class is instantiated and the
 128      *   result is returned.  </p></li>
 129      *
 130      * </ol>
 131      *
 132      * <p> Subsequent invocations of this method return the provider that was
 133      * returned by the first invocation.  </p>
 134      *
 135      * @return  The system-wide default FtpClientProvider
 136      */
 137     public static FtpClientProvider provider() {
 138         synchronized (lock) {
 139             if (provider != null) {
 140                 return provider;
 141             }
 142             return (FtpClientProvider) AccessController.doPrivileged(
 143                     new PrivilegedAction<Object>() {
 144 
 145                         public Object run() {
 146                             if (loadProviderFromProperty()) {
 147                                 return provider;
 148                             }
 149                             if (loadProviderAsService()) {
 150                                 return provider;
 151                             }
 152                             provider = new sun.net.ftp.impl.DefaultFtpClientProvider();
 153                             return provider;
 154                         }
 155                     });
 156         }
 157     }
 158 }