/** * 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.swagger; import java.io.InputStream; import java.util.List; import java.util.Map; import io.swagger.models.Operation; import io.swagger.models.Path; import io.swagger.models.Swagger; import io.swagger.models.parameters.Parameter; import io.swagger.parser.SwaggerParser; import org.apache.camel.CamelContext; import org.apache.camel.Producer; import org.apache.camel.spi.RestProducerFactory; import org.apache.camel.util.CollectionStringBuffer; import org.apache.camel.util.IOHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.camel.util.ResourceHelper.resolveMandatoryResourceAsInputStream; public class SwaggerRestProducerFactory implements RestProducerFactory { private static final Logger LOG = LoggerFactory.getLogger(SwaggerRestProducerFactory.class); @Override public Producer createProducer(CamelContext camelContext, String host, String verb, String basePath, String uriTemplate, String queryParameters, String consumes, String produces, Map<String, Object> parameters) throws Exception { String apiDoc = (String) parameters.get("apiDoc"); // load json model if (apiDoc == null) { throw new IllegalArgumentException("Swagger api-doc must be configured using the apiDoc option"); } String path = uriTemplate != null ? uriTemplate : basePath; // path must start with a leading slash if (!path.startsWith("/")) { path = "/" + path; } Swagger swagger = loadSwaggerModel(camelContext, apiDoc); Operation operation = getSwaggerOperation(swagger, verb, path); if (operation == null) { throw new IllegalArgumentException("Swagger api-doc does not contain operation for " + verb + ":" + path); } // validate if we have the query parameters also if (queryParameters != null) { for (Parameter param : operation.getParameters()) { if ("query".equals(param.getIn()) && param.getRequired()) { // check if we have the required query parameter defined String key = param.getName(); String token = key + "="; boolean hasQuery = queryParameters.contains(token); if (!hasQuery) { throw new IllegalArgumentException("Swagger api-doc does not contain query parameter " + key + " for " + verb + ":" + path); } } } } String componentName = (String) parameters.get("componentName"); Producer producer = createHttpProducer(camelContext, swagger, operation, host, verb, path, queryParameters, produces, consumes, componentName, parameters); return producer; } Swagger loadSwaggerModel(CamelContext camelContext, String apiDoc) throws Exception { InputStream is = resolveMandatoryResourceAsInputStream(camelContext, apiDoc); try { SwaggerParser parser = new SwaggerParser(); String json = camelContext.getTypeConverter().mandatoryConvertTo(String.class, is); LOG.debug("Loaded swagger api-doc:\n{}", json); return parser.parse(json); } finally { IOHelper.close(is); } } private Operation getSwaggerOperation(Swagger swagger, String verb, String path) { // path may include base path so skip that String basePath = swagger.getBasePath(); if (basePath != null && path.startsWith(basePath)) { path = path.substring(basePath.length()); } Path modelPath = swagger.getPath(path); if (modelPath == null) { return null; } // get,put,post,head,delete,patch,options Operation op = null; if ("get".equals(verb)) { op = modelPath.getGet(); } else if ("put".equals(verb)) { op = modelPath.getPut(); } else if ("post".equals(verb)) { op = modelPath.getPost(); } else if ("head".equals(verb)) { op = modelPath.getHead(); } else if ("delete".equals(verb)) { op = modelPath.getDelete(); } else if ("patch".equals(verb)) { op = modelPath.getPatch(); } else if ("options".equals(verb)) { op = modelPath.getOptions(); } return op; } private Producer createHttpProducer(CamelContext camelContext, Swagger swagger, Operation operation, String host, String verb, String path, String queryParameters, String consumes, String produces, String componentName, Map<String, Object> parameters) throws Exception { LOG.debug("Using Swagger operation: {} with {} {}", operation, verb, path); RestProducerFactory factory = (RestProducerFactory) parameters.remove("restProducerFactory"); if (factory != null) { LOG.debug("Using RestProducerFactory: {}", factory); if (produces == null) { CollectionStringBuffer csb = new CollectionStringBuffer(","); List<String> list = operation.getProduces(); if (list == null) { list = swagger.getProduces(); } if (list != null) { for (String s : list) { csb.append(s); } } produces = csb.isEmpty() ? null : csb.toString(); } if (consumes == null) { CollectionStringBuffer csb = new CollectionStringBuffer(","); List<String> list = operation.getConsumes(); if (list == null) { list = swagger.getConsumes(); } if (list != null) { for (String s : list) { csb.append(s); } } consumes = csb.isEmpty() ? null : csb.toString(); } String basePath; String uriTemplate; if (host == null) { // if no explicit host has been configured then use host and base path from the swagger api-doc host = swagger.getHost(); basePath = swagger.getBasePath(); uriTemplate = path; } else { // path includes also uri template basePath = path; uriTemplate = null; } return factory.createProducer(camelContext, host, verb, basePath, uriTemplate, queryParameters, consumes, produces, parameters); } else { throw new IllegalStateException("Cannot find RestProducerFactory in Registry or as a Component to use"); } } }