Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.azure.core.http.policy.RetryStrategy;
import com.azure.core.implementation.accesshelpers.ExponentialBackoffAccessHelper;
import com.azure.core.implementation.accesshelpers.FixedDelayAccessHelper;
import com.azure.core.util.Configuration;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.DateTimeRfc1123;
import com.azure.core.util.FluxUtil;
Expand Down Expand Up @@ -497,6 +498,91 @@ public static <T> T getResultWithTimeout(Future<T> future, long timeoutInMillis)
}
}

/**
* Helper method that safely adds a {@link Runtime#addShutdownHook(Thread)} to the JVM that will run when the JVM is
* shutting down.
* <p>
* {@link Runtime#addShutdownHook(Thread)} checks for security privileges and will throw an exception if the proper
* security isn't available. So, if running with a security manager, setting
* {@code AZURE_ENABLE_SHUTDOWN_HOOK_WITH_PRIVILEGE} to true will have this method use access controller to add
* the shutdown hook with privileged permissions.
* <p>
* If {@code shutdownThread} is null, no shutdown hook will be added and this method will return null.
*
* @param shutdownThread The {@link Thread} that will be added as a
* {@link Runtime#addShutdownHook(Thread) shutdown hook}.
* @return The {@link Thread} that was passed in.
*/
@SuppressWarnings({ "deprecation", "removal" })
public static Thread addShutdownHookSafely(Thread shutdownThread) {
if (shutdownThread == null) {
return null;
}

if (ShutdownHookAccessHelperHolder.shutdownHookAccessHelper) {
java.security.AccessController.doPrivileged((java.security.PrivilegedAction<Void>) () -> {
Runtime.getRuntime().addShutdownHook(shutdownThread);
return null;
});
} else {
Runtime.getRuntime().addShutdownHook(shutdownThread);
}

return shutdownThread;
}

/**
* Helper method that safely removes a {@link Runtime#removeShutdownHook(Thread)} from the JVM.
* <p>
* {@link Runtime#removeShutdownHook(Thread)} checks for security privileges and will throw an exception if the
* proper security isn't available. So, if running with a security manager, setting
* {@code AZURE_ENABLE_SHUTDOWN_HOOK_WITH_PRIVILEGE} to true will have this method use access controller to remove
* the shutdown hook with privileged permissions.
* <p>
* If {@code shutdownThread} is null, no shutdown hook will be removed.
*
* @param shutdownThread The {@link Thread} that will be added as a
* {@link Runtime#addShutdownHook(Thread) shutdown hook}.
*/
@SuppressWarnings({ "deprecation", "removal" })
public static void removeShutdownHookSafely(Thread shutdownThread) {
if (shutdownThread == null) {
return;
}

if (ShutdownHookAccessHelperHolder.shutdownHookAccessHelper) {
java.security.AccessController.doPrivileged((java.security.PrivilegedAction<Void>) () -> {
Runtime.getRuntime().removeShutdownHook(shutdownThread);
return null;
});
} else {
Runtime.getRuntime().removeShutdownHook(shutdownThread);
}
}

/*
* This looks a bit strange but is needed as CoreUtils is used within Configuration code and if this was done in
* the static constructor for CoreUtils it would cause a circular dependency, potentially causing a deadlock.
* Since this is in a static holder class, it will only be loaded when CoreUtils accesses it, which won't happen
* until CoreUtils is loaded.
*/
private static final class ShutdownHookAccessHelperHolder {
private static boolean shutdownHookAccessHelper;

static {
shutdownHookAccessHelper = Boolean
.parseBoolean(Configuration.getGlobalConfiguration().get("AZURE_ENABLE_SHUTDOWN_HOOK_WITH_PRIVILEGE"));
}
}

static boolean isShutdownHookAccessHelper() {
return ShutdownHookAccessHelperHolder.shutdownHookAccessHelper;
}

static void setShutdownHookAccessHelper(boolean shutdownHookAccessHelper) {
ShutdownHookAccessHelperHolder.shutdownHookAccessHelper = shutdownHookAccessHelper;
}

private ImplUtils() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ private String getLocalProperty(String name, Iterable<String> aliases, Function<
return null;
}

private <T> String getWithFallback(ConfigurationProperty<T> property) {
private String getWithFallback(ConfigurationProperty<?> property) {
String name = property.getName();
if (!CoreUtils.isNullOrEmpty(name)) {
String value = getLocalProperty(name, property.getAliases(), property.getValueSanitizer());
Expand All @@ -567,31 +567,28 @@ private <T> String getWithFallback(ConfigurationProperty<T> property) {
}
}
}
return getFromEnvironment(property);
return getFromEnvironment(property.getSystemPropertyName(), property.getEnvironmentVariableName(),
property.getValueSanitizer());
}

private <T> String getFromEnvironment(ConfigurationProperty<T> property) {
String systemProperty = property.getSystemPropertyName();
String getFromEnvironment(String systemProperty, String envVar, Function<String, String> valueSanitizer) {
if (systemProperty != null) {
final String value = environmentConfiguration.getSystemProperty(systemProperty);
if (value != null) {
LOGGER.atVerbose()
.addKeyValue("name", property.getName())
.addKeyValue("systemProperty", systemProperty)
.addKeyValue("value", () -> property.getValueSanitizer().apply(value))
.addKeyValue("value", () -> valueSanitizer.apply(value))
.log("Got property from system property.");
return value;
}
}

String envVar = property.getEnvironmentVariableName();
if (envVar != null) {
final String value = environmentConfiguration.getEnvironmentVariable(envVar);
if (value != null) {
LOGGER.atVerbose()
.addKeyValue("name", property.getName())
.addKeyValue("envVar", envVar)
.addKeyValue("value", () -> property.getValueSanitizer().apply(value))
.addKeyValue("value", () -> valueSanitizer.apply(value))
.log("Got property from environment variable.");
return value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* @param <T> Type of property value.
*/
public final class ConfigurationProperty<T> {
private static final Function<String, String> REDACT_VALUE_SANITIZER = (value) -> "redacted";
static final Function<String, String> REDACT_VALUE_SANITIZER = (value) -> "redacted";

private final String name;
private final List<String> aliases;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,6 @@ public static <T> T getResultWithTimeout(Future<T> future, Duration timeout)
* @throws NullPointerException If {@code shutdownTimeout} is null.
* @throws IllegalArgumentException If {@code shutdownTimeout} is zero or negative.
*/
@SuppressWarnings({ "deprecation", "removal" })
public static ExecutorService addShutdownHookSafely(ExecutorService executorService, Duration shutdownTimeout) {
if (executorService == null) {
return null;
Expand All @@ -620,8 +619,14 @@ public static ExecutorService addShutdownHookSafely(ExecutorService executorServ
throw new IllegalArgumentException("'shutdownTimeout' must be a non-zero positive duration.");
}

CoreUtils.addShutdownHookSafely(createExecutorServiceShutdownThread(executorService, shutdownTimeout));

return executorService;
}

static Thread createExecutorServiceShutdownThread(ExecutorService executorService, Duration shutdownTimeout) {
long timeoutNanos = shutdownTimeout.toNanos();
Thread shutdownThread = new Thread(() -> {
return new Thread(() -> {
try {
executorService.shutdown();
if (!executorService.awaitTermination(timeoutNanos / 2, TimeUnit.NANOSECONDS)) {
Expand All @@ -633,10 +638,6 @@ public static ExecutorService addShutdownHookSafely(ExecutorService executorServ
executorService.shutdown();
}
});

CoreUtils.addShutdownHookSafely(shutdownThread);

return executorService;
}

/**
Expand All @@ -654,22 +655,8 @@ public static ExecutorService addShutdownHookSafely(ExecutorService executorServ
* {@link Runtime#addShutdownHook(Thread) shutdown hook}.
* @return The {@link Thread} that was passed in.
*/
@SuppressWarnings({ "deprecation", "removal" })
public static Thread addShutdownHookSafely(Thread shutdownThread) {
if (shutdownThread == null) {
return null;
}

if (ShutdownHookAccessHelperHolder.shutdownHookAccessHelper) {
java.security.AccessController.doPrivileged((java.security.PrivilegedAction<Void>) () -> {
Runtime.getRuntime().addShutdownHook(shutdownThread);
return null;
});
} else {
Runtime.getRuntime().addShutdownHook(shutdownThread);
}

return shutdownThread;
return ImplUtils.addShutdownHookSafely(shutdownThread);
}

/**
Expand Down Expand Up @@ -800,27 +787,4 @@ public static OffsetDateTime parseBestOffsetDateTime(String dateString) {
return OffsetDateTime.from(temporal);
}
}

/*
* This looks a bit strange but is needed as CoreUtils is used within Configuration code and if this was done in
* the static constructor for CoreUtils it would cause a circular dependency, potentially causing a deadlock.
* Since this is in a static holder class, it will only be loaded when CoreUtils accesses it, which won't happen
* until CoreUtils is loaded.
*/
private static final class ShutdownHookAccessHelperHolder {
private static boolean shutdownHookAccessHelper;

static {
shutdownHookAccessHelper = Boolean
.parseBoolean(Configuration.getGlobalConfiguration().get("AZURE_ENABLE_SHUTDOWN_HOOK_WITH_PRIVILEGE"));
}
}

static boolean isShutdownHookAccessHelper() {
return ShutdownHookAccessHelperHolder.shutdownHookAccessHelper;
}

static void setShutdownHookAccessHelper(boolean shutdownHookAccessHelper) {
ShutdownHookAccessHelperHolder.shutdownHookAccessHelper = shutdownHookAccessHelper;
}
}
Loading