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

org.kathra.codegen.languages.KathraJavaCodegen Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/* 
 * Copyright 2019 The Kathra Authors.
 *
 * 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.
 *
 * Contributors:
 *
 *    IRT SystemX (https://www.kathra.org/)    
 *
 */

package org.kathra.codegen.languages;

import org.kathra.codegen.*;
import io.swagger.models.*;
import io.swagger.models.parameters.*;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.PropertyBuilder;
import io.swagger.models.properties.RefProperty;
import io.swagger.util.Json;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.*;

public class KathraJavaCodegen extends AbstractJavaCodegen {

    public static final String JAVAX_ACTIVATION_FILE_DATA_SOURCE = "javax.activation.FileDataSource";
    public static final String API_MUSTACHE = "api.mustache";
    public static final String IMPORT = "import";
    public static final String API_DOC_MUSTACHE = "api_doc.mustache";
    public static final String API_TEST_MUSTACHE = "api_test.mustache";
    public static final String MODEL_DOC_MUSTACHE = "model_doc.mustache";
    public static final String MODEL_MUSTACHE = "model.mustache";
    public static final String MODEL_TEST_MUSTACHE = "model_test.mustache";
    public static final String BEANS_XML = "beans.xml";
    public static final String META_INF = "META-INF";
    public static final String MODEL = ".model.";
    public static final String IMPORTS = "imports";
    public static final String GROUP_ID = "groupId";
    public static final String ARTIFACT_ID = "artifactId";
    public static final String ARTIFACT_VERSION = "artifactVersion";
    public static final String OBJECTS = "objects";
    public static final String X_GROUP_ID = "x-groupId";
    public static final String X_MODEL_PACKAGE = "x-modelPackage";
    public static final String UNMARSHAL = "unmarshal";
    public static final String MARSHAL = "marshal";
    public static final String CLASS = ".class)";
    public static final String CLASS_ARRAY = "[].class)";
    static String tab = "    ";
    HashMap kathraImports = new HashMap();
    String apiName;
    String apiSuffix;

    public KathraJavaCodegen() {
        super();
        outputFolder = "generated-code" + File.separator + "java";
        setReservedWordsLowerCase(
                Arrays.asList(
                        // used as internal variables, can collide with parameter names
                        "localVarPath", "localVarQueryParams", "localVarHeaderParams", "localVarFormParams",
                        "localVarPostBody", "localVarAccepts", "localVarAccept", "localVarContentTypes",
                        "localVarContentType", "localVarAuthNames", "localReturnType",
                        "ApiClient", "ApiException", "Configuration", "StringUtil",

                        // language reserved words
                        "abstract", "continue", "for", "new", "switch", "assert",
                        "default", "if", "package", "synchronized", "do", "goto", "private",
                        "this", "break", "implements", "protected", "throw", "else",
                        IMPORT, "public", "throws", "case", "enum", "instanceof", "return", "transient",
                        "catch", "extends", "try", "char", "final", "interface", "static",
                        "void", "class", "finally", "strictfp", "volatile", "const",
                        "native", "super", "while", "null", "object")
        );
        supportedLibraries.put(KathraLibraryType.MODEL.getName(), "Generate Model");
        supportedLibraries.put(KathraLibraryType.INTERFACE.getName(), "Generate Interface + Api");
        supportedLibraries.put(KathraLibraryType.IMPLEM.getName(), "Generate Implementation");
        supportedLibraries.put(KathraLibraryType.CLIENT.getName(), "Generate Client");

        CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use");
        libraryOption.setEnum(supportedLibraries);
        // set model as the default
        libraryOption.setDefault(KathraLibraryType.MODEL.getName());
        cliOptions.add(libraryOption);
        setLibrary(KathraLibraryType.MODEL.getName());
        setDateLibrary("java8");
    }

    @Override
    public void processOpts() {
        super.processOpts();
        intializeAdditionalProperties();
    }

    public void intializeAdditionalProperties() {
        generateArtifactName();
        apiName = StringUtils.capitalize(apiPackage);
        artifactId = artifactId.toLowerCase();
        additionalProperties.put("apiName", apiName);
        apiPackage = apiPackage.toLowerCase();
        modelPackage = modelPackage.toLowerCase();
        additionalProperties.put(ARTIFACT_ID, artifactId);
        embeddedTemplateDir = templateDir = "Kathra/Java/" + getLibrary();
        String resourceFolder = projectFolder + File.separatorChar + "resources";
        typeMapping.put("file", "FileDataSource");
        importMapping.put("FileDataSource", "javax.activation.FileDataSource");
        if (KathraLibraryType.MODEL.getName().equalsIgnoreCase(getLibrary())) {
            apiTemplateFiles.remove(API_MUSTACHE);
            apiDocTemplateFiles.remove(API_DOC_MUSTACHE);
            apiTestTemplateFiles.remove(API_TEST_MUSTACHE);
        } else if (KathraLibraryType.INTERFACE.getName().equalsIgnoreCase(getLibrary())) {
            //TODO: tests and docs
            apiTemplateFiles.remove(API_MUSTACHE);
            apiTemplateFiles.put("service.mustache", ".java");
            modelDocTemplateFiles.remove(MODEL_DOC_MUSTACHE);
            modelTemplateFiles.remove(MODEL_MUSTACHE);
            apiDocTemplateFiles.remove(API_DOC_MUSTACHE);
            apiTestTemplateFiles.remove(API_TEST_MUSTACHE);
            modelTestTemplateFiles.remove(MODEL_TEST_MUSTACHE);
            supportingFiles.add(new SupportingFile(API_MUSTACHE, apiFolder(), apiName + "Api.java"));
            writeOptional(outputFolder(), new SupportingFile(BEANS_XML, resourceFolder + File.separatorChar + META_INF, BEANS_XML));
            writeOptional(outputFolder(), new SupportingFile("log4j.properties", resourceFolder, "log4j.properties"));
            String s = resourceFolder + File.separatorChar + META_INF + File.separatorChar + "services" + File.separatorChar + "org" + File.separatorChar + "apache" + File.separatorChar + "camel";
            writeOptional(outputFolder(), new SupportingFile("TypeConverter", s, "TypeConverter"));
            apiSuffix = "Service";
        } else if (KathraLibraryType.IMPLEM.getName().equalsIgnoreCase(getLibrary())) {
            //TODO: tests and docs
            modelDocTemplateFiles.remove(MODEL_DOC_MUSTACHE);
            modelTemplateFiles.remove(MODEL_MUSTACHE);
            modelTestTemplateFiles.remove(MODEL_TEST_MUSTACHE);
            apiDocTemplateFiles.remove(API_DOC_MUSTACHE);
            apiTestTemplateFiles.remove(API_TEST_MUSTACHE);
            writeOptional(outputFolder(), new SupportingFile(BEANS_XML, resourceFolder + File.separatorChar + META_INF, BEANS_XML));
            writeOptional(outputFolder(), new SupportingFile("Dockerfile.mustache", "Dockerfile"));
            apiSuffix = "Controller";
        } else if (KathraLibraryType.CLIENT.getName().equalsIgnoreCase(getLibrary())) {
            typeMapping.put("file", "File");
            importMapping.put("File", "java.io.File");
            modelDocTemplateFiles.remove(MODEL_DOC_MUSTACHE);
            modelTemplateFiles.remove(MODEL_MUSTACHE);
            apiDocTemplateFiles.remove(API_DOC_MUSTACHE);
            apiTestTemplateFiles.remove(API_TEST_MUSTACHE);
            modelTestTemplateFiles.remove(MODEL_TEST_MUSTACHE);
            apiSuffix = "Client";
            writeOptional(outputFolder(), new SupportingFile(BEANS_XML, resourceFolder + File.separatorChar + META_INF, BEANS_XML));
        }

        writeOptional(outputFolder(), new SupportingFile("pom.mustache", "pom.xml"));
        writeOptional(outputFolder(), new SupportingFile("README.mustache", "README.md"));
        writeOptional(outputFolder(), new SupportingFile("gitignore.mustache", ".gitignore"));
    }

    @Override
    public void preprocessSwagger(Swagger swagger) {
        super.preprocessSwagger(swagger);

        Map definitions = swagger.getDefinitions();

        if (definitions == null) definitions = new HashMap();

        HashMap dependencies = new HashMap();

        List artifactDependencies = parseKathraDependencies(swagger.getVendorExtensions());
        additionalProperties.put("artifactDependencies", artifactDependencies);

        for (Iterator> iterator = definitions.entrySet().iterator(); iterator.hasNext(); ) {
            Map.Entry modelEntry = iterator.next();
            Model model = modelEntry.getValue();
            String modelName = modelEntry.getKey();

            // Handling external models from other Api definitions
            if (model.getProperties() == null && !(model instanceof ComposedModel)) {
                dependencies.putAll(handleExternalModel(modelName, model.getVendorExtensions(), artifactDependencies));
                // TODO HANDLE OUTER ENUMS
                iterator.remove();
                continue;
            }

            // Handling autogenerated model from same Api definition
            if (!KathraLibraryType.MODEL.getName().equalsIgnoreCase(getLibrary())) {
                handleInternalModel(dependencies, modelName);
            }
        }

        if (KathraLibraryType.MODEL.getName().equalsIgnoreCase(getLibrary())) {
            for (Map.Entry modelEntry : definitions.entrySet()) {
                Model model = modelEntry.getValue();
                String modelName = modelEntry.getKey();
                processModelDescription(modelName, model);
                processModelProperties(dependencies, model);
            }
            for (HashMap dep : dependencies.values()) {
                if (!((List) dep.get(OBJECTS)).isEmpty()) {
                    addArtifactDependency(artifactDependencies, dep);
                }
            }
        } else {
            if (!KathraLibraryType.IMPLEM.getName().equalsIgnoreCase(getLibrary())) {
                for (HashMap dep : dependencies.values()) {
                    addArtifactDependency(artifactDependencies, dep);
                }
            } else {
                HashMap dep = new HashMap();
                dep.put(GROUP_ID, groupIdApi);
                dep.put(ARTIFACT_ID, artifactIdApi);
                dep.put(ARTIFACT_VERSION, artifactVersionApi);
                addArtifactDependency(artifactDependencies, dep);
            }
        }

        if (!KathraLibraryType.MODEL.getName().equalsIgnoreCase(getLibrary()) && swagger.getPaths() != null) {
            for (Path p : swagger.getPaths().values()) {
                for (Operation op : p.getOperations()) {
                    if (op.getTags() == null || op.getTags().isEmpty()) {
                        op.addTag(apiName);
                    }
                }
            }
        }
    }

    @Override
    public String apiFileFolder() {
        String s = (outputFolder() + File.separatorChar + apiFolder().toLowerCase() + File.separatorChar);
        if (KathraLibraryType.INTERFACE.getName().equalsIgnoreCase(getLibrary())) {
            return s + "service";
        } else if (KathraLibraryType.IMPLEM.getName().equalsIgnoreCase(getLibrary())) {
            return s + "controller";
        } else if (KathraLibraryType.CLIENT.getName().equalsIgnoreCase(getLibrary())) {
            return s + KathraLibraryType.CLIENT.getName();
        }
        return "";
    }

    @Override
    public String modelFileFolder() {
        return outputFolder() + File.separatorChar + modelFolder().replace('.', File.separatorChar) + File.separatorChar + KathraLibraryType.MODEL.getName();
    }

    public String apiFolder() {
        return (sourceFolder + File.separatorChar + invokerPackage.replace('.', File.separatorChar) + File.separatorChar + apiPackage().replace('.', File.separatorChar)).toLowerCase();
    }

    public String modelFolder() {
        return (sourceFolder + File.separatorChar + invokerPackage.replace('.', File.separatorChar) + File.separatorChar + modelPackage().replace('.', File.separatorChar)).toLowerCase();
    }

    @Override
    public String toModelImport(String name) {
        if (KathraLibraryType.MODEL.getName().equalsIgnoreCase(getLibrary())) {
            if (kathraImports.containsKey(name)) {
                return kathraImports.get(name);
            } else return invokerPackage + "." + modelPackage.toLowerCase() + MODEL + name;
        } else {
            if (kathraImports.containsKey(name)) {
                return kathraImports.get(name);
            } else return invokerPackage + "." + apiPackage.toLowerCase() + MODEL + name;
        }
    }

    @Override
    public Map postProcessOperations(Map objs) {
        // Override AbstractJavaCodegen.postProcessOperations() as it removes List and Map imports
        ArrayList operations = (ArrayList) ((Map) objs.get("operations")).get("operation");
        List imports = (List) objs.get(IMPORTS);
        for (CodegenOperation op : operations) {
            if ("Default".equals(op.baseName)) op.baseName = apiName;

            if (!KathraLibraryType.CLIENT.getName().equalsIgnoreCase(getLibrary())) {
                for (Map imp : imports) {
                    String imPath = (String) imp.get(IMPORT);
                    if (imPath.contains("ApiResponse")) {
                        imp.put(IMPORT, "org.kathra.utils.ApiResponse");
                    }
                }

                boolean importList = false;

                if (op.isListContainer)
                    importList=true;

                else for (CodegenParameter param : op.allParams) {
                    if (param.isListContainer) {
                        importList=true;
                        break;
                    }
                }

                if (importList) {
                    op.imports.add("List");
                    LinkedHashMap list = new LinkedHashMap();
                    list.put(IMPORT, "java.util.List");
                    if(!imports.contains(list)) imports.add(list);
                    break;
                }
            } else {
                Iterator iterator = imports.iterator();
                while (iterator.hasNext()) {
                    Map next = iterator.next();
                    String imPath = (String) next.get(IMPORT);
                    if (imPath.contains("ApiResponse")) {
                        iterator.remove();
                        break;
                    }
                }
            }
        }

        return objs;
    }

    @Override
    public Map postProcessAllModels(Map objs) {
        if (supportsInheritance) {
            // Index all CodegenModels by model name.
            Map allModels = new HashMap();
            for (Map.Entry entry : objs.entrySet()) {
                String modelName = toModelName(entry.getKey());
                Map inner = (Map) entry.getValue();
                List> models = (List>) inner.get("models");
                for (Map mo : models) {
                    CodegenModel cm = (CodegenModel) mo.get("model");
                    allModels.put(modelName, cm);
                }
            }
            // Fix up all parent and interface CodegenModel references.
            for (CodegenModel cm : allModels.values()) {
                if (cm.parent != null) {
                    cm.parentModel = allModels.get(cm.parent);
                }
                if (cm.interfaces != null && !cm.interfaces.isEmpty()) {
                    cm.interfaceModels = new ArrayList(cm.interfaces.size());
                    for (String intf : cm.interfaces) {
                        CodegenModel intfModel = allModels.get(intf);
                        if (intfModel != null) {
                            cm.interfaceModels.add(intfModel);
                        }
                    }
                }
            }
            // Let parent know about all its children
            for (CodegenModel cm : allModels.values()) {
                CodegenModel parent = allModels.get(cm.parent);
                // if a discriminator exists on the parent, don't add this child to the inheritance heirarchy
                // TODO Determine what to do if the parent discriminator name == the grandparent discriminator name
                while (parent != null) {
                    if (parent.children == null) {
                        parent.children = new ArrayList();
                    }
                    parent.children.add(cm);
                    if (parent.discriminator == null) {
                        parent = allModels.get(parent.parent);
                    } else {
                        parent = null;
                    }
                }
                handleParentVarsInheritance(cm);
                Map model = (Map) objs.get(cm.name);
                for (CodegenProperty parentVar : cm.parentVars) {
                    if (parentVar.isListContainer && !cm.imports.contains("List")) {
                        cm.imports.add("List");
                    } else if (parentVar.isMapContainer && !cm.imports.contains("Map")) {
                        cm.imports.add("Map");
                    }
                }
                model.put(IMPORTS, getModelImports(cm.imports));
                ArrayList imports = (ArrayList) model.get(IMPORTS);
                for (Iterator iterator = imports.iterator(); iterator.hasNext(); ) {
                    HashMap imp = iterator.next();
                    String anImport = (String) imp.get(IMPORT);
                    if (anImport.contains(invokerPackage + "." + modelPackage.toLowerCase() + MODEL)) {
                        iterator.remove();
                    }
                }
            }
        }
        return objs;
    }

    private List parseKathraDependencies(Map vendorExtensions) {
        if (vendorExtensions != null && !vendorExtensions.isEmpty() && vendorExtensions.containsKey("x-dependencies")) {
            return (List) vendorExtensions.get("x-dependencies");
        }
        return new ArrayList();
    }

    private void handleInternalModel(HashMap dependencies, String modelName) {
        kathraImports.put(modelName, invokerPackage + "." + apiPackage.toLowerCase() + MODEL + modelName);
        if (!dependencies.containsKey(kathraImports.get(modelName))) {
            HashMap dep = new HashMap();
            dep.put(GROUP_ID, groupId);
            dep.put(ARTIFACT_ID, artifactId.substring(0, artifactId.lastIndexOf('-') + 1) + KathraLibraryType.MODEL.getName());
            dep.put("modelPackage", apiPackage.toLowerCase());
            dep.put(ARTIFACT_VERSION, artifactVersion);
            dependencies.put(kathraImports.get(modelName), dep);
        }
    }

    private Map handleExternalModel(String modelName, Map vendorExtensions, List artifactDependencies) {
        HashMap dependencies = new HashMap();
        String artifactId = (String) vendorExtensions.get("x-artifactId");
        String groupId = (String) vendorExtensions.get(X_GROUP_ID);
        String modelPackage = (String) vendorExtensions.get(X_MODEL_PACKAGE);
        String artifactVersion = (String) vendorExtensions.get("x-artifactVersion");
        if (vendorExtensions.isEmpty() || artifactId == null) {
            return dependencies;
        } else {
            Map dependency = null;
            for (Map dep : artifactDependencies) {
                if (dep.get(ARTIFACT_ID).equals(artifactId)) {
                    dependency = dep;
                    break;
                }
            }
            if (dependency != null) {
                if (groupId == null) groupId = (String) dependency.get(GROUP_ID);
                if (artifactVersion == null) artifactVersion = (String) dependency.get(ARTIFACT_VERSION);
                if (modelPackage == null) modelPackage = (String) dependency.get("modelPackage");
                kathraImports.put(modelName, groupId + "." + modelPackage + "." + modelName);
                if (!dependencies.containsKey(kathraImports.get(modelName))) {
                    HashMap dep = new HashMap();
                    dep.put(GROUP_ID, groupId);
                    dep.put(ARTIFACT_ID, artifactId);
                    dep.put("modelPackage", modelPackage);
                    dep.put(ARTIFACT_VERSION, artifactVersion);
                    if (KathraLibraryType.MODEL.getName().equalsIgnoreCase(getLibrary()))
                        dep.put(OBJECTS, new ArrayList());
                    dependencies.put(kathraImports.get(modelName), dep);
                }
            }
        }
        return dependencies;
    }

    private void addArtifactDependency(List artifactDependencies, HashMap dep) {
        if (!artifactDependencies.contains(dep)) artifactDependencies.add(dep);
    }

    private void processModelProperties(HashMap dependencies, Model model) {
        if (model.getProperties() != null) {
            for (Map.Entry propertyEntry : model.getProperties().entrySet()) {
                Property property = propertyEntry.getValue();
                String refName = null;

                if (property instanceof RefProperty) refName = ((RefProperty) property).getSimpleRef();
                else if (property instanceof RefModel) refName = ((RefModel) property).getSimpleRef();

                countDependency(dependencies, refName);
            }
        } else if (model instanceof ComposedModel) {
            ComposedModel cmodel = (ComposedModel) model;
            processModelProperties(dependencies, cmodel.getChild());
            countDependency(dependencies, cmodel.getInterfaces().get(0).getSimpleRef());
        }
    }

    private void countDependency(HashMap dependencies, String refName) {
        if (refName != null && kathraImports.containsKey(refName)) {
            HashMap dep = dependencies.get(kathraImports.get(refName));
            if (!((ArrayList) dep.get(OBJECTS)).contains(refName)) {
                ((ArrayList) dep.get(OBJECTS)).add(refName);
            }
        }
    }

    private void processModelDescription(String modelName, Model model) {
        if (model.getDescription() == null || model.getDescription().isEmpty()) {
            model.setDescription(modelName);
        }
        if (model.getProperties() != null) {
            for (Map.Entry propertyEntry : model.getProperties().entrySet()) {
                Property property = propertyEntry.getValue();
                if (property.getDescription() == null || property.getDescription().isEmpty()) {
                    property.setDescription(propertyEntry.getKey());
                }
            }
        } else if (model instanceof ComposedModel) {
            ComposedModel cmodel = (ComposedModel) model;
            cmodel.setParent(cmodel.getInterfaces().get(0));
            if (cmodel.getChild() == null) {
                cmodel.setChild(new ModelImpl().type("object"));
            }
            ModelImpl modelImpl = (ModelImpl) cmodel.getChild();
            processModelDescription(modelName, modelImpl);
        }
    }

    @Override
    public Map postProcessSupportingFileData(Map objs) {
        if (KathraLibraryType.INTERFACE.getName().equalsIgnoreCase(getLibrary())) {
            ArrayList myImps = new ArrayList();
            handleAuthForApi(objs, myImps);
            Map gsonDataFormat = new LinkedHashMap();
            gsonDataFormat.put(IMPORT, "org.apache.camel.model.dataformat.JsonLibrary");
            HashMap apiInfo = (HashMap) objs.get("apiInfo");
            ArrayList apis = (ArrayList) apiInfo.get("apis");
            ArrayList endpoints = new ArrayList();
            Swagger swagger = (Swagger) objs.get("swagger");
            Map paths = swagger.getPaths();
            objs.put(IMPORTS, myImps);
            for (HashMap api : apis) {
                postProcessImports(myImps, api);
                HashMap operations = (HashMap) api.get("operations");
                ArrayList operationList = (ArrayList) operations.get("operation");
                for (CodegenOperation op : operationList) {
                    postProcessOperation(gsonDataFormat, endpoints, paths, myImps, op);
                }
            }
            objs.put("endpoints", endpoints);
        }
        return objs;
    }

    public void handleAuthForApi(Map objs, List imports) {
        ArrayList authMethods = (ArrayList) objs.get("authMethods");
        if (authMethods != null && !authMethods.isEmpty()) {
            for (CodegenSecurity authMethod : authMethods) {
                if (authMethod.name.equalsIgnoreCase("kathra_auth")) {
                    objs.put("kathraAuth", "KeycloakUtils.init();\n" + tabs(2));
                    Map keyCloakUtilsImport = new LinkedHashMap();
                    keyCloakUtilsImport.put(IMPORT, "org.kathra.utils.security.KeycloakUtils");
                    imports.add(keyCloakUtilsImport);
                    break;
                }
            }
        }
    }

    private void postProcessOperation(Map gsonDataFormat, ArrayList endpoints, Map paths, ArrayList myImps, CodegenOperation op) {
        HashMap endpoint = new HashMap();
        if (op.hasConsumes) {
            List> consumes = op.consumes;
            endpoint.put("consumes", ".consumes(\"" + consumes.get(0).get("mediaType") + "\")");
        }
        if (op.hasProduces) {
            List> produces = op.produces;
            endpoint.put("produces", ".produces(\"" + produces.get(0).get("mediaType") + "\")");
        }
        endpoint.put("tag", op.tags.get(0).getName());
        endpoint.put("httpMethod", op.httpMethod.toLowerCase());
        endpoint.put("path", op.path);
        endpoint.put("description", op.summary);
        endpoint.put(UNMARSHAL, "");

        List responses = op.responses;
        postProcessResponses(op, endpoint, responses);

        List allParams = op.allParams;
        ArrayList params = new ArrayList();
        endpoint.put("params", params);
        endpoint.put("body", "");
        StringBuilder methodParams = new StringBuilder().append("(");
        postProcessParameters(gsonDataFormat, paths, myImps, endpoint, allParams, params, methodParams);

        final String classnameSessionHandler = "KathraAuthRequestHandlerImpl.class";

        endpoint.put("method", op.operationId);
        endpoint.put("exceptionHandling",
                ".onException(Exception.class)\n" +
                        tabs(5) + ".bean(" + classnameSessionHandler + ",\"handleException\")\n" +
                        tabs(5) + ".bean(" + classnameSessionHandler + ",\"deleteSession\")\n" +
                        tabs(5) + ".handled(true).stop().end()");
        endpoint.put("route", ".to(\"bean:" + op.baseName + "Controller?");
        if (!op.isResponseFile && !endpoint.containsKey(MARSHAL)) {
            endpoint.put(MARSHAL, "\n" + tabs(4) + ".marshal().json(JsonLibrary.Gson)");
            if (!myImps.contains(gsonDataFormat)) myImps.add(gsonDataFormat);
        }
        if (op.hasAuthMethods) {
            endpoint.put("preprocess", ".bean(" + classnameSessionHandler + ",\"handleAuthenticatedRequest\")");
        } else {
            endpoint.put("preprocess", ".bean(" + classnameSessionHandler + ",\"handleRequest\")");
        }
        endpoint.put("postprocess", ".bean(" + classnameSessionHandler + ",\"postProcessResponse\")");
        endpoints.add(endpoint);
    }

    private void postProcessImports(ArrayList myImps, HashMap api) {
        ArrayList imports = (ArrayList) api.get(IMPORTS);
        for (Map imp : imports) {
            String imPath = (String) imp.get(IMPORT);
            if (imPath == null) {
                continue;
            }
            if (imPath.contains("ApiResponse")) {
                imp.put(IMPORT, "org.kathra.utils.ApiResponse");
            }
            if (!imPath.equals("java.util.List") && !imPath.equals(JAVAX_ACTIVATION_FILE_DATA_SOURCE) && !myImps.contains(imp)) {
                myImps.add(imp);
            }
        }
    }

    private void postProcessResponses(CodegenOperation op, HashMap endpoint, List responses) {
        for (CodegenResponse response : responses) {
            if (response.code.equals("200")) {
                if (response.isListContainer && op.returnBaseType != null) {
                    endpoint.put("outType", ".outType(" + op.returnBaseType + CLASS_ARRAY);
                } else if (!response.isListContainer && op.returnType != null && !op.returnType.equalsIgnoreCase("filedatasource")) {
                    endpoint.put("outType", ".outType(" + op.returnType + CLASS);
                    if (op.returnType.equalsIgnoreCase("ApiResponse")) op.imports.add("ApiResponse");
                }
                break;
            }
        }
    }

    private void postProcessParameters(Map gsonDataFormat, Map paths, ArrayList myImps, HashMap endpoint, List allParams, ArrayList params, StringBuilder methodParams) {
        for (CodegenParameter param : allParams) {
            HashMap parameter = new HashMap();
            parameter.put("name", param.baseName);
            LinkedHashMap listImport = new LinkedHashMap();
            listImport.put("import",importMapping.get("List"));
            if(param.isListContainer && !myImps.contains(listImport)) {
                myImps.add(listImport);
            }
            if (param.isBodyParam && !param.isPrimitiveType) {
                if (param.isListContainer) {
                    endpoint.put("type", ".type(" + param.baseType + CLASS_ARRAY);
                    endpoint.put(UNMARSHAL, "\n" + tabs(4) + ".unmarshal().json(JsonLibrary.Gson," + param.baseType + CLASS_ARRAY);
                } else {
                    endpoint.put("type", ".type(" + param.dataType + CLASS);
                    endpoint.put(UNMARSHAL, "\n" + tabs(4) + ".unmarshal().json(JsonLibrary.Gson," + param.dataType + CLASS);
                }
                if (!myImps.contains(gsonDataFormat)) myImps.add(gsonDataFormat);
            }
            Path path = paths.get(endpoint.get("path"));
            Operation operation = path.getOperationMap().get(HttpMethod.valueOf(((String) endpoint.get("httpMethod")).toUpperCase()));
            List parameters = operation.getParameters();
            for (Parameter par : parameters) {
                if (par.getName().equals(parameter.get("name"))) {
                    parameter.put("required", "\n" + tabs(5) + ".required(" + par.getRequired() + ")");
                    String dataType = null;
                    if (par instanceof PathParameter) {
                        PathParameter pathPar = (PathParameter) par;
                        dataType = pathPar.getType();
                    } else if (par instanceof QueryParameter) {
                        QueryParameter queryPar = (QueryParameter) par;
                        dataType = queryPar.getType();
                        if (queryPar.getEnum() != null && !queryPar.getEnum().isEmpty()) {
                            StringBuilder sb = new StringBuilder();
                            sb.append("\n" + tabs(5) + ".allowableValues(");
                            for (String allowableValue : queryPar.getEnum()) {
                                sb.append('"').append(allowableValue).append("\",");
                            }
                            sb.replace(sb.length() - 1, sb.length(), ")");
                            parameter.put("allowableValues", sb.toString());
                        }
                    } else if (par instanceof FormParameter) {
                        FormParameter formPar = (FormParameter) par;
                        dataType = formPar.getType();
                    }

                    if (par instanceof BodyParameter) methodParams.append("${body},");
                    else methodParams.append("${header." + par.getName() + "},");

                    if (dataType != null)
                        parameter.put("dataType", "\n" + tabs(5) + ".dataType(\"" + dataType + "\")");

                    parameter.put("type", par.getIn());
                    parameter.put("description", par.getDescription());
                    break;
                }
            }
            params.add(parameter);
        }
        if (methodParams.length() > 1) {
            methodParams.deleteCharAt(methodParams.length() - 1);
            methodParams.append(")");
            endpoint.put("methodParams", methodParams.toString());
        } else {
            endpoint.put("methodParams", "");
        }
    }

    private void generateArtifactName() {
        String[] parts = artifactId.split("\\-");
        StringBuilder f = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            String z = parts[i];
            if (z.length() > 0) {
                if (i == 0) {
                    f.append(z.toUpperCase());
                } else {
                    f.append(StringUtils.capitalize(z));
                }

                if (i < parts.length - 1) {
                    f.append(" :: ");
                }
            }
        }
        additionalProperties.put("artifactName", f.toString());
    }

    @Override
    public CodegenModel fromModel(String name, Model model, Map allDefinitions) {
        CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL);
        if (reservedWords.contains(name)) {
            m.name = escapeReservedWord(name);
        } else {
            m.name = name;
        }
        m.title = escapeText(model.getTitle());
        m.description = escapeText(model.getDescription());
        m.unescapedDescription = model.getDescription();
        m.classname = toModelName(name);
        m.classVarName = toVarName(name);
        m.classFilename = toModelFilename(name);
        m.modelJson = Json.pretty(model);
        m.externalDocs = model.getExternalDocs();
        m.vendorExtensions = model.getVendorExtensions();

        if (model instanceof ModelImpl) {
            m.discriminator = ((ModelImpl) model).getDiscriminator();
        }

        if (model instanceof ArrayModel) {
            ArrayModel am = (ArrayModel) model;
            ArrayProperty arrayProperty = new ArrayProperty(am.getItems());
            m.isArrayModel = true;
            m.arrayModelType = fromProperty(name, arrayProperty).complexType;
            addParentContainer(m, name, arrayProperty);
        } else if (model instanceof RefModel) {
            // TODO
        } else if (model instanceof ComposedModel) {
            final ComposedModel composed = (ComposedModel) model;
            Map properties = new LinkedHashMap();
            List required = new ArrayList();
            Map allProperties;
            List allRequired;
            if (supportsInheritance || supportsMixins) {
                allProperties = new LinkedHashMap();
                allRequired = new ArrayList();
                m.allVars = new ArrayList();
                int modelImplCnt = 0; // only one inline object allowed in a ComposedModel
                for (Model innerModel : ((ComposedModel) model).getAllOf()) {
                    if (innerModel instanceof ModelImpl) {
                        if (m.discriminator == null) {
                            m.discriminator = ((ModelImpl) innerModel).getDiscriminator();
                        }
                        if (modelImplCnt++ > 1) {
                            LOGGER.warn("More than one inline schema specified in allOf:. Only the first one is recognized. All others are ignored.");
                            break; // only one ModelImpl with discriminator allowed in allOf
                        }
                    }
                }
            } else {
                allProperties = null;
                allRequired = null;
            }
            // parent model
            RefModel parent = (RefModel) composed.getParent();

            // interfaces (intermediate models)
            if (composed.getInterfaces() != null) {
                if (m.interfaces == null)
                    m.interfaces = new ArrayList();
                for (RefModel _interface : composed.getInterfaces()) {
                    Model interfaceModel = null;
                    if (allDefinitions != null) {
                        interfaceModel = allDefinitions.get(_interface.getSimpleRef());
                    }
                    // set first interface with discriminator found as parent
                    if (parent == null
                                && ((interfaceModel instanceof ModelImpl && ((ModelImpl) interfaceModel).getDiscriminator() != null)
                                            || (interfaceModel instanceof ComposedModel && isDiscriminatorInInterfaceTree((ComposedModel) interfaceModel, allDefinitions)))) {
                        parent = _interface;
                    } else {
                        final String interfaceRef = toModelName(_interface.getSimpleRef());
                        m.interfaces.add(interfaceRef);
                        addImport(m, interfaceRef);
                    }
                }
            }

            if (parent != null) {
                final String parentRef = parent.getSimpleRef();
                m.parentSchema = parentRef;
                m.parent = toModelName(parent.getSimpleRef());
                addImport(m, m.parent);
            }

            // child model (properties owned by the model itself)
            Model child = composed.getChild();
            if (child != null && child instanceof RefModel && allDefinitions != null) {
                final String childRef = ((RefModel) child).getSimpleRef();
                child = allDefinitions.get(childRef);
            }
            if (child != null && child instanceof ModelImpl) {
                addProperties(properties, required, child, allDefinitions);
                if (supportsInheritance) {
                    addProperties(allProperties, allRequired, child, allDefinitions);
                }
            }
            addVars(m, properties, required, allProperties, allRequired);
        } else {
            ModelImpl impl = (ModelImpl) model;
            if (impl.getType() != null) {
                Property p = PropertyBuilder.build(impl.getType(), impl.getFormat(), null);
                if (!impl.getType().equals("object") && impl.getEnum() == null) {
                    typeAliases.put(name, impl.getType());
                    m.isAlias = true;
                }
                m.dataType = getSwaggerType(p);
            }
            if (impl.getEnum() != null && !impl.getEnum().isEmpty()) {
                m.isEnum = true;
                // comment out below as allowableValues is not set in post processing model enum
                m.allowableValues = new HashMap();
                m.allowableValues.put("values", impl.getEnum());
            }
            if (impl.getAdditionalProperties() != null) {
                addAdditionPropertiesToCodeGenModel(m, impl);
            }
            addVars(m, impl.getProperties(), impl.getRequired());
        }

        if (!BooleanUtils.toBoolean(m.isEnum)) {
            // needed by all pojos, but not enums
            if (m.vars != null && !m.vars.isEmpty()) m.imports.add("ApiModelProperty");
            m.imports.add("ApiModel");
        }

        if (m.vars != null) {
            for (CodegenProperty prop : m.vars) {
                postProcessModelProperty(m, prop);
            }
        }
        return m;
    }

    private String tabs(int number) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < number; i++) {
            sb.append(tab);
        }
        return sb.toString();
    }

    /**
     * Configures the type of generator.
     *
     * @return the CodegenType for this generator
     * @see CodegenType
     */
    public CodegenType getTag() {
        return CodegenType.SERVER;
    }

    /**
     * Configures a friendly name for the generator.  This will be used by the generator
     * to select the library with the -l flag.
     *
     * @return the friendly name for the generator
     */
    public String getName() {
        return "KathraJava";
    }

    /**
     * Returns human-friendly help for the generator.  Provide the consumer with help
     * tips, parameters here
     *
     * @return A string value for the help message
     */
    public String getHelp() {
        return "Generates a KathraJava.";
    }

    @Override
    public String toApiName(String name) {
        if (name.length() == 0) {
            return initialCaps(apiName) + apiSuffix;
        }
        return initialCaps(name) + apiSuffix;
    }

    public String outputFolder() {
        return outputFolder.toLowerCase();
    }

    private CodegenModel handleParentVarsInheritance(CodegenModel m) {
        if (m.parentModel != null) {
            CodegenModel parentModelWithParentVars = handleParentVarsInheritance(m.parentModel);
            m.parentVars.addAll(parentModelWithParentVars.parentVars);
            m.parentVars.addAll(parentModelWithParentVars.vars);
            m.parentVars = new ArrayList(new LinkedHashSet(m.parentVars));
        }
        return m;
    }

    private List> getModelImports(Set allImports) {
        Set importSet = new TreeSet();
        for (String nextImport : allImports) {
            String mapping = importMapping().get(nextImport);
            if (mapping == null) {
                mapping = toModelImport(nextImport);
            }
            if (mapping != null && !defaultIncludes().contains(mapping)) {
                importSet.add(mapping);
            }
            // add instantiation types
            mapping = instantiationTypes().get(nextImport);
            if (mapping != null && !defaultIncludes().contains(mapping)) {
                importSet.add(mapping);
            }
        }
        List> imports = new ArrayList();
        for (String s : importSet) {
            Map item = new HashMap();
            item.put("import", s);
            imports.add(item);
        }
        return imports;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy