/**
* 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.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.camel.CamelContext;
import org.apache.camel.ComponentVerifier;
import org.apache.camel.NoSuchOptionException;
import org.apache.camel.TypeConverter;
import org.apache.camel.runtimecatalog.EndpointValidationResult;
import org.apache.camel.runtimecatalog.RuntimeCamelCatalog;
import org.apache.camel.util.CamelContextHelper;
import org.apache.camel.util.EndpointHelper;
import org.apache.camel.util.IntrospectionSupport;
import static org.apache.camel.util.StreamUtils.stream;
public class DefaultComponentVerifier implements ComponentVerifier {
private final String defaultScheme;
private final CamelContext camelContext;
public DefaultComponentVerifier(String defaultScheme, CamelContext camelContext) {
this.defaultScheme = defaultScheme;
this.camelContext = camelContext;
}
// *************************************
//
// *************************************
@Override
public Result verify(Scope scope, Map<String, Object> parameters) {
// Camel context is mandatory
if (this.camelContext == null) {
return ResultBuilder.withStatusAndScope(Result.Status.ERROR, scope)
.error(ResultErrorBuilder.withCodeAndDescription(VerificationError.StandardCode.INTERNAL, "Missing camel-context").build())
.build();
}
if (scope == Scope.PARAMETERS) {
return verifyParameters(parameters);
}
if (scope == Scope.CONNECTIVITY) {
return verifyConnectivity(parameters);
}
return ResultBuilder.unsupportedScope(scope).build();
}
protected Result verifyConnectivity(Map<String, Object> parameters) {
return ResultBuilder.withStatusAndScope(Result.Status.UNSUPPORTED, Scope.CONNECTIVITY).build();
}
protected Result verifyParameters(Map<String, Object> parameters) {
ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS);
// Validate against catalog
verifyParametersAgainstCatalog(builder, parameters);
return builder.build();
}
// *************************************
// Helpers :: Parameters validation
// *************************************
protected void verifyParametersAgainstCatalog(ResultBuilder builder, Map<String, Object> parameters) {
verifyParametersAgainstCatalog(builder, parameters, new CatalogVerifierCustomizer());
}
protected void verifyParametersAgainstCatalog(ResultBuilder builder, Map<String, Object> parameters, CatalogVerifierCustomizer customizer) {
String scheme = defaultScheme;
if (parameters.containsKey("scheme")) {
scheme = parameters.get("scheme").toString();
}
// Grab the runtime catalog to check parameters
RuntimeCamelCatalog catalog = camelContext.getRuntimeCamelCatalog();
// Convert from Map<String, Object> to Map<String, String> as required
// by the Camel Catalog
EndpointValidationResult result = catalog.validateProperties(
scheme,
parameters.entrySet().stream()
.collect(
Collectors.toMap(
Map.Entry::getKey,
e -> camelContext.getTypeConverter().convertTo(String.class, e.getValue())
)
)
);
if (!result.isSuccess()) {
if (customizer.isIncludeUnknown()) {
stream(result.getUnknown())
.map(option -> ResultErrorBuilder.withUnknownOption(option).build())
.forEach(builder::error);
}
if (customizer.isIncludeRequired()) {
stream(result.getRequired())
.map(option -> ResultErrorBuilder.withMissingOption(option).build())
.forEach(builder::error);
}
if (customizer.isIncludeInvalidBoolean()) {
stream(result.getInvalidBoolean())
.map(entry -> ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()).build())
.forEach(builder::error);
}
if (customizer.isIncludeInvalidInteger()) {
stream(result.getInvalidInteger())
.map(entry -> ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()).build())
.forEach(builder::error);
}
if (customizer.isIncludeInvalidNumber()) {
stream(result.getInvalidNumber())
.map(entry -> ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue()).build())
.forEach(builder::error);
}
if (customizer.isIncludeInvalidEnum()) {
stream(result.getInvalidEnum())
.map(entry ->
ResultErrorBuilder.withIllegalOption(entry.getKey(), entry.getValue())
.detail("enum.values", result.getEnumChoices(entry.getKey()))
.build())
.forEach(builder::error);
}
}
}
// *************************************
// Helpers
// *************************************
protected CamelContext getCamelContext() {
return camelContext;
}
protected <T> T setProperties(T instance, Map<String, Object> properties) throws Exception {
if (camelContext == null) {
throw new IllegalStateException("Camel context is null");
}
if (!properties.isEmpty()) {
final TypeConverter converter = camelContext.getTypeConverter();
IntrospectionSupport.setProperties(converter, instance, properties);
for (Map.Entry<String, Object> entry : properties.entrySet()) {
if (entry.getValue() instanceof String) {
String value = (String)entry.getValue();
if (EndpointHelper.isReferenceParameter(value)) {
IntrospectionSupport.setProperty(camelContext, converter, instance, entry.getKey(), null, value, true);
}
}
}
}
return instance;
}
protected <T> T setProperties(T instance, String prefix, Map<String, Object> properties) throws Exception {
return setProperties(
instance,
IntrospectionSupport.extractProperties(properties, prefix, false)
);
}
protected <T> Optional<T> getOption(Map<String, Object> parameters, String key, Class<T> type) {
Object value = parameters.get(key);
if (value != null) {
return Optional.ofNullable(CamelContextHelper.convertTo(camelContext, type, value));
}
return Optional.empty();
}
protected <T> T getOption(Map<String, Object> parameters, String key, Class<T> type, Supplier<T> defaultSupplier) {
return getOption(parameters, key, type).orElseGet(defaultSupplier);
}
protected <T> T getMandatoryOption(Map<String, Object> parameters, String key, Class<T> type) throws NoSuchOptionException {
return getOption(parameters, key, type).orElseThrow(() -> new NoSuchOptionException(key));
}
}