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