Skip to content

Commit

Permalink
Support for -XX: options
Browse files Browse the repository at this point in the history
  • Loading branch information
aloubyansky committed Nov 5, 2024
1 parent bf6180f commit a448c4f
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 14 deletions.
2 changes: 1 addition & 1 deletion devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -1498,7 +1498,7 @@ private void addExtensionJvmArgs(ApplicationModel appModel, JvmOptionsBuilder jv
}
debug("Adding JVM options from %s", extDevMode.getExtensionKey());
if (extDevMode.getJvmOptions() != null) {
jvmArgsBuilder.add(extDevMode.getJvmOptions());
jvmArgsBuilder.addAll(extDevMode.getJvmOptions());
if (getLog().isDebugEnabled()) {
for (var arg : extDevMode.getJvmOptions().asCollection()) {
getLog().debug(" " + arg.getName() + ": " + arg.getValues());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ private JvmOptionsBuilder addToGroup(String optionGroupPrefix, String optionName
options = new HashMap<>();
}
var option = options.computeIfAbsent(optionName, n -> {
if (MutableStandardJvmOption.PROPERTY_GROUP_PREFIX.equals(optionGroupPrefix)) {
return MutableStandardJvmOption.newInstance(optionName);
switch (optionGroupPrefix) {
case MutableStandardJvmOption.PROPERTY_GROUP_PREFIX:
return MutableStandardJvmOption.newInstance(optionName);
case MutableXxJvmOption.PROPERTY_GROUP_PREFIX:
return MutableXxJvmOption.newInstance(optionName);
}
throw new IllegalArgumentException("Unrecognized JVM option group prefix " + optionGroupPrefix);
});
Expand All @@ -54,7 +57,7 @@ private JvmOptionsBuilder addToGroup(String optionGroupPrefix, String optionName
}

/**
* Adds an option without a value.
* Adds a standard option without a value.
*
* @param name option name without the starting dashes
* @return this builder instance
Expand All @@ -68,7 +71,7 @@ public JvmOptionsBuilder add(String name) {
}

/**
* Adds an option with a value.
* Adds a standard option with a value.
*
* @param name option name without the starting dashes
* @param value option value, must not be null or black
Expand All @@ -88,7 +91,7 @@ public JvmOptionsBuilder add(String name, String value) {
}

/**
* Adds an option with multiple values.
* Adds a standard option with multiple values.
*
* @param name option name without the starting dashes
* @param values option values
Expand All @@ -105,18 +108,44 @@ public JvmOptionsBuilder addAll(String name, Collection<String> values) {
return this;
}

/**
* Adds a non-standard option that should be prefixed with {@code -XX:} when added to the command line with a value.
*
* @param name option name without the starting dashes
* @param value option value, must not be null or black
* @return this builder instance
*/
public JvmOptionsBuilder addXxOption(String name, String value) {
if (options.isEmpty()) {
options = new HashMap<>();
}
var arg = options.get(name);
if (arg == null) {
options.put(name, MutableXxJvmOption.newInstance(name, value));
} else {
arg.addValue(value);
}
return this;
}

/**
* Adds JVM options with their values.
*
* @param options options to add
* @return this builder instance
*/
public JvmOptionsBuilder add(JvmOptions options) {
public JvmOptionsBuilder addAll(JvmOptions options) {
for (var option : options.asCollection()) {
if (option.hasValue()) {
var existing = this.options.putIfAbsent(option.getName(), (MutableBaseJvmOption<?>) option);
if (existing != null) {
for (var value : option.getValues()) {
existing.addValue(value);
}
}
addAll(option.getName(), option.getValues());
} else {
add(option.getName());
this.options.putIfAbsent(option.getName(), (MutableBaseJvmOption<?>) option);
}
}
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.quarkus.bootstrap.model;

import java.util.List;

import io.quarkus.bootstrap.BootstrapConstants;

public class MutableXxJvmOption extends MutableBaseJvmOption<MutableXxJvmOption> {

public static final String PROPERTY_GROUP_PREFIX = "xx.";

private static final String COMPLETE_PROPERTY_PREFIX = BootstrapConstants.EXT_DEV_MODE_JVM_OPTION_PREFIX
+ PROPERTY_GROUP_PREFIX;

private static final String DASH_XX_COLLON = "-XX:";

public static MutableXxJvmOption fromQuarkusExtensionProperty(String propertyName, String value) {
final String optionName = propertyName.substring(COMPLETE_PROPERTY_PREFIX.length());
return value.isBlank() ? newInstance(optionName) : newInstance(optionName, value);
}

public static MutableXxJvmOption newInstance(String name) {
return newInstance(name, null);
}

public static MutableXxJvmOption newInstance(String name, String value) {
var result = new MutableXxJvmOption();
result.setName(name);
if (value != null) {
result.addValue(value);
}
return result;
}

@Override
protected String getQuarkusExtensionPropertyPrefix() {
return COMPLETE_PROPERTY_PREFIX;
}

@Override
public List<String> toCliOptions() {
if (!hasValue()) {
return toBooleanOption(true);
}
if (getValues().size() == 1) {
var value = getValues().iterator().next();
if ("true".equalsIgnoreCase(value) || "+".equals(value)) {
return toBooleanOption(true);
}
if ("false".equalsIgnoreCase(value) || "-".equals(value)) {
return toBooleanOption(false);
}
return List.of(DASH_XX_COLLON + getName() + "=" + value);
}
throw new IllegalArgumentException(
"Failed to format option " + DASH_XX_COLLON + getName() + " with values " + getValues());
}

private List<String> toBooleanOption(boolean enabled) {
return List.of(DASH_XX_COLLON + (enabled ? "+" : "-") + getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.quarkus.bootstrap.model;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

public class MutableXxJvmOptionTest {

@Test
public void testHasNoValue() {
assertThat(MutableXxJvmOption.newInstance("AllowUserSignalHandlers").hasValue()).isFalse();
}

@Test
public void testHasValue() {
assertThat(MutableXxJvmOption.newInstance("AllowUserSignalHandlers", "true").hasValue()).isTrue();
}

@Test
public void testCliBooleanOptionWithNoValue() {
assertThat(MutableXxJvmOption.newInstance("AllowUserSignalHandlers").toCliOptions())
.containsExactly("-XX:+AllowUserSignalHandlers");
}

@Test
public void testCliBooleanOptionWithTrueValue() {
assertThat(MutableXxJvmOption.newInstance("AllowUserSignalHandlers", "true").toCliOptions())
.containsExactly("-XX:+AllowUserSignalHandlers");
}

@Test
public void testCliBooleanOptionWithFalseValue() {
assertThat(MutableXxJvmOption.newInstance("AllowUserSignalHandlers", "false").toCliOptions())
.containsExactly("-XX:-AllowUserSignalHandlers");
}

@Test
public void testCliOptionWithSingleStringValue() {
assertThat(MutableXxJvmOption.newInstance("ErrorFile", "./hs_err_pid<pid>.log").toCliOptions())
.containsExactly("-XX:ErrorFile=./hs_err_pid<pid>.log");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,14 @@ public void execute() throws MojoExecutionException {
}

private void recordDevModeConfig(Properties props) {
var jvmArgs = devMode == null ? null : devMode.getJvmOptions();
if (devMode == null) {
return;
}
var jvmArgs = devMode.getJvmOptions();
if (jvmArgs != null && !jvmArgs.isEmpty()) {
jvmArgs.setAsExtensionDevModeProperties(props);
}
jvmArgs = devMode.getXxJvmOptions();
if (jvmArgs != null && !jvmArgs.isEmpty()) {
jvmArgs.setAsExtensionDevModeProperties(props);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,41 @@
public class ExtensionDevModeMavenConfig {

private JvmOptionsMap jvmOptions;
private XxJvmOptionsMap xxJvmOptions;

/**
* JVM options that should be added to the command line launching an application in Dev mode.
* Standard JVM options that should be added to the command line launching an application in Dev mode.
*
* @return JVM options that should be added to the command line launching an application in Dev mode
* @return standard JVM options that should be added to the command line launching an application in Dev mode
*/
public JvmOptions getJvmOptions() {
return jvmOptions.builder.build();
return jvmOptions == null ? null : jvmOptions.builder.build();
}

public void setJvmOptions(JvmOptionsMap jvmOptions) {
this.jvmOptions = jvmOptions;
}

/**
* Non-standard JVM options that should be added to the command line launching an application in Dev mode.
*
* @return non-standard JVM options that should be added to the command line launching an application in Dev mode
*/
public JvmOptions getXxJvmOptions() {
return xxJvmOptions == null ? null : xxJvmOptions.builder.build();
}

public void setXxJvmOptions(XxJvmOptionsMap xxJvmOptions) {
this.xxJvmOptions = xxJvmOptions;
}

/**
* This {@link java.util.Map} implementation overrides the {@link java.util.Map#put(Object, Object)} method
* to allow the users configuring a parameter with the same name more than once, merging all the configured values.
*/
public static class JvmOptionsMap extends AbstractMap<String, String> {

private JvmOptionsBuilder builder = JvmOptions.builder();
protected final JvmOptionsBuilder builder = JvmOptions.builder();

public JvmOptionsMap() {
super();
Expand All @@ -56,8 +70,21 @@ public Set<Entry<String, String>> entrySet() {
return map.entrySet();
}

private static String nullOrTrim(Object value) {
static String nullOrTrim(Object value) {
return value == null ? null : String.valueOf(value).trim();
}
}

public static class XxJvmOptionsMap extends JvmOptionsMap {

public XxJvmOptionsMap() {
super();
}

@Override
public String put(String name, String value) {
builder.addXxOption(name, nullOrTrim(value));
return null;
}
}
}

0 comments on commit a448c4f

Please sign in to comment.