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.rest; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Optional; 022 023import org.apache.camel.Component; 024import org.apache.camel.ComponentVerifier; 025import org.apache.camel.component.extension.ComponentVerifierExtension; 026import org.apache.camel.component.extension.verifier.CatalogVerifierCustomizer; 027import org.apache.camel.component.extension.verifier.DefaultComponentVerifierExtension; 028import org.apache.camel.component.extension.verifier.ResultBuilder; 029import org.apache.camel.component.extension.verifier.ResultErrorBuilder; 030import org.apache.camel.runtimecatalog.JSonSchemaHelper; 031import org.apache.camel.runtimecatalog.RuntimeCamelCatalog; 032import org.apache.camel.spi.RestConsumerFactory; 033import org.apache.camel.spi.RestProducerFactory; 034import org.apache.camel.util.ObjectHelper; 035import org.apache.camel.util.function.Suppliers; 036 037public class RestComponentVerifierExtension extends DefaultComponentVerifierExtension implements ComponentVerifier { 038 private static final CatalogVerifierCustomizer CUSTOMIZER = new CatalogVerifierCustomizer().excludeUnknown(); 039 040 RestComponentVerifierExtension() { 041 super("rest"); 042 } 043 044 // ********************************* 045 // Parameters validation 046 // ********************************* 047 048 @Override 049 protected Result verifyParameters(Map<String, Object> parameters) { 050 ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS); 051 052 // Validate using the catalog but do not report unknown options as error 053 // as the may be used to customize the underlying component 054 super.verifyParametersAgainstCatalog(builder, parameters, CUSTOMIZER); 055 056 verifyUnderlyingComponent(Scope.PARAMETERS, builder, parameters); 057 058 return builder.build(); 059 } 060 061 // ********************************* 062 // Connectivity validation 063 // ********************************* 064 065 @Override 066 protected Result verifyConnectivity(Map<String, Object> parameters) { 067 ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.CONNECTIVITY); 068 069 verifyUnderlyingComponent(Scope.CONNECTIVITY, builder, parameters); 070 071 return builder.build(); 072 } 073 074 // ********************************* 075 // Helpers 076 // ********************************* 077 078 protected void verifyUnderlyingComponent(Scope scope, ResultBuilder builder, Map<String, Object> parameters) { 079 // componentName is required for validation even at runtime camel might 080 // be able to find a suitable component at runtime. 081 String componentName = (String)parameters.get("componentName"); 082 if (ObjectHelper.isNotEmpty(componentName)) { 083 try { 084 final Component component = getTransportComponent(componentName); 085 final Optional<ComponentVerifierExtension> extension = component.getExtension(ComponentVerifierExtension.class); 086 087 if (extension.isPresent()) { 088 final ComponentVerifierExtension verifier = extension.get(); 089 final RuntimeCamelCatalog catalog = getCamelContext().getRuntimeCamelCatalog(); 090 final String json = catalog.componentJSonSchema("rest"); 091 final Map<String, Object> restParameters = new HashMap<>(parameters); 092 093 for (Map<String, String> m : JSonSchemaHelper.parseJsonSchema("componentProperties", json, true)) { 094 String name = m.get("name"); 095 Object val = restParameters.remove(name); 096 if (val != null) { 097 // Add rest prefix to properties belonging to the rest 098 // component so the underlying component know we want 099 // to validate rest-related stuffs. 100 restParameters.put("rest." + name, parameters.get(name)); 101 } 102 } 103 for (Map<String, String> m : JSonSchemaHelper.parseJsonSchema("properties", json, true)) { 104 String name = m.get("name"); 105 Object val = restParameters.remove(name); 106 if (val != null) { 107 // Add rest prefix to properties belonging to the rest 108 // component so the underlying component know we want 109 // to validate rest-related stuffs. 110 restParameters.put("rest." + name, parameters.get(name)); 111 } 112 } 113 114 // restParameters now should contains rest-component related 115 // properties with "rest." prefix and all the remaining can 116 // be used to customize the underlying component (i.e. http 117 // proxies, auth, etc) 118 Result result = verifier.verify(scope, restParameters); 119 120 // Combine errors and add an information about the component 121 // they comes from 122 for (VerificationError error : result.getErrors()) { 123 builder.error( 124 ResultErrorBuilder.fromError(error) 125 .detail("component", componentName) 126 .build() 127 ); 128 } 129 } else { 130 builder.error( 131 ResultErrorBuilder.withUnsupportedComponent(componentName).build() 132 ); 133 } 134 } catch (Exception e) { 135 builder.error( 136 ResultErrorBuilder.withException(e).build() 137 ); 138 } 139 } else { 140 builder.error(ResultErrorBuilder.withMissingOption("componentName").build()); 141 } 142 } 143 144 private Component getTransportComponent(String componentName) throws Exception { 145 return Suppliers.firstMatching( 146 comp -> comp != null && (comp instanceof RestConsumerFactory || comp instanceof RestProducerFactory), 147 () -> getCamelContext().getRegistry().lookupByNameAndType(componentName, Component.class), 148 () -> getCamelContext().getComponent(componentName, true, false) 149 ).orElse(null); 150 } 151}