package com.bagri.rest.service;
import static com.bagri.rest.RestConstants.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bagri.core.system.Function;
import com.bagri.core.system.Parameter;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.jaxrs.Reader;
import io.swagger.jaxrs.config.ReaderListener;
import io.swagger.jaxrs.config.SwaggerConfigLocator;
import io.swagger.jaxrs.config.SwaggerContextService;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Response;
import io.swagger.models.Scheme;
import io.swagger.models.Swagger;
import io.swagger.models.Tag;
import io.swagger.models.parameters.BodyParameter;
import io.swagger.models.parameters.CookieParameter;
import io.swagger.models.parameters.FormParameter;
import io.swagger.models.parameters.HeaderParameter;
import io.swagger.models.parameters.PathParameter;
import io.swagger.models.parameters.QueryParameter;
import io.swagger.models.parameters.RefParameter;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.PropertyBuilder;
import io.swagger.models.properties.StringProperty;
//import io.swagger.util.
@SwaggerDefinition()
public class SwaggerListener implements ReaderListener {
private static final Logger logger = LoggerFactory.getLogger(SwaggerListener.class);
private static List<RestMethod> restMethods = new ArrayList<>();
public SwaggerListener() {
logger.debug("SwaggerListener.<init>");
}
public static void addFunction(String basePath, Function fn) {
restMethods.add(new RestMethod(basePath, fn));
}
public static void clearFunctions() {
restMethods.clear();
}
@Override
public void beforeScan(Reader reader, Swagger swagger) {
//
}
@Override
public void afterScan(Reader reader, Swagger swagger) {
logger.debug("afterScan.enter; methods to process: {}; swagger: {}", restMethods.size(), swagger);
for (RestMethod rm: restMethods) {
String base = rm.getBasePath();
Function fn = rm.getFunction();
logger.debug("afterScan; processing function: {}", fn);
Map<String, List<String>> annotations = fn.getAnnotations();
List<String> consumes = annotations.get(an_consumes);
List<String> produces = annotations.get(an_produces);
List<String> paths = annotations.get(an_path);
String fullPath = base;
if (paths != null) {
fullPath += paths.get(0);
}
Path path = swagger.getPath(fullPath);
if (path == null) {
path = new Path();
}
for (String method: methods) {
List<String> values = annotations.get("rest:" + method);
if (values != null) {
Operation op = new Operation();
op.addScheme(Scheme.HTTP);
op.addScheme(Scheme.HTTPS);
op.setDescription(fn.getDescription());
if (consumes != null) {
op.consumes(consumes);
}
if (produces != null) {
op.produces(produces);
}
op.setOperationId(fn.getMethod());
op.setSummary(fn.getSignature());
op.addTag(base.substring(1));
for (Parameter param: fn.getParameters()) {
String pName = param.getName();
io.swagger.models.parameters.Parameter pm = null;
if (rm.isPathParameter(pName)) {
pm = new PathParameter().type(param.getType()).required(true);
} else {
String aType = rm.getParamAnnotationType(pName);
if (aType == null) {
// this is for POST/PUT only!
if (POST.equals(method) || PUT.equals(method)) {
pm = new BodyParameter();
}
} else {
switch (aType) {
case apn_cookie: {
pm = new CookieParameter().type(param.getType());
break;
}
case apn_form: {
pm = new FormParameter().type(param.getType());
break;
}
case apn_header: {
pm = new HeaderParameter().type(param.getType());
break;
}
case apn_matrix: {
// no MatrixParameter in Swagger! just to get something:
pm = new PathParameter().description("This is a MatrixParameter, which is not supported by Swagger. " +
"Please add custom client code to pass the parameter properly.").items(new MapProperty(new StringProperty())).type(param.getType());
//PropertyBuilder.build(type, format, args);
break;
}
case apn_query: {
pm = new QueryParameter().type(param.getType());
break;
}
}
}
}
if (pm != null) {
pm.setName(pName);
op.addParameter(pm);
}
}
op.defaultResponse(new Response());
//io.swagger.models.properties.PropertyBuilder.
path.set(method.toLowerCase(), op);
logger.debug("afterScan; added op: {} for method {}", op, method);
}
}
swagger.path(fullPath, path);
logger.debug("afterScan; set path: {}", path.getOperations());
if (consumes != null) {
for (String consume: consumes) {
swagger.addConsumes(consume);
}
}
if (produces != null) {
for (String produce: produces) {
swagger.addProduces(produce);
}
}
swagger.tag(new Tag().name(base.substring(1)));
}
//String configIdKey = SwaggerContextService.CONFIG_ID_DEFAULT;
//SwaggerConfigLocator.getInstance().putSwagger(configIdKey, swagger);
}
private static class RestMethod {
private String basePath;
private Function fn;
RestMethod(String basePath, Function fn) {
this.basePath = basePath;
this.fn = fn;
}
public String getBasePath() {
return basePath;
}
public Function getFunction() {
return fn;
}
public boolean isPathParameter(String pName) {
List<String> pa = fn.getAnnotations().get(an_path);
return (pa != null && pa.size() == 1 && pa.get(0).indexOf("{" + pName + "}") > 0);
}
public String getParamAnnotationType(String pName) {
String xpName = "{$" + pName + "}";
for (Map.Entry<String, List<String>> ant: fn.getAnnotations().entrySet()) {
for (String val: ant.getValue()) {
if (pName.equals(val) || xpName.equals(val)) {
return ant.getKey();
}
}
}
return null;
}
}
}