All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.rest.api.spec.converter.wsdl.WSDLToOpenAPIConverter Maven / Gradle / Ivy

There is a newer version: 4.5.0-alpha.1
Show newest version
/*
 * Copyright © 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed 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 io.gravitee.rest.api.spec.converter.wsdl;

import static io.gravitee.rest.api.spec.converter.wsdl.WSDLUtils.*;

import com.ibm.wsdl.xml.WSDLReaderImpl;
import io.gravitee.common.http.HttpMethod;
import io.gravitee.common.http.HttpStatusCode;
import io.gravitee.common.http.MediaType;
import io.gravitee.rest.api.spec.converter.OpenAPIConverter;
import io.gravitee.rest.api.spec.converter.wsdl.exception.WsdlDescriptorException;
import io.gravitee.rest.api.spec.converter.wsdl.reader.GraviteeWSDLReaderImpl;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.servers.Server;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;
import javax.wsdl.*;
import javax.wsdl.extensions.schema.Schema;
import javax.xml.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

/**
 * @author GraviteeSource Team
 */
public class WSDLToOpenAPIConverter implements OpenAPIConverter {

    public static final Logger LOGGER = LoggerFactory.getLogger(WSDLToOpenAPIConverter.class);

    public static final String SOAP_EXTENSION_ENVELOPE = "x-graviteeio-soap-envelope";
    public static final String SOAP_EXTENSION_ACTION = "x-graviteeio-soap-action";

    private OpenAPI openAPI;
    private Definition wsdlDefinition;
    private SoapMessageBuilder soapBuilder;

    private Set serverCache = new HashSet<>();

    @Override
    public OpenAPI toOpenAPI(String content) {
        return toOpenAPI(new ByteArrayInputStream(content.getBytes()));
    }

    @Override
    public OpenAPI toOpenAPI(InputStream stream) {
        Objects.requireNonNull(stream, "WSDL input source is required");
        this.wsdlDefinition = loadWSDL(stream);
        // create the SoapBuilder with namespaces declared in the Definition element
        // this allows Apache XmlBeans to load additional Namespaces if required to parse the XSDs
        this.soapBuilder = new SoapMessageBuilder(wsdlDefinition.getNamespaces());

        this.openAPI = new OpenAPI();
        buildInfo();
        createSchemaObjects(this.wsdlDefinition);
        processServices();

        return openAPI;
    }

    private Definition loadWSDL(InputStream stream) {
        try {
            WSDLReaderImpl reader = new GraviteeWSDLReaderImpl();
            reader.setFeature("javax.wsdl.importDocuments", true);
            return reader.readWSDL(null, new InputSource(stream));
        } catch (WSDLException e) {
            throw new WsdlDescriptorException("Unable to read WSDL");
        }
    }

    private void buildInfo() {
        Info info = new Info();
        info.version(DEFAULT_API_VERSION);
        if (wsdlDefinition.getQName() != null) {
            info.setTitle(wsdlDefinition.getQName().getLocalPart());
        } else {
            info.setTitle(wsdlDefinition.getTargetNamespace());
        }

        Element documentation = wsdlDefinition.getDocumentationElement();
        if (documentation != null) {
            info.setDescription(documentation.getTextContent());
        }

        this.openAPI.setInfo(info);
    }

    private void createSchemaObjects(Definition definition) {
        // Types element contains a list of XmlSchema
        Types types = definition.getTypes();
        if (types != null) {
            types.getExtensibilityElements().forEach(o -> soapBuilder.addSchema((Schema) o));
        }

        if (definition.getImports() != null && !definition.getImports().isEmpty()) {
            ((Map>) definition.getImports()).values()
                .stream()
                .flatMap(Collection::stream)
                .map(Import::getDefinition)
                .filter(Objects::nonNull)
                .forEach(this::createSchemaObjects);
        }
    }

    private void processServices() {
        Map services = wsdlDefinition.getServices();
        services.values().stream().forEach(this::processPorts);
    }

    private void processPorts(Service serviceDefinition) {
        Map ports = serviceDefinition.getPorts();
        Iterator> portIterator = ports.entrySet().iterator();

        final boolean singlePort = (ports.size() == 1);
        while (portIterator.hasNext()) {
            Entry entry = portIterator.next();

            String portName = entry.getKey();
            Port portDefinition = entry.getValue();

            // create Server section for the given port
            createServer(openAPI, portDefinition);

            final Binding binding = wsdlDefinition.getBinding(portDefinition.getBinding().getQName());
            for (int i = 0; i < binding.getBindingOperations().size(); ++i) {
                final BindingOperation bindingOperation = (BindingOperation) binding.getBindingOperations().get(i);
                final Operation operation = bindingOperation.getOperation();
                final String operationName = operation.getName();

                PathItem pathItem = new PathItem();
                io.swagger.v3.oas.models.Operation openApiOperation = new io.swagger.v3.oas.models.Operation();
                openApiOperation.operationId(String.join("_", binding.getQName().getLocalPart(), operationName));
                if (operation.getDocumentationElement() != null) {
                    openApiOperation.description(operation.getDocumentationElement().getTextContent());
                }

                Input input = operation.getInput();
                if (input != null) {
                    extractSOAPAction(bindingOperation).ifPresent(action -> openApiOperation.addExtension(SOAP_EXTENSION_ACTION, action));
                    this.soapBuilder.generateSoapEnvelop(wsdlDefinition, binding, bindingOperation)
                        .ifPresent(envelope -> openApiOperation.addExtension(SOAP_EXTENSION_ENVELOPE, envelope));
                }

                // create an empty Content definition used by each response description
                Content nodefContent = new Content();
                io.swagger.v3.oas.models.media.MediaType item = new io.swagger.v3.oas.models.media.MediaType();
                io.swagger.v3.oas.models.media.Schema schema = new io.swagger.v3.oas.models.media.Schema();
                schema.setType("object");
                item.setSchema(schema);
                nodefContent.addMediaType(MediaType.APPLICATION_JSON, item);

                Output output = operation.getOutput();
                ApiResponse successResp = new ApiResponse();
                successResp.content(nodefContent);
                successResp.setDescription(""); // description is mandatory
                if (output != null) {
                    Message msg = output.getMessage();
                    if (msg != null) {
                        if (msg.getDocumentationElement() != null) {
                            successResp.description(operation.getDocumentationElement().getTextContent());
                        }
                    }
                }

                ApiResponse errorResp = new ApiResponse();
                errorResp.description("Error throws by the Backend Service");
                errorResp.content(nodefContent);

                ApiResponses responses = new ApiResponses();
                responses.addApiResponse(Integer.toString(HttpStatusCode.OK_200), successResp);
                responses.addApiResponse(Integer.toString(HttpStatusCode.INTERNAL_SERVER_ERROR_500), errorResp);

                openApiOperation.setResponses(responses);

                // TODO use the http:binding element to extract the HTTP method (§4.4) ?
                switch (detectHttpMethod(operationName)) {
                    case GET:
                        pathItem.get(openApiOperation);
                        break;
                    case DELETE:
                        pathItem.delete(openApiOperation);
                        break;
                    case PUT:
                        pathItem.put(openApiOperation);
                        break;
                    default:
                        pathItem.post(openApiOperation);
                }

                if (singlePort) {
                    openAPI.path(String.join("/", "", serviceDefinition.getQName().getLocalPart(), operationName), pathItem);
                } else {
                    openAPI.path(String.join("/", "", serviceDefinition.getQName().getLocalPart(), portName, operationName), pathItem);
                }
            }
        }
    }

    private HttpMethod detectHttpMethod(String operationName) {
        String name = operationName.toLowerCase();
        if (name.startsWith("get") || name.startsWith("find") || name.startsWith("search")) {
            return HttpMethod.GET;
        }

        if (name.startsWith("delete") || name.startsWith("remove")) {
            return HttpMethod.DELETE;
        }

        if (name.startsWith("update")) {
            return HttpMethod.PUT;
        }

        return HttpMethod.POST;
    }

    private void createServer(OpenAPI openAPI, Port port) {
        String address = extractSOAPAddress(port);
        if (!serverCache.contains(address)) {
            Server server = new Server();
            server.setUrl(address);
            openAPI.addServersItem(server);
            serverCache.add(address);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy