Skip to content

Commit

Permalink
Merge branch 'WFCORE-7108' into ModuleIdentifier_in_API
Browse files Browse the repository at this point in the history
  • Loading branch information
bstansberry committed Dec 22, 2024
2 parents 420f552 + 179a48d commit e5775f4
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*/
package org.jboss.as.controller;

import java.util.function.BiFunction;

import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;

Expand All @@ -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.
* <p/>
* 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 <R> the type returned by {@code function}
*/
public static <R> R parseModuleIdentifier(String moduleIdentifier, BiFunction<String, String, R> 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.
* <p/>
*
* @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 <R> the type returned by {@code function}
*/
public static <R> R parseModuleIdentifier(String moduleIdentifier, BiFunction<String, String, R> 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.
* <p/>
*
* @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 <R> the type returned by {@code function}
*/
public static <R> R parseModuleIdentifier(String moduleIdentifier, BiFunction<String, String, R> 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;
Expand All @@ -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());
}
}

Expand Down Expand Up @@ -151,4 +209,4 @@ private static String escapeSlot(String slot) {

return escaped ? b.toString() : slot;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<String, String> 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<String, String> biFunction(String name, String slot) {
return Map.of(name, slot == null ? "placeholder" : slot);
}
}

0 comments on commit e5775f4

Please sign in to comment.