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.api.management.mbean; 018 019import java.io.Serializable; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.camel.api.management.mbean.ComponentVerifierExtension.VerificationError.Attribute; 025import org.apache.camel.api.management.mbean.ComponentVerifierExtension.VerificationError.Code; 026import org.apache.camel.api.management.mbean.ComponentVerifierExtension.VerificationError.ExceptionAttribute; 027import org.apache.camel.api.management.mbean.ComponentVerifierExtension.VerificationError.GroupAttribute; 028import org.apache.camel.api.management.mbean.ComponentVerifierExtension.VerificationError.HttpAttribute; 029import org.apache.camel.api.management.mbean.ComponentVerifierExtension.VerificationError.StandardCode; 030 031/** 032 * Defines the interface used for validating component/endpoint parameters. The central method of this interface is 033 * {@link ManagedComponentMBean#verify(String, Map)} which takes a scope and a set of parameters which should be 034 * verified. 035 * <p/> 036 * The return value is a {@link ComponentVerifierExtension.Result} of the verification 037 */ 038public final class ComponentVerifierExtension { 039 040 /** 041 * The result of a verification 042 */ 043 public interface Result extends Serializable { 044 045 /** 046 * Status of the verification 047 */ 048 enum Status { 049 /** 050 * Verification succeeded 051 */ 052 OK, 053 /** 054 * Error occurred during the verification 055 */ 056 ERROR, 057 /** 058 * Verification is not supported. This can depend on the given scope. 059 */ 060 UNSUPPORTED 061 } 062 063 /** 064 * Scope of the verification. This is the scope given to the call to 065 * {@link ManagedComponentMBean#verify(String, Map)} and can be used for correlation. 066 * 067 * @return the scope against which the parameters have been validated. 068 */ 069 Scope getScope(); 070 071 /** 072 * Result of the validation as status. This should be the first datum to check after a verification happened. 073 * 074 * @return the status 075 */ 076 Status getStatus(); 077 078 /** 079 * Collection of errors happened for the verification. This list is empty (but non null) if the verification 080 * succeeded. 081 * 082 * @return a list of errors. Can be empty when verification was successful 083 */ 084 List<VerificationError> getErrors(); 085 } 086 087 /** 088 * The scope defines how the parameters should be verified. 089 */ 090 public enum Scope { 091 092 /** 093 * Only validate the parameters for their <em>syntactic</em> soundness. Verifications in this scope should be as 094 * fast as possible 095 */ 096 PARAMETERS, 097 098 /** 099 * Reach out to the backend and verify that a connection can be established. This means, if the verification in 100 * this scope succeeds, then it can safely be assumed that the component can be used. 101 */ 102 CONNECTIVITY; 103 104 /** 105 * Get an instance of this scope from a string representation 106 * 107 * @param scope the scope as string, which can be in any case 108 * @return the scope enum represented by this string 109 */ 110 public static Scope fromString(String scope) { 111 return Scope.valueOf(scope != null ? scope.toUpperCase() : null); 112 } 113 } 114 115 // ============================================================================================= 116 117 /** 118 * This interface represents a detailed error in case when the verification fails. 119 */ 120 public interface VerificationError extends Serializable { 121 122 /** 123 * The overall error code, which can be either a {@link StandardCode} or a custom code. It is recommended to 124 * stick to the predefined standard codes 125 * 126 * @return the general error code. 127 */ 128 Code getCode(); 129 130 /** 131 * A human readable description of the error in plain english 132 * 133 * @return the error description (if available) 134 */ 135 String getDescription(); 136 137 /** 138 * A set of input parameter names which fails the verification. These are keys to the parameter provided to 139 * {@link ManagedComponentMBean#verify(String, Map)}. 140 * 141 * @return the parameter names which are malformed and caused the failure of the validation 142 */ 143 Set<String> getParameterKeys(); 144 145 /** 146 * Details about the failed verification. The keys can be either predefined values ({@link ExceptionAttribute}, 147 * {@link HttpAttribute}, {@link GroupAttribute}) or it can be free-form custom keys specific to a component. 148 * The standard attributes are defined as enums in all uppercase (with underscore as separator), custom 149 * attributes are supposed to be in all lower case (also with underscores as separators) 150 * 151 * @return a number of key/value pair with additional information related to the verification. 152 */ 153 Map<Attribute, Object> getDetails(); 154 155 /** 156 * Get a single detail for a given attribute 157 * 158 * @param attribute the attribute to lookup 159 * @return the detail value or null if no such attribute exists 160 */ 161 default Object getDetail(Attribute attribute) { 162 Map<Attribute, Object> details = getDetails(); 163 if (details != null) { 164 return details.get(attribute); 165 } 166 return null; 167 } 168 169 /** 170 * Get a single detail for a given attribute 171 * 172 * @param attribute the attribute to lookup 173 * @return the detail value or null if no such attribute exists 174 */ 175 default Object getDetail(String attribute) { 176 return getDetail(asAttribute(attribute)); 177 } 178 179 /** 180 * Convert a string to an {@link Code} 181 * 182 * @param code the code to convert. It should be in all lower case (with underscore as a separator) to avoid 183 * overlap with {@link StandardCode} 184 * @return error code 185 */ 186 static Code asCode(String code) { 187 return new ErrorCode(code); 188 } 189 190 /** 191 * Convert a string to an {@link Attribute} 192 * 193 * @param attribute the string representation of an attribute to convert. It should be in all lower case (with 194 * underscore as a separator) to avoid overlap with standard attributes like 195 * {@link ExceptionAttribute}, {@link HttpAttribute} or {@link GroupAttribute} 196 * @return generated attribute 197 */ 198 static Attribute asAttribute(String attribute) { 199 return new ErrorAttribute(attribute); 200 } 201 202 /** 203 * Interface defining an error code. This is implemented by the {@link StandardCode} but also own code can be 204 * generated by implementing this interface. This is best done via {@link #asCode(String)} If possible, the 205 * standard codes should be reused 206 */ 207 interface Code extends Serializable { 208 /** 209 * Name of the code. All uppercase for standard codes, all lower case for custom codes. Separator between 210 * two words is an underscore. 211 * 212 * @return code name 213 */ 214 String name(); 215 216 /** 217 * Bean style accessor to name. This is required for framework like Jackson using bean convention for object 218 * serialization. 219 * 220 * @return code name 221 */ 222 default String getName() { 223 return name(); 224 } 225 } 226 227 /** 228 * Standard set of error codes 229 */ 230 interface StandardCode extends Code { 231 /** 232 * Authentication failed 233 */ 234 StandardCode AUTHENTICATION = new StandardErrorCode("AUTHENTICATION"); 235 /** 236 * An exception occurred 237 */ 238 StandardCode EXCEPTION = new StandardErrorCode("EXCEPTION"); 239 /** 240 * Internal error while performing the verification 241 */ 242 StandardCode INTERNAL = new StandardErrorCode("INTERNAL"); 243 /** 244 * A mandatory parameter is missing 245 */ 246 StandardCode MISSING_PARAMETER = new StandardErrorCode("MISSING_PARAMETER"); 247 /** 248 * A given parameter is not known to the component 249 */ 250 StandardCode UNKNOWN_PARAMETER = new StandardErrorCode("UNKNOWN_PARAMETER"); 251 /** 252 * A given parameter is illegal 253 */ 254 StandardCode ILLEGAL_PARAMETER = new StandardErrorCode("ILLEGAL_PARAMETER"); 255 /** 256 * A combination of parameters is illegal. See {@link VerificationError#getParameterKeys()} for the set of 257 * affected parameters 258 */ 259 StandardCode ILLEGAL_PARAMETER_GROUP_COMBINATION = new StandardErrorCode("ILLEGAL_PARAMETER_GROUP_COMBINATION"); 260 /** 261 * A parameter <em>value</em> is not valid 262 */ 263 StandardCode ILLEGAL_PARAMETER_VALUE = new StandardErrorCode("ILLEGAL_PARAMETER_VALUE"); 264 /** 265 * A group of parameters is not complete in order to be valid 266 */ 267 StandardCode INCOMPLETE_PARAMETER_GROUP = new StandardErrorCode("INCOMPLETE_PARAMETER_GROUP"); 268 /** 269 * The verification is not supported 270 */ 271 StandardCode UNSUPPORTED = new StandardErrorCode("UNSUPPORTED"); 272 /** 273 * The requested {@link Scope} is not supported 274 */ 275 StandardCode UNSUPPORTED_SCOPE = new StandardErrorCode("UNSUPPORTED_SCOPE"); 276 /** 277 * The requested Component is not supported 278 */ 279 StandardCode UNSUPPORTED_COMPONENT = new StandardErrorCode("UNSUPPORTED_COMPONENT"); 280 /** 281 * Generic error which is explained in more details with {@link VerificationError#getDetails()} 282 */ 283 StandardCode GENERIC = new StandardErrorCode("GENERIC"); 284 } 285 286 /** 287 * Interface defining an attribute which is a key for the detailed error messages. 288 */ 289 interface Attribute extends Serializable { 290 291 /** 292 * Name of the attribute. All uppercase for standard attributes and all lower case for custom attributes. 293 * Separator between words is an underscore. 294 * 295 * @return attribute name 296 */ 297 String name(); 298 299 /** 300 * Bean style accessor to name; This is required for framework like Jackson using bean convention for object 301 * serialization. 302 * 303 * @return attribute name 304 */ 305 default String getName() { 306 return name(); 307 } 308 } 309 310 /** 311 * Attributes for details about an exception that was raised 312 */ 313 interface ExceptionAttribute extends Attribute { 314 315 /** 316 * The exception object that has been thrown. Note that this can be a complex object and can cause large 317 * content when e.g. serialized as JSON 318 */ 319 ExceptionAttribute EXCEPTION_INSTANCE = new ExceptionErrorAttribute("EXCEPTION_INSTANCE"); 320 321 /** 322 * The exception class 323 */ 324 ExceptionAttribute EXCEPTION_CLASS = new ExceptionErrorAttribute("EXCEPTION_CLASS"); 325 } 326 327 /** 328 * HTTP related error details 329 */ 330 interface HttpAttribute extends Attribute { 331 332 /** 333 * The erroneous HTTP code that occurred 334 */ 335 HttpAttribute HTTP_CODE = new HttpErrorAttribute("HTTP_CODE"); 336 337 /** 338 * HTTP response's body 339 */ 340 HttpAttribute HTTP_TEXT = new HttpErrorAttribute("HTTP_TEXT"); 341 342 /** 343 * If given as details, specifies that a redirect happened and the content of this detail is the redirect 344 * URL 345 */ 346 HttpAttribute HTTP_REDIRECT = new HttpErrorAttribute("HTTP_REDIRECT"); 347 } 348 349 /** 350 * Group related details 351 */ 352 interface GroupAttribute extends Attribute { 353 354 /** 355 * Group name 356 */ 357 GroupAttribute GROUP_NAME = new GroupErrorAttribute("GROUP_NAME"); 358 359 /** 360 * Options for the group 361 */ 362 GroupAttribute GROUP_OPTIONS = new GroupErrorAttribute("GROUP_OPTIONS"); 363 } 364 } 365 366 /** 367 * Custom class for error codes 368 */ 369 static class ErrorCode implements Code { 370 371 private final String name; 372 373 ErrorCode(String name) { 374 if (name == null) { 375 throw new IllegalArgumentException("Name of an error code must not be null"); 376 } 377 this.name = name; 378 } 379 380 @Override 381 public String name() { 382 return name; 383 } 384 385 @Override 386 public boolean equals(Object o) { 387 if (this == o) { 388 return true; 389 } 390 if (!(o instanceof Code)) { 391 return false; 392 } 393 394 Code errorCode = (Code) o; 395 396 return name.equals(errorCode.name()); 397 } 398 399 @Override 400 public int hashCode() { 401 return name.hashCode(); 402 } 403 404 @Override 405 public String toString() { 406 return name(); 407 } 408 } 409 410 static class ErrorAttribute implements Attribute { 411 412 private final String name; 413 414 ErrorAttribute(String name) { 415 if (name == null) { 416 throw new IllegalArgumentException("Name of an error attribute must not be null"); 417 } 418 this.name = name; 419 } 420 421 @Override 422 public String name() { 423 return name; 424 } 425 426 @Override 427 public boolean equals(Object o) { 428 if (this == o) { 429 return true; 430 } 431 if (!(o instanceof Attribute)) { 432 return false; 433 } 434 435 Attribute that = (Attribute) o; 436 437 return name.equals(that.name()); 438 } 439 440 @Override 441 public int hashCode() { 442 return name.hashCode(); 443 } 444 445 @Override 446 public String toString() { 447 return name(); 448 } 449 } 450 451 // =========================================================================================================== 452 // Helper classes for implementing the constants in ComponentVerifier: 453 454 static class StandardErrorCode extends ErrorCode implements StandardCode { 455 StandardErrorCode(String name) { 456 super(name); 457 } 458 } 459 460 static class ExceptionErrorAttribute extends ErrorAttribute implements ExceptionAttribute { 461 ExceptionErrorAttribute(String name) { 462 super(name); 463 } 464 } 465 466 static class HttpErrorAttribute extends ErrorAttribute implements HttpAttribute { 467 HttpErrorAttribute(String name) { 468 super(name); 469 } 470 } 471 472 static class GroupErrorAttribute extends ErrorAttribute implements GroupAttribute { 473 GroupErrorAttribute(String name) { 474 super(name); 475 } 476 } 477}