| /* |
| * 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.servicecomb.toolkit.generator.context; |
| |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.stream.Collectors; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.servicecomb.toolkit.generator.HttpStatuses; |
| import org.apache.servicecomb.toolkit.generator.MediaTypes; |
| import org.apache.servicecomb.toolkit.generator.parser.api.OpenApiAnnotationParser; |
| import org.apache.servicecomb.toolkit.generator.util.ModelConverter; |
| import org.apache.servicecomb.toolkit.generator.util.RequestResponse; |
| |
| import io.swagger.v3.oas.models.Components; |
| import io.swagger.v3.oas.models.OpenAPI; |
| import io.swagger.v3.oas.models.Operation; |
| import io.swagger.v3.oas.models.media.Content; |
| import io.swagger.v3.oas.models.media.MediaType; |
| import io.swagger.v3.oas.models.media.ObjectSchema; |
| import io.swagger.v3.oas.models.media.Schema; |
| import io.swagger.v3.oas.models.media.StringSchema; |
| import io.swagger.v3.oas.models.parameters.HeaderParameter; |
| import io.swagger.v3.oas.models.parameters.Parameter; |
| import io.swagger.v3.oas.models.parameters.RequestBody; |
| import io.swagger.v3.oas.models.responses.ApiResponse; |
| import io.swagger.v3.oas.models.responses.ApiResponses; |
| |
| public class OperationContext implements IExtensionsContext { |
| |
| private static final RequestBody nullRequestBody = new RequestBody(); |
| |
| private OasContext parentContext; |
| |
| private Method method; |
| |
| private Operation operation = new Operation(); |
| |
| private String operationId; |
| |
| private String path; |
| |
| private String httpMethod; |
| |
| private ApiResponses apiResponses = new ApiResponses(); |
| |
| private List<ParameterContext> parameterContexts = new ArrayList<>(); |
| |
| private OpenApiAnnotationParser parser; |
| |
| private Boolean deprecated = false; |
| |
| private String description = null; |
| |
| private String summary; |
| |
| private List<String> tags; |
| |
| private String[] consumers; |
| |
| private String[] produces; |
| |
| private String[] headers; |
| |
| public OperationContext(Method method, OasContext parentContext) { |
| this.parentContext = parentContext; |
| this.method = method; |
| this.parser = parentContext.getParser(); |
| this.parentContext.addOperation(this); |
| } |
| |
| @Override |
| public OpenApiAnnotationParser getParser() { |
| return parser; |
| } |
| |
| public boolean hasOperation() { |
| return getHttpMethod() != null && method != null; |
| } |
| |
| public Operation toOperation() { |
| |
| if (!hasOperation()) { |
| return null; |
| } |
| |
| if (StringUtils.isEmpty(operationId)) { |
| operationId = method.getName(); |
| } |
| |
| operation.operationId(operationId); |
| processHeaders(); |
| processProduces(); |
| correctResponse(apiResponses); |
| operation.setResponses(apiResponses); |
| |
| RequestBody requestBody = new RequestBody(); |
| Content content = new Content(); |
| MediaType mediaType = new MediaType(); |
| |
| // process parameter |
| List<Parameter> parameterList = parameterContexts.stream() |
| .map(parameterContext -> |
| { |
| // requestBody |
| if (parameterContext.isRequestBody()) { |
| |
| Schema schema = mediaType.getSchema(); |
| if (schema == null) { |
| schema = new ObjectSchema(); |
| mediaType.schema(schema); |
| } |
| schema.addProperties(parameterContext.getName(), parameterContext.getSchema()); |
| if (consumers != null) { |
| for (String consume : getConsumers()) { |
| content.addMediaType(consume, mediaType); |
| } |
| } else { |
| if (parameterContext.getConsumers() != null && parameterContext.getConsumers().size() > 0) { |
| for (String consume : parameterContext.getConsumers()) { |
| content.addMediaType(consume, mediaType); |
| } |
| } else { |
| content.addMediaType(MediaTypes.APPLICATION_JSON, mediaType); |
| } |
| } |
| |
| requestBody.setContent(content); |
| requestBody.setRequired(parameterContext.getRequired()); |
| return null; |
| } |
| |
| // parameter |
| return parameterContext.toParameter(); |
| }) |
| .filter(parameter -> parameter != null) |
| .collect(Collectors.toList()); |
| |
| if (parameterList.size() > 0) { |
| operation.parameters(parameterList); |
| } |
| |
| if (!nullRequestBody.equals(requestBody)) { |
| operation.setRequestBody(requestBody); |
| } |
| return operation; |
| } |
| |
| private void processHeaders() { |
| |
| if (headers == null) { |
| headers = parentContext.getHeaders(); |
| } |
| |
| if (headers == null) { |
| return; |
| } |
| |
| Arrays.stream(headers).forEach(header -> { |
| String[] headMap = header.split("="); |
| if (headMap.length == 2) { |
| HeaderParameter headerParameter = new HeaderParameter(); |
| headerParameter.setName(headMap[0]); |
| StringSchema value = new StringSchema(); |
| value.setDefault(headMap[1]); |
| headerParameter.setSchema(value); |
| operation.addParametersItem(headerParameter); |
| } |
| }); |
| } |
| |
| private void processProduces() { |
| |
| if (produces == null) { |
| produces = parentContext.getProduces(); |
| } |
| |
| if (produces == null) { |
| return; |
| } |
| |
| List<String> produceList = Arrays.stream(produces).filter(s -> !StringUtils.isEmpty(s)) |
| .collect(Collectors.toList()); |
| |
| if (!produceList.isEmpty()) { |
| ApiResponse apiResponse = new ApiResponse(); |
| Content content = new Content(); |
| MediaType mediaType = new MediaType(); |
| Schema schema = ModelConverter |
| .getSchema(getMethod().getReturnType(), getComponents(), RequestResponse.RESPONSE); |
| mediaType.schema(schema); |
| for (String produce : produceList) { |
| content.addMediaType(produce, mediaType); |
| } |
| apiResponse.setContent(content); |
| addResponse(HttpStatuses.OK, apiResponse); |
| } |
| } |
| |
| public void setRequestBody(RequestBody requestBody) { |
| operation.requestBody(requestBody); |
| } |
| |
| public void correctResponse(ApiResponses apiResponses) { |
| |
| if (apiResponses == null) { |
| return; |
| } |
| |
| // no annotations are processed |
| // generate a default response based on the method return value |
| if (apiResponses.get(HttpStatuses.OK) == null) { |
| ApiResponse apiResponse = new ApiResponse(); |
| |
| Class<?> returnType = method.getReturnType(); |
| if (returnType == Void.TYPE || returnType == Void.class) { |
| return; |
| } |
| |
| MediaType mediaType = new MediaType(); |
| |
| Schema refSchema = ModelConverter.getSchema(returnType, getComponents(), RequestResponse.RESPONSE); |
| mediaType.schema(refSchema); |
| |
| Content content = new Content(); |
| content.addMediaType(MediaTypes.APPLICATION_JSON, mediaType); |
| apiResponse.description("OK"); |
| apiResponse.setContent(content); |
| apiResponses.addApiResponse(HttpStatuses.OK, apiResponse); |
| } |
| } |
| |
| public Components getComponents() { |
| return parentContext.getComponents(); |
| } |
| |
| public void addResponse(String key, ApiResponse response) { |
| apiResponses.addApiResponse(key, response); |
| } |
| |
| public ApiResponses getApiResponses() { |
| return apiResponses; |
| } |
| |
| public void setApiResponses(ApiResponses apiResponses) { |
| this.apiResponses = apiResponses; |
| } |
| |
| public String getOperationId() { |
| return operationId; |
| } |
| |
| public void setOperationId(String operationId) { |
| this.operationId = operationId; |
| } |
| |
| public String getPath() { |
| return path; |
| } |
| |
| public void setPath(String path) { |
| this.path = path; |
| } |
| |
| public Operation getOperation() { |
| return operation; |
| } |
| |
| public OpenAPI getOpenAPI() { |
| return parentContext.getOpenAPI(); |
| } |
| |
| public Method getMethod() { |
| return method; |
| } |
| |
| public OasContext getOpenApiContext() { |
| return parentContext; |
| } |
| |
| public String getHttpMethod() { |
| return Optional.ofNullable(httpMethod).orElse(parentContext.getHttpMethod()); |
| } |
| |
| public void setHttpMethod(String httpMethod) { |
| if (this.httpMethod != null) { |
| throw new IllegalArgumentException(String.format("too many http method in the method %s", method.getName())); |
| } |
| this.httpMethod = httpMethod.toUpperCase(); |
| } |
| |
| public Boolean getDeprecated() { |
| return deprecated; |
| } |
| |
| public void setDeprecated(Boolean deprecated) { |
| this.deprecated = deprecated; |
| } |
| |
| public String getDescription() { |
| return description; |
| } |
| |
| public void setDescription(String description) { |
| this.description = description; |
| } |
| |
| public String getSummary() { |
| return summary; |
| } |
| |
| public void setSummary(String summary) { |
| this.summary = summary; |
| } |
| |
| public List<String> getTags() { |
| return tags; |
| } |
| |
| public void setTags(List<String> tags) { |
| this.tags = tags; |
| } |
| |
| public void addTag(String tag) { |
| if (tags == null) { |
| tags = new ArrayList<>(); |
| } |
| tags.add(tag); |
| } |
| |
| @Override |
| public void addExtension(String name, Object value) { |
| operation.addExtension(name, value); |
| } |
| |
| @Override |
| public Map<String, Object> getExtensions() { |
| return operation.getExtensions(); |
| } |
| |
| public String[] getConsumers() { |
| return consumers; |
| } |
| |
| public void setConsumers(String[] consumers) { |
| this.consumers = consumers; |
| } |
| |
| public void addParamCtx(ParameterContext ctx) { |
| this.parameterContexts.add(ctx); |
| } |
| |
| public String[] getProduces() { |
| return produces; |
| } |
| |
| public void setProduces(String[] produces) { |
| this.produces = produces; |
| } |
| |
| public String[] getHeaders() { |
| return headers; |
| } |
| |
| public void setHeaders(String[] headers) { |
| this.headers = headers; |
| } |
| } |