001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.component.extension.verifier; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashSet; 024import java.util.List; 025import java.util.Map; 026import java.util.Optional; 027import java.util.Set; 028import java.util.TreeSet; 029import java.util.stream.Collectors; 030 031import org.apache.camel.component.extension.ComponentVerifierExtension.VerificationError; 032import org.apache.camel.util.ObjectHelper; 033 034/** 035 * Helper that validates component parameters. 036 */ 037public final class ResultErrorHelper { 038 039 private ResultErrorHelper() { 040 } 041 042 // ********************************** 043 // Helpers 044 // ********************************** 045 046 /** 047 * 048 * @param parameterName the required option 049 * @param parameters the 050 * @return 051 */ 052 public static Optional<VerificationError> requiresOption(String parameterName, Map<String, Object> parameters) { 053 if (ObjectHelper.isEmpty(parameters.get(parameterName))) { 054 return Optional.of(ResultErrorBuilder.withMissingOption(parameterName).build()); 055 } 056 057 return Optional.empty(); 058 } 059 060 /** 061 * Validates that the given parameters satisfy any grouped options 062 * ({@link OptionsGroup}). A parameter set is valid if it is 063 * present and required by least one of the groups. 064 * 065 * <p>As an example consider that there are two option groups that 066 * can be specified: 067 * <ul> 068 * <li>optionA: requires param1 and param2 069 * <li>optionB: requires param1 and param3 070 * </ul> 071 * 072 * Valid parameters are those that include param1 and either param2 073 * and/or param3. 074 * 075 * <p>Note the special syntax of {@link OptionsGroup#getOptions()} 076 * that can require an property ({@code "propertyName"}) or can 077 * forbid the presence of a property ({@code "!propertyName"}). 078 * 079 * <p>With that if in the example above if param2 is specified 080 * specifying param3 is not allowed, and vice versa option groups 081 * should be defined with options: 082 * <ul> 083 * <li>optionA: ["param1", "param2", "!param3"] 084 * <li>optionB: ["param1", "!param2", "param3"] 085 * </ul> 086 * 087 * @param parameters given parameters of a component 088 * @param groups groups of options 089 * @see OptionsGroup 090 */ 091 public static List<VerificationError> requiresAny(Map<String, Object> parameters, OptionsGroup... groups) { 092 return requiresAny(parameters, Arrays.asList(groups)); 093 } 094 095 /** 096 * Validates that the given parameters satisfy any grouped options 097 * ({@link OptionsGroup}). A parameter set is valid if it is 098 * present and required by least one of the groups. 099 * 100 * @param parameters given parameters of a component 101 * @param groups groups of options 102 * @see #requiresAny(Map, OptionsGroup...) 103 * @see OptionsGroup 104 */ 105 public static List<VerificationError> requiresAny(Map<String, Object> parameters, Collection<OptionsGroup> groups) { 106 final List<VerificationError> verificationErrors = new ArrayList<>(); 107 final Set<String> keys = new HashSet<>(parameters.keySet()); 108 109 for (OptionsGroup group : groups) { 110 final Set<String> required = required(group.getOptions()); 111 final Set<String> excluded = excluded(group.getOptions()); 112 113 final ResultErrorBuilder builder = new ResultErrorBuilder() 114 .code(VerificationError.StandardCode.ILLEGAL_PARAMETER_GROUP_COMBINATION) 115 .detail(VerificationError.GroupAttribute.GROUP_NAME, group.getName()) 116 .detail(VerificationError.GroupAttribute.GROUP_OPTIONS, String.join(",", parameters(group.getOptions()))); 117 118 if (keys.containsAll(required)) { 119 // All the options of this group are found so we are good 120 final Set<String> shouldBeExcluded = new HashSet<>(keys); 121 shouldBeExcluded.retainAll(excluded); 122 123 if (shouldBeExcluded.isEmpty()) { 124 // None of the excluded properties is present, also good 125 return Collections.emptyList(); 126 } 127 128 shouldBeExcluded.forEach(builder::parameterKey); 129 verificationErrors.add(builder.build()); 130 } else { 131 132 for (String option : required) { 133 if (!parameters.containsKey(option)) { 134 builder.parameterKey(option); 135 } 136 } 137 138 for (String option : excluded) { 139 if (parameters.containsKey(option)) { 140 builder.parameterKey(option); 141 } 142 } 143 144 verificationErrors.add(builder.build()); 145 } 146 } 147 148 return verificationErrors; 149 } 150 151 static Set<String> required(final Set<String> options) { 152 return options.stream().filter(o -> !o.startsWith("!")).collect(Collectors.toSet()); 153 } 154 155 static Set<String> excluded(final Set<String> options) { 156 return options.stream().filter(o -> o.startsWith("!")).map(o -> o.substring(1)).collect(Collectors.toSet()); 157 } 158 159 static Set<String> parameters(final Set<String> options) { 160 final Set<String> withoutExclusionMark = options.stream().map(o -> o.replaceFirst("!", "")).collect(Collectors.toSet()); 161 162 return new TreeSet<>(withoutExclusionMark); 163 } 164}