278 lines
10 KiB
Java
278 lines
10 KiB
Java
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package org.apache.tomcat.util.compat;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.lang.reflect.AccessibleObject;
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URI;
|
|
import java.net.URL;
|
|
import java.net.URLConnection;
|
|
import java.util.Deque;
|
|
import java.util.Set;
|
|
import java.util.jar.JarFile;
|
|
import java.util.zip.ZipFile;
|
|
|
|
import javax.net.ssl.SSLEngine;
|
|
import javax.net.ssl.SSLParameters;
|
|
|
|
import org.apache.juli.logging.Log;
|
|
import org.apache.juli.logging.LogFactory;
|
|
import org.apache.tomcat.util.res.StringManager;
|
|
|
|
class Jre9Compat extends Jre8Compat {
|
|
|
|
private static final Log log = LogFactory.getLog(Jre9Compat.class);
|
|
private static final StringManager sm = StringManager.getManager(Jre9Compat.class);
|
|
|
|
private static final Class<?> inaccessibleObjectExceptionClazz;
|
|
private static final Method setApplicationProtocolsMethod;
|
|
private static final Method getApplicationProtocolMethod;
|
|
private static final Method setDefaultUseCachesMethod;
|
|
private static final Method bootMethod;
|
|
private static final Method configurationMethod;
|
|
private static final Method modulesMethod;
|
|
private static final Method referenceMethod;
|
|
private static final Method locationMethod;
|
|
private static final Method isPresentMethod;
|
|
private static final Method getMethod;
|
|
private static final Constructor<JarFile> jarFileConstructor;
|
|
private static final Method isMultiReleaseMethod;
|
|
private static final Object RUNTIME_VERSION;
|
|
private static final int RUNTIME_MAJOR_VERSION;
|
|
private static final Method canAccessMethod;
|
|
private static final Method getModuleMethod;
|
|
private static final Method isExportedMethod;
|
|
|
|
static {
|
|
Class<?> c1 = null;
|
|
Method m2 = null;
|
|
Method m3 = null;
|
|
Method m4 = null;
|
|
Method m5 = null;
|
|
Method m6 = null;
|
|
Method m7 = null;
|
|
Method m8 = null;
|
|
Method m9 = null;
|
|
Method m10 = null;
|
|
Method m11 = null;
|
|
Constructor<JarFile> c12 = null;
|
|
Method m13 = null;
|
|
Object o14 = null;
|
|
Object o15 = null;
|
|
Method m16 = null;
|
|
Method m17 = null;
|
|
Method m18 = null;
|
|
|
|
try {
|
|
// Order is important for the error handling below.
|
|
// Must look up c1 first.
|
|
c1 = Class.forName("java.lang.reflect.InaccessibleObjectException");
|
|
|
|
Class<?> moduleLayerClazz = Class.forName("java.lang.ModuleLayer");
|
|
Class<?> configurationClazz = Class.forName("java.lang.module.Configuration");
|
|
Class<?> resolvedModuleClazz = Class.forName("java.lang.module.ResolvedModule");
|
|
Class<?> moduleReferenceClazz = Class.forName("java.lang.module.ModuleReference");
|
|
Class<?> optionalClazz = Class.forName("java.util.Optional");
|
|
Class<?> versionClazz = Class.forName("java.lang.Runtime$Version");
|
|
Method runtimeVersionMethod = JarFile.class.getMethod("runtimeVersion");
|
|
Method majorMethod = versionClazz.getMethod("major");
|
|
|
|
m2 = SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
|
|
m3 = SSLEngine.class.getMethod("getApplicationProtocol");
|
|
m4 = URLConnection.class.getMethod("setDefaultUseCaches", String.class, boolean.class);
|
|
m5 = moduleLayerClazz.getMethod("boot");
|
|
m6 = moduleLayerClazz.getMethod("configuration");
|
|
m7 = configurationClazz.getMethod("modules");
|
|
m8 = resolvedModuleClazz.getMethod("reference");
|
|
m9 = moduleReferenceClazz.getMethod("location");
|
|
m10 = optionalClazz.getMethod("isPresent");
|
|
m11 = optionalClazz.getMethod("get");
|
|
c12 = JarFile.class.getConstructor(File.class, boolean.class, int.class, versionClazz);
|
|
m13 = JarFile.class.getMethod("isMultiRelease");
|
|
o14 = runtimeVersionMethod.invoke(null);
|
|
o15 = majorMethod.invoke(o14);
|
|
m16 = AccessibleObject.class.getMethod("canAccess", new Class<?>[] { Object.class });
|
|
m17 = Class.class.getMethod("getModule");
|
|
Class<?> moduleClass = Class.forName("java.lang.Module");
|
|
m18 = moduleClass.getMethod("isExported", String.class);
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
if (c1 == null) {
|
|
// Must be pre-Java 9
|
|
log.debug(sm.getString("jre9Compat.javaPre9"), e);
|
|
} else {
|
|
// Should never happen - signature error in lookup?
|
|
log.error(sm.getString("jre9Compat.unexpected"), e);
|
|
}
|
|
} catch (ReflectiveOperationException | IllegalArgumentException e) {
|
|
// Should never happen
|
|
log.error(sm.getString("jre9Compat.unexpected"), e);
|
|
}
|
|
|
|
inaccessibleObjectExceptionClazz = c1;
|
|
setApplicationProtocolsMethod = m2;
|
|
getApplicationProtocolMethod = m3;
|
|
setDefaultUseCachesMethod = m4;
|
|
bootMethod = m5;
|
|
configurationMethod = m6;
|
|
modulesMethod = m7;
|
|
referenceMethod = m8;
|
|
locationMethod = m9;
|
|
isPresentMethod = m10;
|
|
getMethod = m11;
|
|
jarFileConstructor = c12;
|
|
isMultiReleaseMethod = m13;
|
|
|
|
RUNTIME_VERSION = o14;
|
|
if (o15 != null) {
|
|
RUNTIME_MAJOR_VERSION = ((Integer) o15).intValue();
|
|
} else {
|
|
// Must be Java 8
|
|
RUNTIME_MAJOR_VERSION = 8;
|
|
}
|
|
|
|
canAccessMethod = m16;
|
|
getModuleMethod = m17;
|
|
isExportedMethod = m18;
|
|
}
|
|
|
|
|
|
static boolean isSupported() {
|
|
return inaccessibleObjectExceptionClazz != null;
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean isInstanceOfInaccessibleObjectException(Throwable t) {
|
|
if (t == null) {
|
|
return false;
|
|
}
|
|
|
|
return inaccessibleObjectExceptionClazz.isAssignableFrom(t.getClass());
|
|
}
|
|
|
|
|
|
@Override
|
|
public void setApplicationProtocols(SSLParameters sslParameters, String[] protocols) {
|
|
try {
|
|
setApplicationProtocolsMethod.invoke(sslParameters, (Object) protocols);
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
|
throw new UnsupportedOperationException(e);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public String getApplicationProtocol(SSLEngine sslEngine) {
|
|
try {
|
|
return (String) getApplicationProtocolMethod.invoke(sslEngine);
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
|
throw new UnsupportedOperationException(e);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public void disableCachingForJarUrlConnections() throws IOException {
|
|
try {
|
|
setDefaultUseCachesMethod.invoke(null, "JAR", Boolean.FALSE);
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
|
throw new UnsupportedOperationException(e);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public void addBootModulePath(Deque<URL> classPathUrlsToProcess) {
|
|
try {
|
|
Object bootLayer = bootMethod.invoke(null);
|
|
Object bootConfiguration = configurationMethod.invoke(bootLayer);
|
|
Set<?> resolvedModules = (Set<?>) modulesMethod.invoke(bootConfiguration);
|
|
for (Object resolvedModule : resolvedModules) {
|
|
Object moduleReference = referenceMethod.invoke(resolvedModule);
|
|
Object optionalURI = locationMethod.invoke(moduleReference);
|
|
Boolean isPresent = (Boolean) isPresentMethod.invoke(optionalURI);
|
|
if (isPresent.booleanValue()) {
|
|
URI uri = (URI) getMethod.invoke(optionalURI);
|
|
try {
|
|
URL url = uri.toURL();
|
|
classPathUrlsToProcess.add(url);
|
|
} catch (MalformedURLException e) {
|
|
log.warn(sm.getString("jre9Compat.invalidModuleUri", uri), e);
|
|
}
|
|
}
|
|
}
|
|
} catch (ReflectiveOperationException e) {
|
|
throw new UnsupportedOperationException(e);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public JarFile jarFileNewInstance(File f) throws IOException {
|
|
try {
|
|
return jarFileConstructor.newInstance(
|
|
f, Boolean.TRUE, Integer.valueOf(ZipFile.OPEN_READ), RUNTIME_VERSION);
|
|
} catch (ReflectiveOperationException | IllegalArgumentException e) {
|
|
throw new IOException(e);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean jarFileIsMultiRelease(JarFile jarFile) {
|
|
try {
|
|
return ((Boolean) isMultiReleaseMethod.invoke(jarFile)).booleanValue();
|
|
} catch (ReflectiveOperationException | IllegalArgumentException e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public int jarFileRuntimeMajorVersion() {
|
|
return RUNTIME_MAJOR_VERSION;
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean canAcccess(Object base, AccessibleObject accessibleObject) {
|
|
try {
|
|
return ((Boolean) canAccessMethod.invoke(accessibleObject, base)).booleanValue();
|
|
} catch (ReflectiveOperationException | IllegalArgumentException e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean isExported(Class<?> type) {
|
|
try {
|
|
String packageName = type.getPackage().getName();
|
|
Object module = getModuleMethod.invoke(type);
|
|
return ((Boolean) isExportedMethod.invoke(module, packageName)).booleanValue();
|
|
} catch (ReflectiveOperationException e) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|