1
17 package org.apache.tomcat.util.compat;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.lang.reflect.AccessibleObject;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.net.MalformedURLException;
26 import java.net.URI;
27 import java.net.URL;
28 import java.net.URLConnection;
29 import java.util.Deque;
30 import java.util.Set;
31 import java.util.jar.JarFile;
32 import java.util.zip.ZipFile;
33
34 import javax.net.ssl.SSLEngine;
35 import javax.net.ssl.SSLParameters;
36
37 import org.apache.juli.logging.Log;
38 import org.apache.juli.logging.LogFactory;
39 import org.apache.tomcat.util.res.StringManager;
40
41 class Jre9Compat extends JreCompat {
42
43 private static final Log log = LogFactory.getLog(Jre9Compat.class);
44 private static final StringManager sm = StringManager.getManager(Jre9Compat.class);
45
46 private static final Class<?> inaccessibleObjectExceptionClazz;
47 private static final Method setApplicationProtocolsMethod;
48 private static final Method getApplicationProtocolMethod;
49 private static final Method setDefaultUseCachesMethod;
50 private static final Method bootMethod;
51 private static final Method configurationMethod;
52 private static final Method modulesMethod;
53 private static final Method referenceMethod;
54 private static final Method locationMethod;
55 private static final Method isPresentMethod;
56 private static final Method getMethod;
57 private static final Constructor<JarFile> jarFileConstructor;
58 private static final Method isMultiReleaseMethod;
59 private static final Object RUNTIME_VERSION;
60 private static final int RUNTIME_MAJOR_VERSION;
61 private static final Method canAccessMethod;
62 private static final Method getModuleMethod;
63 private static final Method isExportedMethod;
64
65 static {
66 Class<?> c1 = null;
67 Method m2 = null;
68 Method m3 = null;
69 Method m4 = null;
70 Method m5 = null;
71 Method m6 = null;
72 Method m7 = null;
73 Method m8 = null;
74 Method m9 = null;
75 Method m10 = null;
76 Method m11 = null;
77 Constructor<JarFile> c12 = null;
78 Method m13 = null;
79 Object o14 = null;
80 Object o15 = null;
81 Method m16 = null;
82 Method m17 = null;
83 Method m18 = null;
84
85 try {
86
87
88 c1 = Class.forName("java.lang.reflect.InaccessibleObjectException");
89
90 Class<?> moduleLayerClazz = Class.forName("java.lang.ModuleLayer");
91 Class<?> configurationClazz = Class.forName("java.lang.module.Configuration");
92 Class<?> resolvedModuleClazz = Class.forName("java.lang.module.ResolvedModule");
93 Class<?> moduleReferenceClazz = Class.forName("java.lang.module.ModuleReference");
94 Class<?> optionalClazz = Class.forName("java.util.Optional");
95 Class<?> versionClazz = Class.forName("java.lang.Runtime$Version");
96 Method runtimeVersionMethod = JarFile.class.getMethod("runtimeVersion");
97 Method majorMethod = versionClazz.getMethod("major");
98
99 m2 = SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
100 m3 = SSLEngine.class.getMethod("getApplicationProtocol");
101 m4 = URLConnection.class.getMethod("setDefaultUseCaches", String.class, boolean.class);
102 m5 = moduleLayerClazz.getMethod("boot");
103 m6 = moduleLayerClazz.getMethod("configuration");
104 m7 = configurationClazz.getMethod("modules");
105 m8 = resolvedModuleClazz.getMethod("reference");
106 m9 = moduleReferenceClazz.getMethod("location");
107 m10 = optionalClazz.getMethod("isPresent");
108 m11 = optionalClazz.getMethod("get");
109 c12 = JarFile.class.getConstructor(File.class, boolean.class, int.class, versionClazz);
110 m13 = JarFile.class.getMethod("isMultiRelease");
111 o14 = runtimeVersionMethod.invoke(null);
112 o15 = majorMethod.invoke(o14);
113 m16 = AccessibleObject.class.getMethod("canAccess", new Class<?>[] { Object.class });
114 m17 = Class.class.getMethod("getModule");
115 Class<?> moduleClass = Class.forName("java.lang.Module");
116 m18 = moduleClass.getMethod("isExported", String.class);
117
118 } catch (ClassNotFoundException e) {
119 if (c1 == null) {
120
121 log.debug(sm.getString("jre9Compat.javaPre9"), e);
122 } else {
123
124 log.error(sm.getString("jre9Compat.unexpected"), e);
125 }
126 } catch (ReflectiveOperationException | IllegalArgumentException e) {
127
128 log.error(sm.getString("jre9Compat.unexpected"), e);
129 }
130
131 inaccessibleObjectExceptionClazz = c1;
132 setApplicationProtocolsMethod = m2;
133 getApplicationProtocolMethod = m3;
134 setDefaultUseCachesMethod = m4;
135 bootMethod = m5;
136 configurationMethod = m6;
137 modulesMethod = m7;
138 referenceMethod = m8;
139 locationMethod = m9;
140 isPresentMethod = m10;
141 getMethod = m11;
142 jarFileConstructor = c12;
143 isMultiReleaseMethod = m13;
144
145 RUNTIME_VERSION = o14;
146 if (o15 != null) {
147 RUNTIME_MAJOR_VERSION = ((Integer) o15).intValue();
148 } else {
149
150 RUNTIME_MAJOR_VERSION = 8;
151 }
152
153 canAccessMethod = m16;
154 getModuleMethod = m17;
155 isExportedMethod = m18;
156 }
157
158
159 static boolean isSupported() {
160 return inaccessibleObjectExceptionClazz != null;
161 }
162
163
164 @Override
165 public boolean isInstanceOfInaccessibleObjectException(Throwable t) {
166 if (t == null) {
167 return false;
168 }
169
170 return inaccessibleObjectExceptionClazz.isAssignableFrom(t.getClass());
171 }
172
173
174 @Override
175 public void setApplicationProtocols(SSLParameters sslParameters, String[] protocols) {
176 try {
177 setApplicationProtocolsMethod.invoke(sslParameters, (Object) protocols);
178 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
179 throw new UnsupportedOperationException(e);
180 }
181 }
182
183
184 @Override
185 public String getApplicationProtocol(SSLEngine sslEngine) {
186 try {
187 return (String) getApplicationProtocolMethod.invoke(sslEngine);
188 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
189 throw new UnsupportedOperationException(e);
190 }
191 }
192
193
194 @Override
195 public void disableCachingForJarUrlConnections() throws IOException {
196 try {
197 setDefaultUseCachesMethod.invoke(null, "JAR", Boolean.FALSE);
198 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
199 throw new UnsupportedOperationException(e);
200 }
201 }
202
203
204 @Override
205 public void addBootModulePath(Deque<URL> classPathUrlsToProcess) {
206 try {
207 Object bootLayer = bootMethod.invoke(null);
208 Object bootConfiguration = configurationMethod.invoke(bootLayer);
209 Set<?> resolvedModules = (Set<?>) modulesMethod.invoke(bootConfiguration);
210 for (Object resolvedModule : resolvedModules) {
211 Object moduleReference = referenceMethod.invoke(resolvedModule);
212 Object optionalURI = locationMethod.invoke(moduleReference);
213 Boolean isPresent = (Boolean) isPresentMethod.invoke(optionalURI);
214 if (isPresent.booleanValue()) {
215 URI uri = (URI) getMethod.invoke(optionalURI);
216 try {
217 URL url = uri.toURL();
218 classPathUrlsToProcess.add(url);
219 } catch (MalformedURLException e) {
220 log.warn(sm.getString("jre9Compat.invalidModuleUri", uri), e);
221 }
222 }
223 }
224 } catch (ReflectiveOperationException e) {
225 throw new UnsupportedOperationException(e);
226 }
227 }
228
229
230 @Override
231 public JarFile jarFileNewInstance(File f) throws IOException {
232 try {
233 return jarFileConstructor.newInstance(
234 f, Boolean.TRUE, Integer.valueOf(ZipFile.OPEN_READ), RUNTIME_VERSION);
235 } catch (ReflectiveOperationException | IllegalArgumentException e) {
236 throw new IOException(e);
237 }
238 }
239
240
241 @Override
242 public boolean jarFileIsMultiRelease(JarFile jarFile) {
243 try {
244 return ((Boolean) isMultiReleaseMethod.invoke(jarFile)).booleanValue();
245 } catch (ReflectiveOperationException | IllegalArgumentException e) {
246 return false;
247 }
248 }
249
250
251 @Override
252 public int jarFileRuntimeMajorVersion() {
253 return RUNTIME_MAJOR_VERSION;
254 }
255
256
257 @Override
258 public boolean canAcccess(Object base, AccessibleObject accessibleObject) {
259 try {
260 return ((Boolean) canAccessMethod.invoke(accessibleObject, base)).booleanValue();
261 } catch (ReflectiveOperationException | IllegalArgumentException e) {
262 return false;
263 }
264 }
265
266
267 @Override
268 public boolean isExported(Class<?> type) {
269 try {
270 String packageName = type.getPackage().getName();
271 Object module = getModuleMethod.invoke(type);
272 return ((Boolean) isExportedMethod.invoke(module, packageName)).booleanValue();
273 } catch (ReflectiveOperationException e) {
274 return false;
275 }
276 }
277 }
278