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)); }
Profiles contents = parseTokens(expression, tokens, Context.BRACKET); if (context == Context.INVERT) { return 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.INVERT))); break; case ")": Profiles merged = merge(expression, elements, operator); if (context == Context.BRACKET) { return merged; break; default: Profiles value = equals(token); if (context == Context.INVERT) { return value; return merge(expression, elements, operator);
private static Profiles and(Profiles... profiles) { return activeProfile -> Arrays.stream(profiles).allMatch(isMatch(activeProfile)); }
private static Profiles parseTokens(String expression, StringTokenizer tokens) { return parseTokens(expression, tokens, Context.NONE); } private static Profiles parseTokens(String expression, StringTokenizer tokens, Context context) {
static Profiles parse(String... expressions) { Assert.notEmpty(expressions, "Must specify at least one profile"); Profiles[] parsed = new Profiles[expressions.length]; for (int i = 0; i < expressions.length; i++) { parsed[i] = parseExpression(expressions[i]); } return new ParsedProfiles(expressions, parsed); }
/** * Create a new {@link Profiles} instance that checks for matches against * the given <em>profile strings</em>. * <p>The returned instance will {@linkplain Profiles#matches(Predicate) match} * if any one of the given profile strings matches. * <p>A profile string may contain a simple profile name (for example * {@code "production"}) or a profile expression. A profile expression allows * for more complicated profile logic to be expressed, for example * {@code "production & cloud"}. * <p>The following operators are supported in profile expressions: * <ul> * <li>{@code !} - A logical <em>not</em> of the profile</li> * <li>{@code &} - A logical <em>and</em> of the profiles</li> * <li>{@code |} - A logical <em>or</em> of the profiles</li> * </ul> * <p>Please note that the {@code &} and {@code |} operators may not be mixed * without using parentheses. For example {@code "a & b | c"} is not a valid * expression; it must be expressed as {@code "(a & b) | c"} or * {@code "a & (b | c)"}. * @param profiles the <em>profile strings</em> to include * @return a new {@link Profiles} instance */ static Profiles of(String... profiles) { return ProfilesParser.parse(profiles); }
private static Profiles parseTokens(String expression, StringTokenizer tokens) { return parseTokens(expression, tokens, Context.NONE); } private static Profiles parseTokens(String expression, StringTokenizer tokens, Context context) {
static Profiles parse(String... expressions) { Assert.notEmpty(expressions, "Must specify at least one profile"); Profiles[] parsed = new Profiles[expressions.length]; for (int i = 0; i < expressions.length; i++) { parsed[i] = parseExpression(expressions[i]); } return new ParsedProfiles(expressions, parsed); }
/** * Create a new {@link Profiles} instance that checks for matches against * the given <em>profile strings</em>. * <p>The returned instance will {@linkplain Profiles#matches(Predicate) match} * if any one of the given profile strings matches. * <p>A profile string may contain a simple profile name (for example * {@code "production"}) or a profile expression. A profile expression allows * for more complicated profile logic to be expressed, for example * {@code "production & cloud"}. * <p>The following operators are supported in profile expressions: * <ul> * <li>{@code !} - A logical <em>not</em> of the profile</li> * <li>{@code &} - A logical <em>and</em> of the profiles</li> * <li>{@code |} - A logical <em>or</em> of the profiles</li> * </ul> * <p>Please note that the {@code &} and {@code |} operators may not be mixed * without using parentheses. For example {@code "a & b | c"} is not a valid * expression; it must be expressed as {@code "(a & b) | c"} or * {@code "a & (b | c)"}. * @param profiles the <em>profile strings</em> to include * @return a new {@link Profiles} instance */ static Profiles of(String... profiles) { return ProfilesParser.parse(profiles); }
Profiles contents = parseTokens(expression, tokens, Context.BRACKET); if (context == Context.INVERT) { return 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.INVERT))); break; case ")": Profiles merged = merge(expression, elements, operator); if (context == Context.BRACKET) { return merged; break; default: Profiles value = equals(token); if (context == Context.INVERT) { return 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 Profiles or(Profiles... profiles) { return activeProfile -> Arrays.stream(profiles).anyMatch(isMatch(activeProfile)); }
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); }
static Profiles parse(String... expressions) { Assert.notEmpty(expressions, "Must specify at least one profile"); Profiles[] parsed = new Profiles[expressions.length]; for (int i = 0; i < expressions.length; i++) { parsed[i] = parseExpression(expressions[i]); } return new ParsedProfiles(expressions, parsed); }
/** * Create a new {@link Profiles} instance that checks for matches against * the given <em>profile strings</em>. * <p>The returned instance will {@linkplain Profiles#matches(Predicate) match} * if any one of the given profile strings matches. * <p>A profile string may contain a simple profile name (for example * {@code "production"}) or a profile expression. A profile expression allows * for more complicated profile logic to be expressed, for example * {@code "production & cloud"}. * <p>The following operators are supported in profile expressions: * <ul> * <li>{@code !} - A logical <em>not</em> of the profile</li> * <li>{@code &} - A logical <em>and</em> of the profiles</li> * <li>{@code |} - A logical <em>or</em> of the profiles</li> * </ul> * <p>Please note that the {@code &} and {@code |} operators may not be mixed * without using parentheses. For example {@code "a & b | c"} is not a valid * expression; it must be expressed as {@code "(a & b) | c"} or * {@code "a & (b | c)"}. * @param profiles the <em>profile strings</em> to include * @return a new {@link Profiles} instance */ static Profiles of(String... profiles) { return ProfilesParser.parse(profiles); }
elements.add(parseTokens(expression, tokens)); 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))); break; case ")": Profiles merged = merge(expression, elements, operator); elements.clear(); elements.add(merged); break; default: elements.add(equals(token)); 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 Profiles or(Profiles... profiles) { return activeProfile -> Arrays.stream(profiles).anyMatch(isMatch(activeProfile)); }
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); }
static Profiles parse(String... expressions) { Assert.notEmpty(expressions, "Must specify at least one profile"); Profiles[] parsed = new Profiles[expressions.length]; for (int i = 0; i < expressions.length; i++) { parsed[i] = parseExpression(expressions[i]); } return new ParsedProfiles(expressions, parsed); }