Skip to content

Commit

Permalink
Update ProfilesParser.java
Browse files Browse the repository at this point in the history
  • Loading branch information
mercyblitz committed Dec 27, 2024
1 parent 42c866f commit 86884d6
Showing 1 changed file with 153 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import java.util.StringTokenizer;
import java.util.function.Predicate;

import static io.microsphere.util.Assert.assertNotEmpty;
import static io.microsphere.util.Assert.assertTrue;

/**
* Internal parser used by {@link Profiles#of}.
*
Expand All @@ -38,157 +41,156 @@
*/
final class ProfilesParser {

private ProfilesParser() {
}


static Profiles parse(String... expressions) {
Assert.notEmpty(expressions, "Must specify at least one profile expression");
Profiles[] parsed = new Profiles[expressions.length];
for (int i = 0; i < expressions.length; i++) {
parsed[i] = parseExpression(expressions[i]);
}
return new ParsedProfiles(expressions, parsed);
}

private static Profiles parseExpression(String expression) {
Assert.hasText(expression, () -> "Invalid profile expression [" + expression + "]: must contain text");
StringTokenizer tokens = new StringTokenizer(expression, "()&|!", true);
return parseTokens(expression, tokens);
}

private static Profiles parseTokens(String expression, StringTokenizer tokens) {
return parseTokens(expression, tokens, Context.NONE);
}

private static Profiles parseTokens(String expression, StringTokenizer tokens, Context context) {
List<Profiles> elements = new ArrayList<>();
Operator operator = null;
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
if (token.isEmpty()) {
continue;
}
switch (token) {
case "(":
Profiles contents = parseTokens(expression, tokens, Context.PARENTHESIS);
if (context == Context.NEGATE) {
return contents;
}
elements.add(contents);
break;
case "&":
assertWellFormed(expression, operator == null || operator == Operator.AND);
operator = Operator.AND;
break;
case "|":
assertWellFormed(expression, operator == null || operator == Operator.OR);
operator = Operator.OR;
break;
case "!":
elements.add(not(parseTokens(expression, tokens, Context.NEGATE)));
break;
case ")":
Profiles merged = merge(expression, elements, operator);
if (context == Context.PARENTHESIS) {
return merged;
}
elements.clear();
elements.add(merged);
operator = null;
break;
default:
Profiles value = equals(token);
if (context == Context.NEGATE) {
return value;
}
elements.add(value);
}
}
return merge(expression, elements, operator);
}

private static Profiles merge(String expression, List<Profiles> elements, @Nullable Operator operator) {
assertWellFormed(expression, !elements.isEmpty());
if (elements.size() == 1) {
return elements.get(0);
}
Profiles[] profiles = elements.toArray(new Profiles[0]);
return (operator == Operator.AND ? and(profiles) : or(profiles));
}

private static void assertWellFormed(String expression, boolean wellFormed) {
Assert.isTrue(wellFormed, () -> "Malformed profile expression [" + expression + "]");
}

private static Profiles or(Profiles... profiles) {
return activeProfile -> Arrays.stream(profiles).anyMatch(isMatch(activeProfile));
}

private static Profiles and(Profiles... profiles) {
return activeProfile -> Arrays.stream(profiles).allMatch(isMatch(activeProfile));
}

private static Profiles not(Profiles profiles) {
return activeProfile -> !profiles.matches(activeProfile);
}

private static Profiles equals(String profile) {
return activeProfile -> activeProfile.test(profile);
}

private static Predicate<Profiles> isMatch(Predicate<String> activeProfiles) {
return profiles -> profiles.matches(activeProfiles);
}


private enum Operator { AND, OR }

private enum Context { NONE, NEGATE, PARENTHESIS }


private static class ParsedProfiles implements Profiles {

private final Set<String> expressions = new LinkedHashSet<>();

private final Profiles[] parsed;

ParsedProfiles(String[] expressions, Profiles[] parsed) {
Collections.addAll(this.expressions, expressions);
this.parsed = parsed;
}

@Override
public boolean matches(Predicate<String> activeProfiles) {
for (Profiles candidate : this.parsed) {
if (candidate.matches(activeProfiles)) {
return true;
private ProfilesParser() {
}

static Profiles parse(String... expressions) {
assertNotEmpty(expressions, "Must specify at least one profile expression");
Profiles[] parsed = new Profiles[expressions.length];
for (int i = 0; i < expressions.length; i++) {
parsed[i] = parseExpression(expressions[i]);
}
return new ParsedProfiles(expressions, parsed);
}

private static Profiles parseExpression(String expression) {
assertNotEmpty(expression, () -> "Invalid profile expression [" + expression + "]: must contain text");
StringTokenizer tokens = new StringTokenizer(expression, "()&|!", true);
return parseTokens(expression, tokens);
}

private static Profiles parseTokens(String expression, StringTokenizer tokens) {
return parseTokens(expression, tokens, Context.NONE);
}

private static Profiles parseTokens(String expression, StringTokenizer tokens, Context context) {
List<Profiles> elements = new ArrayList<>();
Operator operator = null;
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().trim();
if (token.isEmpty()) {
continue;
}
switch (token) {
case "(":
Profiles contents = parseTokens(expression, tokens, Context.PARENTHESIS);
if (context == Context.NEGATE) {
return contents;
}
elements.add(contents);
break;
case "&":
assertWellFormed(expression, operator == null || operator == Operator.AND);
operator = Operator.AND;
break;
case "|":
assertWellFormed(expression, operator == null || operator == Operator.OR);
operator = Operator.OR;
break;
case "!":
elements.add(not(parseTokens(expression, tokens, Context.NEGATE)));
break;
case ")":
Profiles merged = merge(expression, elements, operator);
if (context == Context.PARENTHESIS) {
return merged;
}
elements.clear();
elements.add(merged);
operator = null;
break;
default:
Profiles value = equals(token);
if (context == Context.NEGATE) {
return value;
}
elements.add(value);
}
}
return merge(expression, elements, operator);
}

private static Profiles merge(String expression, List<Profiles> elements, @Nullable Operator operator) {
assertWellFormed(expression, !elements.isEmpty());
if (elements.size() == 1) {
return elements.get(0);
}
Profiles[] profiles = elements.toArray(new Profiles[0]);
return (operator == Operator.AND ? and(profiles) : or(profiles));
}

private static void assertWellFormed(String expression, boolean wellFormed) {
assertTrue(wellFormed, () -> "Malformed profile expression [" + expression + "]");
}

private static Profiles or(Profiles... profiles) {
return activeProfile -> Arrays.stream(profiles).anyMatch(isMatch(activeProfile));
}

private static Profiles and(Profiles... profiles) {
return activeProfile -> Arrays.stream(profiles).allMatch(isMatch(activeProfile));
}

private static Profiles not(Profiles profiles) {
return activeProfile -> !profiles.matches(activeProfile);
}

private static Profiles equals(String profile) {
return activeProfile -> activeProfile.test(profile);
}

private static Predicate<Profiles> isMatch(Predicate<String> activeProfiles) {
return profiles -> profiles.matches(activeProfiles);
}


private enum Operator {AND, OR}

private enum Context {NONE, NEGATE, PARENTHESIS}


private static class ParsedProfiles implements Profiles {

private final Set<String> expressions = new LinkedHashSet<>();

private final Profiles[] parsed;

ParsedProfiles(String[] expressions, Profiles[] parsed) {
Collections.addAll(this.expressions, expressions);
this.parsed = parsed;
}

@Override
public boolean matches(Predicate<String> activeProfiles) {
for (Profiles candidate : this.parsed) {
if (candidate.matches(activeProfiles)) {
return true;
}
}
return false;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ParsedProfiles that = (ParsedProfiles) obj;
return this.expressions.equals(that.expressions);
}

@Override
public int hashCode() {
return this.expressions.hashCode();
}

@Override
public String toString() {
return StringUtils.collectionToDelimitedString(this.expressions, " or ");
}
}
}
return false;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ParsedProfiles that = (ParsedProfiles) obj;
return this.expressions.equals(that.expressions);
}

@Override
public int hashCode() {
return this.expressions.hashCode();
}

@Override
public String toString() {
return StringUtils.collectionToDelimitedString(this.expressions, " or ");
}
}

}

0 comments on commit 86884d6

Please sign in to comment.