/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.impl.verifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; import org.apache.camel.ComponentVerifier.VerificationError; import org.apache.camel.util.ObjectHelper; /** * Helper that validates component parameters. */ public final class ResultErrorHelper { private ResultErrorHelper() { } // ********************************** // Helpers // ********************************** /** * * @param parameterName the required option * @param parameters the * @return */ public static Optional<VerificationError> requiresOption(String parameterName, Map<String, Object> parameters) { if (ObjectHelper.isEmpty(parameters.get(parameterName))) { return Optional.of(ResultErrorBuilder.withMissingOption(parameterName).build()); } return Optional.empty(); } /** * Validates that the given parameters satisfy any grouped options * ({@link OptionsGroup}). A parameter set is valid if it is * present and required by least one of the groups. * * <p>As an example consider that there are two option groups that * can be specified: * <ul> * <li>optionA: requires param1 and param2 * <li>optionB: requires param1 and param3 * </ul> * * Valid parameters are those that include param1 and either param2 * and/or param3. * * <p>Note the special syntax of {@link OptionsGroup#getOptions()} * that can require an property ({@code "propertyName"}) or can * forbid the presence of a property ({@code "!propertyName"}). * * <p>With that if in the example above if param2 is specified * specifying param3 is not allowed, and vice versa option groups * should be defined with options: * <ul> * <li>optionA: ["param1", "param2", "!param3"] * <li>optionB: ["param1", "!param2", "param3"] * </ul> * * @param parameters given parameters of a component * @param groups groups of options * @see OptionsGroup */ public static List<VerificationError> requiresAny(Map<String, Object> parameters, OptionsGroup... groups) { return requiresAny(parameters, Arrays.asList(groups)); } /** * Validates that the given parameters satisfy any grouped options * ({@link OptionsGroup}). A parameter set is valid if it is * present and required by least one of the groups. * * @param parameters given parameters of a component * @param groups groups of options * @see #requiresAny(Map, OptionsGroup...) * @see OptionsGroup */ public static List<VerificationError> requiresAny(Map<String, Object> parameters, Collection<OptionsGroup> groups) { final List<VerificationError> verificationErrors = new ArrayList<>(); final Set<String> keys = new HashSet<>(parameters.keySet()); for (OptionsGroup group : groups) { final Set<String> required = required(group.getOptions()); final Set<String> excluded = excluded(group.getOptions()); final ResultErrorBuilder builder = new ResultErrorBuilder() .code(VerificationError.StandardCode.ILLEGAL_PARAMETER_GROUP_COMBINATION) .detail(VerificationError.GroupAttribute.GROUP_NAME, group.getName()) .detail(VerificationError.GroupAttribute.GROUP_OPTIONS, String.join(",", parameters(group.getOptions()))); if (keys.containsAll(required)) { // All the options of this group are found so we are good final Set<String> shouldBeExcluded = new HashSet<>(keys); shouldBeExcluded.retainAll(excluded); if (shouldBeExcluded.isEmpty()) { // None of the excluded properties is present, also good return Collections.emptyList(); } shouldBeExcluded.forEach(builder::parameterKey); verificationErrors.add(builder.build()); } else { for (String option : required) { if (!parameters.containsKey(option)) { builder.parameterKey(option); } } for (String option : excluded) { if (parameters.containsKey(option)) { builder.parameterKey(option); } } verificationErrors.add(builder.build()); } } return verificationErrors; } static Set<String> required(final Set<String> options) { return options.stream().filter(o -> !o.startsWith("!")).collect(Collectors.toSet()); } static Set<String> excluded(final Set<String> options) { return options.stream().filter(o -> o.startsWith("!")).map(o -> o.substring(1)).collect(Collectors.toSet()); } static Set<String> parameters(final Set<String> options) { final Set<String> withoutExclusionMark = options.stream().map(o -> o.replaceFirst("!", "")).collect(Collectors.toSet()); return new TreeSet<String>(withoutExclusionMark); } }