1 /*
2  * Copyright (c) 2016, 2019, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package jdk.vm.ci.services;
24 
25 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
26 
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.ServiceLoader;
30 
31 /**
32  * Service-provider class for the runtime to locate providers of JVMCI services where the latter are
33  * not in packages exported by the JVMCI module. As part of instantiating a
34  * {@link JVMCIServiceLocator}, all JVMCI packages will be opened to the module defining the class
35  * of the instantiated object.
36  *
37  * While the {@link #getProvider(Class)} method can be used directly, it's usually easier to use
38  * {@link #getProviders(Class)}.
39  */
40 public abstract class JVMCIServiceLocator {
41 
checkPermission()42     private static Void checkPermission() {
43         SecurityManager sm = System.getSecurityManager();
44         if (sm != null) {
45             sm.checkPermission(new JVMCIPermission());
46         }
47         return null;
48     }
49 
50     @SuppressWarnings("unused")
JVMCIServiceLocator(Void ignore)51     private JVMCIServiceLocator(Void ignore) {
52     }
53 
54     /**
55      * Creates a capability for accessing JVMCI. Once successfully instantiated, JVMCI opens all its
56      * packages to the module defining the type of this object.
57      *
58      * @throws SecurityException if a security manager has been installed and it denies
59      *             {@link JVMCIPermission}
60      */
JVMCIServiceLocator()61     protected JVMCIServiceLocator() {
62         this(checkPermission());
63         Services.checkJVMCIEnabled();
64         Services.openJVMCITo(getClass().getModule());
65     }
66 
67     /**
68      * Gets the provider of the service defined by {@code service} or {@code null} if this object
69      * does not have a provider for {@code service}.
70      */
getProvider(Class<S> service)71     protected abstract <S> S getProvider(Class<S> service);
72 
73     private static volatile List<JVMCIServiceLocator> cachedLocators;
74 
getJVMCIServiceLocators()75     private static Iterable<JVMCIServiceLocator> getJVMCIServiceLocators() {
76         Iterable<JVMCIServiceLocator> result = cachedLocators;
77         if (result != null) {
78             return result;
79         }
80         result = ServiceLoader.load(JVMCIServiceLocator.class, ClassLoader.getSystemClassLoader());
81         if (IS_BUILDING_NATIVE_IMAGE) {
82             ArrayList<JVMCIServiceLocator> l = new ArrayList<>();
83             for (JVMCIServiceLocator locator : result) {
84                 l.add(locator);
85             }
86             l.trimToSize();
87             cachedLocators = l;
88             return l;
89         }
90         return result;
91     }
92 
93     /**
94      * Gets the providers of the service defined by {@code service} by querying the available
95      * {@link JVMCIServiceLocator} providers.
96      *
97      * @throws SecurityException if a security manager is present and it denies
98      *             {@link JVMCIPermission}
99      */
getProviders(Class<S> service)100     public static <S> List<S> getProviders(Class<S> service) {
101         Services.checkJVMCIEnabled();
102         SecurityManager sm = System.getSecurityManager();
103         if (sm != null) {
104             sm.checkPermission(new JVMCIPermission());
105         }
106         List<S> providers = new ArrayList<>();
107         for (JVMCIServiceLocator access : getJVMCIServiceLocators()) {
108             S provider = access.getProvider(service);
109             if (provider != null) {
110                 providers.add(provider);
111             }
112         }
113         return providers;
114     }
115 }
116