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.runtimecatalog; 018 019import java.io.Serializable; 020import java.util.Arrays; 021import java.util.Collections; 022import java.util.LinkedHashMap; 023import java.util.LinkedHashSet; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027 028import static org.apache.camel.runtimecatalog.URISupport.isEmpty; 029 030/** 031 * Details result of validating endpoint uri. 032 */ 033public class EndpointValidationResult implements Serializable { 034 035 private final String uri; 036 private int errors; 037 038 // general 039 private String syntaxError; 040 private String unknownComponent; 041 private String incapable; 042 043 // options 044 private Set<String> unknown; 045 private Map<String, String[]> unknownSuggestions; 046 private Set<String> lenient; 047 private Set<String> notConsumerOnly; 048 private Set<String> notProducerOnly; 049 private Set<String> required; 050 private Map<String, String> invalidEnum; 051 private Map<String, String[]> invalidEnumChoices; 052 private Map<String, String[]> invalidEnumSuggestions; 053 private Map<String, String> invalidReference; 054 private Map<String, String> invalidBoolean; 055 private Map<String, String> invalidInteger; 056 private Map<String, String> invalidNumber; 057 private Map<String, String> defaultValues; 058 059 public EndpointValidationResult() { 060 this(null); 061 } 062 063 public EndpointValidationResult(String uri) { 064 this.uri = uri; 065 } 066 067 public String getUri() { 068 return uri; 069 } 070 071 public boolean hasErrors() { 072 return errors > 0; 073 } 074 075 public int getNumberOfErrors() { 076 return errors; 077 } 078 079 public boolean isSuccess() { 080 boolean ok = syntaxError == null && unknownComponent == null && incapable == null 081 && unknown == null && required == null; 082 if (ok) { 083 ok = notConsumerOnly == null && notProducerOnly == null; 084 } 085 if (ok) { 086 ok = invalidEnum == null && invalidEnumChoices == null && invalidReference == null 087 && invalidBoolean == null && invalidInteger == null && invalidNumber == null; 088 } 089 return ok; 090 } 091 092 public void addSyntaxError(String syntaxError) { 093 this.syntaxError = syntaxError; 094 errors++; 095 } 096 097 public void addIncapable(String uri) { 098 this.incapable = uri; 099 errors++; 100 } 101 102 public void addUnknownComponent(String name) { 103 this.unknownComponent = name; 104 errors++; 105 } 106 107 public void addUnknown(String name) { 108 if (unknown == null) { 109 unknown = new LinkedHashSet<String>(); 110 } 111 if (!unknown.contains(name)) { 112 unknown.add(name); 113 errors++; 114 } 115 } 116 117 public void addUnknownSuggestions(String name, String[] suggestions) { 118 if (unknownSuggestions == null) { 119 unknownSuggestions = new LinkedHashMap<String, String[]>(); 120 } 121 unknownSuggestions.put(name, suggestions); 122 } 123 124 public void addLenient(String name) { 125 if (lenient == null) { 126 lenient = new LinkedHashSet<String>(); 127 } 128 if (!lenient.contains(name)) { 129 lenient.add(name); 130 } 131 } 132 133 public void addRequired(String name) { 134 if (required == null) { 135 required = new LinkedHashSet<String>(); 136 } 137 if (!required.contains(name)) { 138 required.add(name); 139 errors++; 140 } 141 } 142 143 public void addInvalidEnum(String name, String value) { 144 if (invalidEnum == null) { 145 invalidEnum = new LinkedHashMap<String, String>(); 146 } 147 if (!invalidEnum.containsKey(name)) { 148 invalidEnum.put(name, value); 149 errors++; 150 } 151 } 152 153 public void addInvalidEnumChoices(String name, String[] choices) { 154 if (invalidEnumChoices == null) { 155 invalidEnumChoices = new LinkedHashMap<String, String[]>(); 156 } 157 invalidEnumChoices.put(name, choices); 158 } 159 160 public void addInvalidEnumSuggestions(String name, String[] suggestions) { 161 if (invalidEnumSuggestions == null) { 162 invalidEnumSuggestions = new LinkedHashMap<String, String[]>(); 163 } 164 invalidEnumSuggestions.put(name, suggestions); 165 } 166 167 public void addInvalidReference(String name, String value) { 168 if (invalidReference == null) { 169 invalidReference = new LinkedHashMap<String, String>(); 170 } 171 if (!invalidReference.containsKey(name)) { 172 invalidReference.put(name, value); 173 errors++; 174 } 175 } 176 177 public void addInvalidBoolean(String name, String value) { 178 if (invalidBoolean == null) { 179 invalidBoolean = new LinkedHashMap<String, String>(); 180 } 181 if (!invalidBoolean.containsKey(name)) { 182 invalidBoolean.put(name, value); 183 errors++; 184 } 185 } 186 187 public void addInvalidInteger(String name, String value) { 188 if (invalidInteger == null) { 189 invalidInteger = new LinkedHashMap<String, String>(); 190 } 191 if (!invalidInteger.containsKey(name)) { 192 invalidInteger.put(name, value); 193 errors++; 194 } 195 } 196 197 public void addInvalidNumber(String name, String value) { 198 if (invalidNumber == null) { 199 invalidNumber = new LinkedHashMap<String, String>(); 200 } 201 if (!invalidNumber.containsKey(name)) { 202 invalidNumber.put(name, value); 203 errors++; 204 } 205 } 206 207 public void addDefaultValue(String name, String value) { 208 if (defaultValues == null) { 209 defaultValues = new LinkedHashMap<String, String>(); 210 } 211 defaultValues.put(name, value); 212 } 213 214 public void addNotConsumerOnly(String name) { 215 if (notConsumerOnly == null) { 216 notConsumerOnly = new LinkedHashSet<String>(); 217 } 218 if (!notConsumerOnly.contains(name)) { 219 notConsumerOnly.add(name); 220 errors++; 221 } 222 } 223 224 public void addNotProducerOnly(String name) { 225 if (notProducerOnly == null) { 226 notProducerOnly = new LinkedHashSet<String>(); 227 } 228 if (!notProducerOnly.contains(name)) { 229 notProducerOnly.add(name); 230 errors++; 231 } 232 } 233 234 public String getSyntaxError() { 235 return syntaxError; 236 } 237 238 public String getIncapable() { 239 return incapable; 240 } 241 242 public Set<String> getUnknown() { 243 return unknown; 244 } 245 246 public Set<String> getLenient() { 247 return lenient; 248 } 249 250 public Map<String, String[]> getUnknownSuggestions() { 251 return unknownSuggestions; 252 } 253 254 public String getUnknownComponent() { 255 return unknownComponent; 256 } 257 258 public Set<String> getRequired() { 259 return required; 260 } 261 262 public Map<String, String> getInvalidEnum() { 263 return invalidEnum; 264 } 265 266 public Map<String, String[]> getInvalidEnumChoices() { 267 return invalidEnumChoices; 268 } 269 270 public List<String> getEnumChoices(String optionName) { 271 if (invalidEnumChoices != null) { 272 String[] enums = invalidEnumChoices.get(optionName); 273 if (enums != null) { 274 return Arrays.asList(enums); 275 } 276 } 277 278 return Collections.emptyList(); 279 } 280 281 public Map<String, String> getInvalidReference() { 282 return invalidReference; 283 } 284 285 public Map<String, String> getInvalidBoolean() { 286 return invalidBoolean; 287 } 288 289 public Map<String, String> getInvalidInteger() { 290 return invalidInteger; 291 } 292 293 public Map<String, String> getInvalidNumber() { 294 return invalidNumber; 295 } 296 297 public Map<String, String> getDefaultValues() { 298 return defaultValues; 299 } 300 301 public Set<String> getNotConsumerOnly() { 302 return notConsumerOnly; 303 } 304 305 public Set<String> getNotProducerOnly() { 306 return notProducerOnly; 307 } 308 309 /** 310 * A human readable summary of the validation errors. 311 * 312 * @param includeHeader whether to include a header 313 * @return the summary, or <tt>null</tt> if no validation errors 314 */ 315 public String summaryErrorMessage(boolean includeHeader) { 316 if (isSuccess()) { 317 return null; 318 } 319 320 if (incapable != null) { 321 return "\tIncapable of parsing uri: " + incapable; 322 } else if (syntaxError != null) { 323 return "\tSyntax error: " + syntaxError; 324 } else if (unknownComponent != null) { 325 return "\tUnknown component: " + unknownComponent; 326 } 327 328 // for each invalid option build a reason message 329 Map<String, String> options = new LinkedHashMap<String, String>(); 330 if (unknown != null) { 331 for (String name : unknown) { 332 if (unknownSuggestions != null && unknownSuggestions.containsKey(name)) { 333 String[] suggestions = unknownSuggestions.get(name); 334 if (suggestions != null && suggestions.length > 0) { 335 String str = Arrays.asList(suggestions).toString(); 336 options.put(name, "Unknown option. Did you mean: " + str); 337 } else { 338 options.put(name, "Unknown option"); 339 } 340 } else { 341 options.put(name, "Unknown option"); 342 } 343 } 344 } 345 if (notConsumerOnly != null) { 346 for (String name : notConsumerOnly) { 347 options.put(name, "Option not applicable in consumer only mode"); 348 } 349 } 350 if (notProducerOnly != null) { 351 for (String name : notProducerOnly) { 352 options.put(name, "Option not applicable in producer only mode"); 353 } 354 } 355 if (required != null) { 356 for (String name : required) { 357 options.put(name, "Missing required option"); 358 } 359 } 360 if (invalidEnum != null) { 361 for (Map.Entry<String, String> entry : invalidEnum.entrySet()) { 362 String name = entry.getKey(); 363 String[] choices = invalidEnumChoices.get(name); 364 String defaultValue = defaultValues != null ? defaultValues.get(entry.getKey()) : null; 365 String str = Arrays.asList(choices).toString(); 366 String msg = "Invalid enum value: " + entry.getValue() + ". Possible values: " + str; 367 if (invalidEnumSuggestions != null) { 368 String[] suggestions = invalidEnumSuggestions.get(name); 369 if (suggestions != null && suggestions.length > 0) { 370 str = Arrays.asList(suggestions).toString(); 371 msg += ". Did you mean: " + str; 372 } 373 } 374 if (defaultValue != null) { 375 msg += ". Default value: " + defaultValue; 376 } 377 378 options.put(entry.getKey(), msg); 379 } 380 } 381 if (invalidReference != null) { 382 for (Map.Entry<String, String> entry : invalidReference.entrySet()) { 383 boolean empty = isEmpty(entry.getValue()); 384 if (empty) { 385 options.put(entry.getKey(), "Empty reference value"); 386 } else if (!entry.getValue().startsWith("#")) { 387 options.put(entry.getKey(), "Invalid reference value: " + entry.getValue() + " must start with #"); 388 } else { 389 options.put(entry.getKey(), "Invalid reference value: " + entry.getValue()); 390 } 391 } 392 } 393 if (invalidBoolean != null) { 394 for (Map.Entry<String, String> entry : invalidBoolean.entrySet()) { 395 boolean empty = isEmpty(entry.getValue()); 396 if (empty) { 397 options.put(entry.getKey(), "Empty boolean value"); 398 } else { 399 options.put(entry.getKey(), "Invalid boolean value: " + entry.getValue()); 400 } 401 } 402 } 403 if (invalidInteger != null) { 404 for (Map.Entry<String, String> entry : invalidInteger.entrySet()) { 405 boolean empty = isEmpty(entry.getValue()); 406 if (empty) { 407 options.put(entry.getKey(), "Empty integer value"); 408 } else { 409 options.put(entry.getKey(), "Invalid integer value: " + entry.getValue()); 410 } 411 } 412 } 413 if (invalidNumber != null) { 414 for (Map.Entry<String, String> entry : invalidNumber.entrySet()) { 415 boolean empty = isEmpty(entry.getValue()); 416 if (empty) { 417 options.put(entry.getKey(), "Empty number value"); 418 } else { 419 options.put(entry.getKey(), "Invalid number value: " + entry.getValue()); 420 } 421 } 422 } 423 424 // build a table with the error summary nicely formatted 425 // lets use 24 as min length 426 int maxLen = 24; 427 for (String key : options.keySet()) { 428 maxLen = Math.max(maxLen, key.length()); 429 } 430 String format = "%" + maxLen + "s %s"; 431 432 // build the human error summary 433 StringBuilder sb = new StringBuilder(); 434 if (includeHeader) { 435 sb.append("Endpoint validator error\n"); 436 sb.append("---------------------------------------------------------------------------------------------------------------------------------------\n"); 437 sb.append("\n"); 438 } 439 if (uri != null) { 440 sb.append("\t").append(uri).append("\n"); 441 } else { 442 sb.append("\n"); 443 } 444 for (Map.Entry<String, String> option : options.entrySet()) { 445 String out = String.format(format, option.getKey(), option.getValue()); 446 sb.append("\n\t").append(out); 447 } 448 449 return sb.toString(); 450 } 451}