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.impl.verifier; 018 019import java.util.Map; 020import java.util.Optional; 021import java.util.function.Supplier; 022import java.util.stream.Collectors; 023 024import org.apache.camel.CamelContext; 025import org.apache.camel.ComponentVerifier; 026import org.apache.camel.NoSuchOptionException; 027import org.apache.camel.TypeConverter; 028import org.apache.camel.runtimecatalog.EndpointValidationResult; 029import org.apache.camel.runtimecatalog.RuntimeCamelCatalog; 030import org.apache.camel.util.CamelContextHelper; 031import org.apache.camel.util.EndpointHelper; 032import org.apache.camel.util.IntrospectionSupport; 033 034import static org.apache.camel.util.StreamUtils.stream; 035 036public class DefaultComponentVerifier implements ComponentVerifier { 037 private final String defaultScheme; 038 private final CamelContext camelContext; 039 040 public DefaultComponentVerifier(String defaultScheme, CamelContext camelContext) { 041 this.defaultScheme = defaultScheme; 042 this.camelContext = camelContext; 043 } 044 045 // ************************************* 046 // 047 // ************************************* 048 049 @Override 050 public Result verify(Scope scope, Map<String, Object> parameters) { 051 // Camel context is mandatory 052 if (this.camelContext == null) { 053 return ResultBuilder.withStatusAndScope(Result.Status.ERROR, scope) 054 .error(ResultErrorBuilder.withCodeAndDescription(VerificationError.StandardCode.INTERNAL, "Missing camel-context").build()) 055 .build(); 056 } 057 058 if (scope == Scope.PARAMETERS) { 059 return verifyParameters(parameters); 060 } 061 if (scope == Scope.CONNECTIVITY) { 062 return verifyConnectivity(parameters); 063 } 064 065 return ResultBuilder.unsupportedScope(scope).build(); 066 } 067 068 protected Result verifyConnectivity(Map<String, Object> parameters) { 069 return ResultBuilder.withStatusAndScope(Result.Status.UNSUPPORTED, Scope.CONNECTIVITY).build(); 070 } 071 072 protected Result verifyParameters(Map<String, Object> parameters) { 073 ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS); 074 075 // Validate against catalog 076 verifyParametersAgainstCatalog(builder, parameters); 077 078 return builder.build(); 079 } 080 081 // ************************************* 082 // Helpers :: Parameters validation 083 // ************************************* 084 085 protected void verifyParametersAgainstCatalog(ResultBuilder builder, Map<String, Object> parameters) { 086 verifyParametersAgainstCatalog(builder, parameters, new CatalogVerifierCustomizer()); 087 } 088 089 protected void verifyParametersAgainstCatalog(ResultBuilder builder, Map<String, Object> parameters, CatalogVerifierCustomizer customizer) { 090 String scheme = defaultScheme; 091 if (parameters.containsKey("scheme")) { 092 scheme = parameters.get("scheme").toString(); 093 } 094 095 // Grab the runtime catalog to check parameters 096 RuntimeCamelCatalog catalog = camelContext.getRuntimeCamelCatalog(); 097 098 // Convert from Map<String, Object> to Map<String, String> as required 099 // by the Camel Catalog 100 EndpointValidationResult result = catalog.validateProperties( 101 scheme, 102 parameters.entrySet().stream() 103 .collect( 104 Collectors.toMap( 105 Map.Entry::getKey, 106 e -> camelContext.getTypeConverter().convertTo(String.class, e.getValue()) 107 ) 108 ) 109 ); 110 111 if (!result.isSuccess()) { 112 if (customizer.isIncludeUnknown()) { 113 stream(result.getUnknown()) 114 .map(option -> ResultErrorBuilder.withUnknownOption(option).build()) 115 .forEach(builder::error); 116 } 117 if (customizer.isIncludeRequired()) { 118 stream(result.getRequired()) 119 .map(option -> ResultErrorBuilder.withMissingOption(option).build()) 120 .forEach(builder::error); 121 } 122 if (customizer.isIncludeInvalidBoolean()) { 123 stream(result.getInvalidBoolean()) 124 .map(entry -> ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()).build()) 125 .forEach(builder::error); 126 } 127 if (customizer.isIncludeInvalidInteger()) { 128 stream(result.getInvalidInteger()) 129 .map(entry -> ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()).build()) 130 .forEach(builder::error); 131 } 132 if (customizer.isIncludeInvalidNumber()) { 133 stream(result.getInvalidNumber()) 134 .map(entry -> ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()).build()) 135 .forEach(builder::error); 136 } 137 if (customizer.isIncludeInvalidEnum()) { 138 stream(result.getInvalidEnum()) 139 .map(entry -> 140 ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()) 141 .detail("enum.values", result.getEnumChoices(entry.getKey())) 142 .build()) 143 .forEach(builder::error); 144 } 145 } 146 } 147 148 // ************************************* 149 // Helpers 150 // ************************************* 151 152 protected CamelContext getCamelContext() { 153 return camelContext; 154 } 155 156 protected <T> T setProperties(T instance, Map<String, Object> properties) throws Exception { 157 if (camelContext == null) { 158 throw new IllegalStateException("Camel context is null"); 159 } 160 161 if (!properties.isEmpty()) { 162 final TypeConverter converter = camelContext.getTypeConverter(); 163 164 IntrospectionSupport.setProperties(converter, instance, properties); 165 166 for (Map.Entry<String, Object> entry : properties.entrySet()) { 167 if (entry.getValue() instanceof String) { 168 String value = (String)entry.getValue(); 169 if (EndpointHelper.isReferenceParameter(value)) { 170 IntrospectionSupport.setProperty(camelContext, converter, instance, entry.getKey(), null, value, true); 171 } 172 } 173 } 174 } 175 176 return instance; 177 } 178 179 protected <T> T setProperties(T instance, String prefix, Map<String, Object> properties) throws Exception { 180 return setProperties( 181 instance, 182 IntrospectionSupport.extractProperties(properties, prefix, false) 183 ); 184 } 185 186 protected <T> Optional<T> getOption(Map<String, Object> parameters, String key, Class<T> type) { 187 Object value = parameters.get(key); 188 if (value != null) { 189 return Optional.ofNullable(CamelContextHelper.convertTo(camelContext, type, value)); 190 } 191 192 return Optional.empty(); 193 } 194 195 protected <T> T getOption(Map<String, Object> parameters, String key, Class<T> type, Supplier<T> defaultSupplier) { 196 return getOption(parameters, key, type).orElseGet(defaultSupplier); 197 } 198 199 protected <T> T getMandatoryOption(Map<String, Object> parameters, String key, Class<T> type) throws NoSuchOptionException { 200 return getOption(parameters, key, type).orElseThrow(() -> new NoSuchOptionException(key)); 201 } 202}