diff --git a/controller/src/main/java/org/jboss/as/controller/ModuleIdentifierUtil.java b/controller/src/main/java/org/jboss/as/controller/ModuleIdentifierUtil.java
index 9ae22bcd0ce..b9cc81f6c62 100644
--- a/controller/src/main/java/org/jboss/as/controller/ModuleIdentifierUtil.java
+++ b/controller/src/main/java/org/jboss/as/controller/ModuleIdentifierUtil.java
@@ -4,6 +4,8 @@
*/
package org.jboss.as.controller;
+import java.util.function.BiFunction;
+
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
@@ -21,32 +23,88 @@ public final class ModuleIdentifierUtil {
* @return the canonical representation. Will not return @{code null}
*/
public static String canonicalModuleIdentifier(String moduleSpec) {
+ return parseModuleIdentifier(moduleSpec, ModuleIdentifierUtil::canonicalModuleIdentifier);
+ }
+
+ /**
+ * Parses the given module identifier into name and optional slot elements, passing those to the given
+ * function and returning the result of that function.
+ *
+ * This variant does not {@link #canonicalModuleIdentifier(String) canonicalize} the given identifier.
+ *
+ * @param moduleIdentifier an identifier for a module. Cannot be {@code null}
+ * @param function a function to apply to the module's name and optional slot. Cannot be {@code null}.
+ * The slot value passed to the function may be null if the identifier does not contain one.
+ * @return the value returned by {@code function}
+ * @param the type returned by {@code function}
+ */
+ public static R parseModuleIdentifier(String moduleIdentifier, BiFunction function) {
+ return parseModuleIdentifier(moduleIdentifier, function, false, null);
+ }
+
+
+ /**
+ * Parses the given module identifier into name and optional slot elements, passing those to the given
+ * function and returning the result of that function.
+ *
+ *
+ * @param moduleIdentifier an identifier for a module. Cannot be {@code null}
+ * @param function a function to apply to the module's name and optional slot. Cannot be {@code null}.
+ * The slot value passed to the function may be null if the identifier does not contain one.
+ * @param canonicalize if {@code true} the identifier will be {@link #canonicalModuleIdentifier(String) canonicalized} before parsing
+ * @return the value returned by {@code function}
+ * @param the type returned by {@code function}
+ */
+ public static R parseModuleIdentifier(String moduleIdentifier, BiFunction function, boolean canonicalize) {
+ return parseModuleIdentifier(moduleIdentifier, function, canonicalize, null);
+ }
+
+
+ /**
+ * Parses the given module identifier into name and optional slot elements, passing those to the given
+ * function and returning the result of that function.
+ *
+ *
+ * @param moduleIdentifier an identifier for a module. Cannot be {@code null}
+ * @param function a function to apply to the module's name and optional slot. Cannot be {@code null}.
+ * The slot value passed to the function may be null if the identifier does not contain one.
+ * @param canonicalize if {@code true} the identifier will be {@link #canonicalModuleIdentifier(String) canonicalized} before parsing
+ * @param defaultSlot string to pass to {@code function} as the slot parameter if the identifier doesn't include a slot value. May be {@code null}
+ * @return the value returned by {@code function}
+ * @param the type returned by {@code function}
+ */
+ public static R parseModuleIdentifier(String moduleIdentifier, BiFunction function,
+ boolean canonicalize, String defaultSlot) {
+ if (canonicalize) {
+ moduleIdentifier = canonicalModuleIdentifier(moduleIdentifier);
+ }
+
// Note: this is taken from org.jboss.modules.ModuleIdentifier.fromString and lightly adapted.
- if (moduleSpec == null) {
+ if (moduleIdentifier == null) {
throw new IllegalArgumentException("Module specification is null");
- } else if (moduleSpec.isEmpty()) {
+ } else if (moduleIdentifier.isEmpty()) {
throw new IllegalArgumentException("Empty module specification");
} else {
StringBuilder b = new StringBuilder();
int c;
int i;
- for(i = 0; i < moduleSpec.length(); i = moduleSpec.offsetByCodePoints(i, 1)) {
- c = moduleSpec.codePointAt(i);
+ for(i = 0; i < moduleIdentifier.length(); i = moduleIdentifier.offsetByCodePoints(i, 1)) {
+ c = moduleIdentifier.codePointAt(i);
if (c == 92) {
b.appendCodePoint(c);
- i = moduleSpec.offsetByCodePoints(i, 1);
- if (i >= moduleSpec.length()) {
+ i = moduleIdentifier.offsetByCodePoints(i, 1);
+ if (i >= moduleIdentifier.length()) {
throw new IllegalArgumentException("Name has an unterminated escape");
}
- c = moduleSpec.codePointAt(i);
+ c = moduleIdentifier.codePointAt(i);
b.appendCodePoint(c);
} else {
if (c == 58) {
- i = moduleSpec.offsetByCodePoints(i, 1);
- if (i == moduleSpec.length()) {
+ i = moduleIdentifier.offsetByCodePoints(i, 1);
+ if (i == moduleIdentifier.length()) {
throw new IllegalArgumentException("Slot is empty");
}
break;
@@ -58,16 +116,16 @@ public static String canonicalModuleIdentifier(String moduleSpec) {
String name = b.toString();
b.setLength(0);
- if (i >= moduleSpec.length()) {
- return canonicalModuleIdentifier(name, null);
+ if (i >= moduleIdentifier.length()) {
+ return function.apply(name, defaultSlot);
} else {
do {
- c = moduleSpec.codePointAt(i);
+ c = moduleIdentifier.codePointAt(i);
b.appendCodePoint(c);
- i = moduleSpec.offsetByCodePoints(i, 1);
- } while(i < moduleSpec.length());
+ i = moduleIdentifier.offsetByCodePoints(i, 1);
+ } while(i < moduleIdentifier.length());
- return canonicalModuleIdentifier(name, b.toString());
+ return function.apply(name, b.toString());
}
}
@@ -151,4 +209,4 @@ private static String escapeSlot(String slot) {
return escaped ? b.toString() : slot;
}
-}
+}
\ No newline at end of file
diff --git a/controller/src/test/java/org/jboss/as/controller/ModuleIdentifierUtilUnitTestCase.java b/controller/src/test/java/org/jboss/as/controller/ModuleIdentifierUtilUnitTestCase.java
new file mode 100644
index 00000000000..6f9243c5197
--- /dev/null
+++ b/controller/src/test/java/org/jboss/as/controller/ModuleIdentifierUtilUnitTestCase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.jboss.as.controller;
+
+import static org.jboss.as.controller.ModuleIdentifierUtil.canonicalModuleIdentifier;
+import static org.jboss.as.controller.ModuleIdentifierUtil.parseModuleIdentifier;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+/**
+ * Unit tests of {@link ModuleIdentifierUtil}.
+ */
+public class ModuleIdentifierUtilUnitTestCase {
+
+ @Test
+ public void testParsingCanonicalization() {
+ assertEquals("org.jboss.foo", canonicalModuleIdentifier("org.jboss.foo"));
+ assertEquals("org.jboss.foo", canonicalModuleIdentifier("org.jboss.foo:main"));
+ assertEquals("org.jboss.foo:bar", canonicalModuleIdentifier("org.jboss.foo:bar"));
+ // TODO these next two seem wrong, but it's what ModuleIdentifier.fromString(...).toString() does
+ assertEquals("org.jboss\\\\\\:foo", canonicalModuleIdentifier("org.jboss\\:foo"));
+ assertEquals("org.jboss\\\\\\:foo:bar", canonicalModuleIdentifier("org.jboss\\:foo:bar"));
+ }
+
+ @Test
+ public void testAppendingCanonicalization() {
+ assertEquals("org.jboss.foo", canonicalModuleIdentifier("org.jboss.foo", null));
+ assertEquals("org.jboss.foo", canonicalModuleIdentifier("org.jboss.foo", "main"));
+ assertEquals("org.jboss.foo:bar", canonicalModuleIdentifier("org.jboss.foo", "bar"));
+ // TODO these next two seem wrong, but it's what ModuleIdentifier.create(...).toString() does
+ assertEquals("org.jboss\\\\\\:foo", canonicalModuleIdentifier("org.jboss\\:foo", null));
+ assertEquals("org.jboss\\\\\\:foo:bar", canonicalModuleIdentifier("org.jboss\\:foo", "bar"));
+ }
+
+ @Test
+ public void testParsingToFunction() {
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo", ModuleIdentifierUtilUnitTestCase::biFunction),
+ null);
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo:main", ModuleIdentifierUtilUnitTestCase::biFunction),
+ "main");
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo:main", ModuleIdentifierUtilUnitTestCase::biFunction, false),
+ "main");
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo:main", ModuleIdentifierUtilUnitTestCase::biFunction, true),
+ null);
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo:main", ModuleIdentifierUtilUnitTestCase::biFunction, false, "bar"),
+ "main");
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo:main", ModuleIdentifierUtilUnitTestCase::biFunction, true, "bar"),
+ "bar");
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo", ModuleIdentifierUtilUnitTestCase::biFunction, false, "bar"),
+ "bar");
+
+ validateFunctionResult(
+ parseModuleIdentifier("org.jboss.foo", ModuleIdentifierUtilUnitTestCase::biFunction, true, "bar"),
+ "bar");
+ }
+
+ private static void validateFunctionResult(Map result, String expectedSlot) {
+ assertNotNull(result.toString(), result);
+ assertEquals(result.toString(), 1, result.size());
+ assertTrue(result.toString(), result.containsKey("org.jboss.foo"));
+ assertEquals(result.toString(), expectedSlot == null ? "placeholder" : expectedSlot, result.get("org.jboss.foo"));
+ }
+
+ private static Map biFunction(String name, String slot) {
+ return Map.of(name, slot == null ? "placeholder" : slot);
+ }
+}