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

io.virtualan.core.VirtualServiceInfo Maven / Gradle / Ivy

There is a newer version: 3.1.0
Show newest version
/*
 * Copyright 2018 Virtualan Contributors (https://virtualan.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.virtualan.core;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.virtualan.annotation.ApiVirtual;
import io.virtualan.annotation.VirtualService;
import io.virtualan.api.ApiMethod;
import io.virtualan.api.ApiResource;
import io.virtualan.api.ApiType;
import io.virtualan.core.model.ResourceMapper;
import io.virtualan.core.model.VirtualServiceApiResponse;
import io.virtualan.core.model.VirtualServiceKeyValue;
import io.virtualan.core.model.VirtualServiceRequest;


/**
 * This interface is base for all VirtualService types
 *
 *
 * @author  Elan Thangamani
 * @see     io.virtualan.core.OpenApiVirtualServiceInfo
 * @see     io.virtualan.core.SpringVirtualServiceInfo
 */

public interface VirtualServiceInfo {

    @Slf4j
    final class LogHolder
    {}

    ApiType getApiType();

    void setApiType(ApiType apiType);

    ObjectMapper getObjectMapper();

    void setObjectMapper(ObjectMapper objectMapper);

    ResourceMapper getResourceParent();

    void setResourceParent(ResourceMapper resourceParent);

    Map> getMockLoadChoice();

    void setMockLoadChoice(Map> mockLoadChoice);

    void buildInput(Method method, VirtualServiceRequest mockLoadRequest)
        throws JsonProcessingException, InstantiationException, IllegalAccessException,
        ClassNotFoundException;


    default String getResourceDesc(Method method) {
        ApiOperation[] apiOperationAnno = method.getAnnotationsByType(ApiOperation.class);
        if (apiOperationAnno != null && apiOperationAnno.length > 0) {
            return apiOperationAnno[0].notes();
        }
        return null;
    }

    default Map findVirtualServices() {
        Map virtualInterfaces = new HashMap<>();
        try {
            Field f = ClassLoader.class.getDeclaredField("classes");
            f.setAccessible(true);
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            List classes = (List) f.get(classLoader);
            for (int i = 0; i < classes.size(); i++) {
                Class classzz = classes.get(i);
                loadClasses(virtualInterfaces, classzz);
            }
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException
            | IllegalAccessException e1) {
            LogHolder.log.error("Unable to load from the class loader {}" , e1.getMessage());
        }
        return virtualInterfaces;
    }

    default void loadClasses(Map virtualInterfaces, Class classzz) {
        try {
            if (classzz.isAnnotationPresent(VirtualService.class)) {
                String interfaceName = classzz.getTypeName();
                interfaceName = interfaceName.substring(interfaceName.lastIndexOf('.') + 1
                );
                interfaceName = interfaceName.toLowerCase();
                virtualInterfaces.put(interfaceName, classzz);
            }
        } catch (ArrayStoreException e) {
            // ignore it
        }
    }


    default Map> loadVirtualServices(boolean scriptEnabled)
        throws ClassNotFoundException, JsonProcessingException, InstantiationException,
        IllegalAccessException {
        Map> mockLoadChoice = getMockLoadChoice();
        if (mockLoadChoice == null) {
            mockLoadChoice = new TreeMap<>();
            for (Map.Entry virtualServiceEntry : findVirtualServices().entrySet()) {
                Map mockAPILoadChoice =
                    buildVirtualServiceInfo(scriptEnabled, virtualServiceEntry);
                if (!mockAPILoadChoice.isEmpty()) {
                    Map> resourceGroup =
                        mockAPILoadChoice.entrySet().stream().filter(x -> !"virtualanendpoint".equalsIgnoreCase(x.getKey()))
                            .collect(Collectors.groupingBy(f -> f.getValue().getResource(),
                                Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
                    mockLoadChoice.putAll(resourceGroup);
                }
            }
        }
        setMockLoadChoice(mockLoadChoice);
        return mockLoadChoice;
    }

    default Map buildVirtualServiceInfo(boolean scriptEnabled,
        Map.Entry virtualServiceEntry) throws JsonProcessingException,
        InstantiationException, IllegalAccessException, ClassNotFoundException {
        Map mockAPILoadChoice =
            new LinkedHashMap<>();
        for (Method method : virtualServiceEntry.getValue().getDeclaredMethods()) {
            ApiVirtual[] annotInstance = method.getAnnotationsByType(ApiVirtual.class);
            if (annotInstance != null && annotInstance.length > 0) {
                VirtualServiceRequest mockReturn = buildServiceDetails(scriptEnabled, virtualServiceEntry, method);
                if (mockReturn != null) {
                    mockAPILoadChoice.put(method.getName(), mockReturn);
                }
            }
        }
        return mockAPILoadChoice;
    }

    default Class getInputType(VirtualServiceRequest mockTransferInput) {
        Class inputType = null;

        if (mockTransferInput.getResource() == null) {
            mockTransferInput.setResource(ApiResource.getResourceByURL(mockTransferInput.getUrl()));
        }
        if (mockTransferInput.getOperationId() != null) {
            VirtualServiceRequest mockTransferActual = getMockLoadChoice()
                .get(mockTransferInput.getResource()).get(mockTransferInput.getOperationId());
            if (mockTransferActual != null) {
                inputType = mockTransferActual.getInputObjectType();
            }
        } else {
            String resourceUrl =
                mockTransferInput.getUrl().substring(1);
            List resouceSplitterList =
                new LinkedList(Arrays.asList(resourceUrl.split("/")));
            if (!resouceSplitterList.isEmpty()) {
                String operationId = getOperationId(mockTransferInput.getMethod(),
                    getResourceParent(), resouceSplitterList);
                VirtualServiceRequest mockTransferActual =
                    getMockLoadChoice().get(mockTransferInput.getResource()).get(operationId);
                if (mockTransferActual != null) {
                    inputType = mockTransferActual.getInputObjectType();
                }
            }
        }
        return inputType;
    }

    default Map buildOpenAPIResponseType(Method method) {
        Map responseType = new HashMap<>();
        ApiResponses[] apiResponsesAnno = method.getAnnotationsByType(ApiResponses.class);
        if (apiResponsesAnno != null) {
            for (ApiResponses apiResponses : apiResponsesAnno) {
                for (ApiResponse apiResponse : apiResponses.value()) {
                    try {
                        if(!responseType.containsKey(String.valueOf(apiResponse.code()))) {
                            responseType
                                .put(String.valueOf(apiResponse.code()),
                                    new VirtualServiceApiResponse(
                                        String.valueOf(apiResponse.code()),
                                        apiResponse.response().getCanonicalName(),
                                        getObjectMapper().writerWithDefaultPrettyPrinter()
                                            .writeValueAsString(Class
                                                .forName(apiResponse.response()
                                                    .getCanonicalName())
                                                .getDeclaredConstructor().newInstance()),
                                        apiResponse.message()));
                        }
                    } catch (Exception e) {
                        responseType.put(String.valueOf(apiResponse.code()),
                            new VirtualServiceApiResponse(String.valueOf(apiResponse.code()),
                                null, null, apiResponse.message()));
                    }
                }
            }

        }
        return responseType;
    }

    default String getOperationId(String httpVerb, ResourceMapper resourceParent,
        List resouceSplitterList) {
        if (resouceSplitterList.isEmpty()) {
            return resourceParent.getOperationId(httpVerb);
        }
        String resource = resouceSplitterList.get(0);
        ResourceMapper mapper = resourceParent.findResource(resource);
        if (mapper != null) {
            return getOperationId(httpVerb, mapper,
                resouceSplitterList.subList(1, resouceSplitterList.size()));
        } else {
            return getOperationId(httpVerb, resourceParent.findResource(VirtualServiceConstants.CURLY_PATH),
                resouceSplitterList.subList(1, resouceSplitterList.size()));
        }

    }

    // RE THINK ABOUT IT
    default VirtualServiceRequest getResponseType(VirtualServiceRequest mockTransferInput) {
        if(mockTransferInput != null && mockTransferInput.getUrl() != null) {
            int index = mockTransferInput.getUrl().indexOf('/', 1) == -1
                ? mockTransferInput.getUrl().length() : mockTransferInput.getUrl().indexOf('/', 1);
            if (mockTransferInput.getResource() == null) {
                mockTransferInput.setResource(mockTransferInput.getUrl().substring(1, index));
            }
        }
        if (mockTransferInput != null && mockTransferInput.getOperationId() != null) {
            return getMockLoadChoice().get(mockTransferInput.getResource())
                .get(mockTransferInput.getOperationId());
        }
        return null;
    }



    default Map getTypes(boolean scriptEnabled) {
        Map map = new LinkedHashMap<>();
        map.put("RESPONSE", "Response");
        map.put("PARAMS", "Params");
        if(scriptEnabled) {
            map.put("RULE", "Rule");
            map.put("SCRIPT", "Script");
        }
        return map;
    }


    default Map getHttpStatusMap() {
        Map map = new LinkedHashMap<>();
        for (HttpStatus status : HttpStatus.values()) {
            map.put(String.valueOf(status.value()), status.name());
        }
        return map;
    }

    default ResourceMapper loadMapper() {
        Set resourceMapperList = new LinkedHashSet<>();
        ResourceMapper resourceParent = new ResourceMapper(VirtualServiceConstants.PARENT_ROOT, resourceMapperList);
        for (Entry> obj : getMockLoadChoice()
            .entrySet()) {
            for (Entry requestMockObject : obj.getValue()
                .entrySet()) {
                String resource = requestMockObject.getValue().getUrl().substring(1
                );
                List resouceSplitterList =
                    new LinkedList(Arrays.asList(resource.split("/")));
                if (!resouceSplitterList.isEmpty()) {
                    ResourceMapper mapperChild = buildHierarchyObject(
                        requestMockObject.getValue().getMethod(), resourceParent,
                        resouceSplitterList, requestMockObject.getKey());
                    resourceParent.addResourceMapper(mapperChild);
                }
            }
        }
        return resourceParent;
    }

    default ResourceMapper buildHierarchyObject(String httpVerb, ResourceMapper resourceParent,
        List resouceSplitterList, String operationId) {
        String resource = resouceSplitterList.get(0);
        String actualResource = resouceSplitterList.get(0);
        final Matcher matcher = VirtualServiceConstants.pattern.matcher(resouceSplitterList.get(0));
        if (matcher.find()) {
            resource = VirtualServiceConstants.CURLY_PATH;
        }
        if (resouceSplitterList.size() == 1) {
            ResourceMapper resourceMapper = resourceParent.findResource(resource);
            if (resourceMapper == null) {
                resourceMapper = new ResourceMapper(resource);
                resourceMapper.setActualResource(actualResource);
            }
            resourceMapper.setOperationId(httpVerb, operationId);
            return resourceMapper;
        } else if (resourceParent.findResource(resource) != null) {
            ResourceMapper resourceChild = resourceParent.findResource(resource);
            ResourceMapper resourceMapperReturn = buildHierarchyObject(httpVerb, resourceChild,
                resouceSplitterList.subList(1, resouceSplitterList.size()), operationId);
            resourceChild.addResourceMapper(resourceMapperReturn);
            return resourceChild;
        } else {
            Set mapperSet = new LinkedHashSet<>();
            ResourceMapper resourceMapper = new ResourceMapper(resource, mapperSet);
            resourceMapper.setActualResource(actualResource);
            ResourceMapper resourceMapperReturn = buildHierarchyObject(httpVerb, resourceMapper,
                resouceSplitterList.subList(1, resouceSplitterList.size()), operationId);
            resourceMapper.addResourceMapper(resourceMapperReturn);

            return resourceMapper;
        }
    }

    default Map buildResponseType(Method method)
        throws JsonProcessingException, InstantiationException, IllegalAccessException,
        ClassNotFoundException {
        Map responseType = buildOpenAPIResponseType(method);
        if (responseType == null || responseType.isEmpty()) {
            responseType = new HashMap<>();
            String defaultResponse = "Default";
            // Check for generic return types
            if (method.getGenericReturnType() instanceof ParameterizedType) {
                ParameterizedType parameterizedType =
                    (ParameterizedType) method.getGenericReturnType();
                for (Type type : parameterizedType.getActualTypeArguments()) {
                    try {
                        responseType.put(defaultResponse,
                            new VirtualServiceApiResponse(defaultResponse, type.getTypeName(),
                                getObjectMapper().writerWithDefaultPrettyPrinter()
                                    .writeValueAsString(Class
                                        .forName(type.getTypeName()).getDeclaredConstructor().newInstance()),
                                null));
                    } catch (Exception e) {
                        responseType.put(defaultResponse,
                            new VirtualServiceApiResponse(defaultResponse, null, null, null));
                    }
                }
            }
        }
        return responseType;
    }

    default VirtualServiceRequest buildServiceDetails(boolean scriptEnabled, Entry virtualServiceEntry,
        Method method) throws JsonProcessingException, InstantiationException,
        IllegalAccessException, ClassNotFoundException {

        String rootResource = ApiResource.getResourceParent(virtualServiceEntry.getValue());
        VirtualServiceRequest virtualServiceRequest = new VirtualServiceRequest();
        virtualServiceRequest.setDesc(getResourceDesc(method));
        virtualServiceRequest.setResponseType(buildResponseType(method));
        virtualServiceRequest.setOperationId(method.getName());
        virtualServiceRequest.setTypes(getTypes(scriptEnabled));
        virtualServiceRequest.setHttpStatusMap(getHttpStatusMap());
        VirtualServiceKeyValue virtualServiceKeyValue = ApiMethod.getApiMethodParamAndURL(method);
        if(rootResource != null) {
            virtualServiceRequest.setUrl("/"+rootResource + virtualServiceKeyValue.getValue());
            virtualServiceRequest.setResource(rootResource);
        } else {
            virtualServiceRequest.setUrl(virtualServiceKeyValue.getValue());
            virtualServiceRequest
                .setResource(ApiResource.getResourceByURL(virtualServiceKeyValue.getValue()));
        }
        virtualServiceRequest.setMethod(virtualServiceKeyValue.getKey());
        buildInput(method, virtualServiceRequest);
        return virtualServiceRequest;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy