Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WFCORE-7108] Add a ModuleIdentifierUtil method to parse a module ide… #6293

Merged
merged 1 commit into from
Dec 23, 2024
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 @@ -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);
}
}
Loading