1 /*
  2  * Copyright (c) 2021, 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 java.net.spi;
 27 
 28 import sun.net.ResolverProviderConfiguration;
 29 
 30 import java.net.InetAddress;
 31 import java.util.ServiceLoader;
 32 
 33 /**
 34  * Service-provider class for {@linkplain InetAddressResolver InetAddress resolvers}.
 35  *
 36  * <p> A resolver provider is a factory for custom implementations of {@linkplain
 37  * InetAddressResolver InetAddress resolvers}. A resolver defines operations for
 38  * looking up (resolving) host names and IP addresses.
 39  * <p>A resolver provider is a concrete subclass of this class that has a
 40  * zero-argument constructor and implements the abstract methods specified below.
 41  *
 42  * <p> A given invocation of the Java virtual machine maintains a single
 43  * system-wide resolver instance, which is used by
 44  * <a href="{@docRoot}/java.base/java/net/InetAddress.html#host-name-resolution">
 45  * InetAddress</a>. It is set after the VM is fully initialized and when an
 46  * invocation of a method in {@link InetAddress} class triggers the first lookup
 47  * operation.
 48  *
 49  * <p id="system-wide-resolver"> A resolver provider is located and loaded by
 50  * {@link InetAddress} to create the system-wide resolver as follows:
 51  * <ol>
 52  *  <li>The {@link ServiceLoader} mechanism is used to locate an
 53  *      {@code InetAddressResolverProvider} using the
 54  *      system class loader. The order in which providers are located is
 55  *      {@linkplain ServiceLoader#load(java.lang.Class, java.lang.ClassLoader)
 56  *      implementation specific}.
 57  *      The first provider found will be used to instantiate the
 58  *      {@link InetAddressResolver InetAddressResolver} by invoking the
 59  *      {@link InetAddressResolverProvider#get(InetAddressResolverProvider.Configuration)}
 60  *      method. The returned {@code InetAddressResolver} will be set as the
 61  *      system-wide resolver.
 62  *  <li>If the previous step fails to find any resolver provider the
 63  *      <a href="{@docRoot}/java.base/java/net/InetAddress.html#built-in-resolver">
 64  *      built-in resolver</a> will be set as the system-wide resolver.
 65  * </ol>
 66  *
 67  * <p> If instantiating a custom resolver from a provider discovered in
 68  * step 1 throws an error or exception, the system-wide resolver will not be
 69  * set and the error or exception will be propagated to the calling thread.
 70  * Otherwise, any lookup operation will be performed using the
 71  * <i>system-wide resolver</i>.
 72  *
 73  * @implNote {@link InetAddress} will use the <i>built-in resolver</i> for any lookup operation
 74  * that might occur before the VM is fully booted.
 75  *
 76  * @since 18
 77  */
 78 public abstract class InetAddressResolverProvider {
 79 
 80     /**
 81      * Initialize and return an {@link InetAddressResolver} provided by
 82      * this provider. This method is called by {@link InetAddress} when
 83      * <a href="#system-wide-resolver">installing</a>
 84      * the system-wide resolver implementation.
 85      *
 86      * <p> Any error or exception thrown by this method is considered as
 87      * a failure of {@code InetAddressResolver} instantiation and will be propagated to
 88      * the calling thread.
 89      * @param configuration a {@link Configuration} instance containing platform built-in address
 90      *                     resolution configuration.
 91      * @return the resolver provided by this provider
 92      */
 93     public abstract InetAddressResolver get(Configuration configuration);
 94 
 95     /**
 96      * {@return the name of this provider, or {@code null} if unnamed}
 97      */
 98     public abstract String name();
 99 
100     /**
101      * The {@code RuntimePermission("inetAddressResolverProvider")} is
102      * necessary to subclass and instantiate the {@code InetAddressResolverProvider} class,
103      * as well as to obtain resolver from an instance of that class,
104      * and it is also required to obtain the operating system name resolution configurations.
105      */
106     private static final RuntimePermission INET_ADDRESS_RESOLVER_PERMISSION =
107             new RuntimePermission("inetAddressResolverProvider");
108 
109     /**
110      * Creates a new instance of {@code InetAddressResolverProvider}.
111      *
112      * @throws SecurityException if a security manager is present and its
113      *                           {@code checkPermission} method doesn't allow the
114      *                           {@code RuntimePermission("inetAddressResolverProvider")}.
115      * @implNote It is recommended that an {@code InetAddressResolverProvider} service
116      * implementation initialization should be as simple as possible, in order to avoid
117      * possible risks of deadlock or class loading cycles during the instantiation of the
118      * service provider.
119      */
120     protected InetAddressResolverProvider() {
121         this(checkPermission());
122     }
123 
124     private InetAddressResolverProvider(Void unused) {
125     }
126 
127     @SuppressWarnings("removal")
128     private static Void checkPermission() {
129         final SecurityManager sm = System.getSecurityManager();
130         if (sm != null) {
131             sm.checkPermission(INET_ADDRESS_RESOLVER_PERMISSION);
132         }
133         return null;
134     }
135 
136     /**
137      * A {@code Configuration} object is supplied to the
138      * {@link InetAddressResolverProvider#get(Configuration)} method when
139      * setting the system-wide resolver.
140      * A resolver implementation can then delegate to the built-in resolver
141      * provided by this interface if it needs to.
142      *
143      * @since 18
144      */
145     public sealed interface Configuration permits ResolverProviderConfiguration {
146         /**
147          * Returns the built-in {@linkplain InetAddressResolver resolver}.
148          *
149          * @return the JDK built-in resolver.
150          */
151         InetAddressResolver builtinResolver();
152 
153         /**
154          * Reads the localhost name from the system configuration.
155          *
156          * @return the localhost name.
157          */
158         String lookupLocalHostName();
159     }
160 }