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

com.cloudimpl.outstack.spring.service.RestControllerService Maven / Gradle / Ivy

There is a newer version: 4.0.551
Show newest version
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cloudimpl.outstack.spring.service;

import com.cloudimpl.outstack.common.CloudMessage;
import com.cloudimpl.outstack.common.FluxMap;
import com.cloudimpl.outstack.common.GsonCodec;
import com.cloudimpl.outstack.common.RouterType;
import com.cloudimpl.outstack.core.CloudService;
import com.cloudimpl.outstack.core.CloudServiceDescriptor;
import com.cloudimpl.outstack.core.Inject;
import com.cloudimpl.outstack.core.Named;
import com.cloudimpl.outstack.core.ServiceRegistryReadOnly;
import com.cloudimpl.outstack.core.annon.CloudFunction;
import com.cloudimpl.outstack.core.annon.Router;
import com.cloudimpl.outstack.core.logger.ILogger;
import com.cloudimpl.outstack.runtime.EntityIdHelper;
import com.cloudimpl.outstack.runtime.EventRepositoryFactory;
import com.cloudimpl.outstack.runtime.EventRepositoy;
import com.cloudimpl.outstack.runtime.ResourceHelper;
import com.cloudimpl.outstack.runtime.domainspec.Entity;
import com.cloudimpl.outstack.runtime.domainspec.EntityHelper;
import com.cloudimpl.outstack.runtime.domainspec.Event;
import com.cloudimpl.outstack.spring.component.SpringServiceDescriptor;
import com.cloudimpl.outstack.runtime.domain.CommandHandlerRegistered;
import com.cloudimpl.outstack.runtime.domain.DomainContext;
import com.cloudimpl.outstack.runtime.domain.DomainContextCreated;
import com.cloudimpl.outstack.runtime.domain.EventHandlerRegistered;
import com.cloudimpl.outstack.runtime.domain.ServiceModule;
import com.cloudimpl.outstack.runtime.domain.ServiceModuleProvisioned;
import com.cloudimpl.outstack.runtime.domain.QueryHandlerRegistered;
import com.cloudimpl.outstack.runtime.domain.ServiceModuleRef;
import com.cloudimpl.outstack.runtime.domain.ServiceModuleRefCreated;
import com.cloudimpl.outstack.spring.util.SpringUtil;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import reactor.core.publisher.Flux;

/**
 *
 * @author nuwan
 */
@CloudFunction(name = "RestController")
@Router(routerType = RouterType.LOCAL)
public class RestControllerService implements Function {

    private Flux> serviceFlux;
    private ServiceDescriptorContextManager serviceManager;
    private ILogger logger;
    private EventRepositoryFactory eventRepoFactory;
    private Map domainContexts = new ConcurrentHashMap<>();
    public static FluxMap domainContextsFlux = new FluxMap<>("DomainContext");

    public static RestControllerService instance;
    private ServiceRegistryReadOnly serviceRegistry;

    @Inject
    public RestControllerService(ServiceRegistryReadOnly serviceRegistry, @Named("@serviceFlux") Flux> serviceFlux,
            ServiceDescriptorContextManager serviceManager, @Named("MemRepositoryFactory") EventRepositoryFactory eventRepoFactory, ILogger logger) {
        this.serviceRegistry = serviceRegistry;
        RestControllerService.instance = this;
        this.logger = logger.createSubLogger(RestControllerService.class);
        this.eventRepoFactory = eventRepoFactory;
        this.serviceFlux = serviceFlux;
        this.serviceManager = serviceManager;
        this.serviceFlux.filter(s -> s.getType() == FluxMap.Event.Type.ADD)
                .map(s -> getSpringDescriptor(s.getValue().getDescriptor()))
                .filter(d -> d.isPresent())
                .map(d -> d.get())
                .doOnNext(this::addCmdDescriptor)
                .doOnError(err -> logger.exception(err, "rest controller service error:"))
                .subscribe();

        this.serviceFlux.filter(s -> s.getType() == FluxMap.Event.Type.ADD)
                .map(s -> getSpringQueryDescriptor(s.getValue().getDescriptor()))
                .filter(d -> d.isPresent())
                .map(d -> d.get())
                .doOnNext(this::addQueryDescriptor)
                .doOnError(err -> logger.exception(err, "rest controller service error:"))
                .subscribe();
    }

    private Optional getSpringDescriptor(CloudServiceDescriptor serviceDescriptor) {
        String str = serviceDescriptor.getAttr().get("serviceMeta");
        if (str != null) {
            logger.info("service descriptor {0}", str);
            SpringServiceDescriptor serviceDesc = GsonCodec.decode(SpringServiceDescriptor.class, str);
            return Optional.of(serviceDesc);
        }
        return Optional.empty();
    }

    public static void refresh(String rootTypePlural) {
        instance._refresh(rootTypePlural);
    }

    public void _refresh(String rootTypePlural) {
        logger.warn("refreshing  rootType : {0}", rootTypePlural);
        serviceRegistry.services().filter(srv -> srv.getDescriptor().getAttr().get("serviceMeta") != null)
                .map(srv -> srv.getDescriptor().getAttr().get("serviceMeta"))
                .map(s -> GsonCodec.decode(SpringServiceDescriptor.class, s))
                .filter(s -> s.getPlural().equals(rootTypePlural))
                .forEach(this::addCmdDescriptor);

        serviceRegistry.services().filter(srv -> srv.getDescriptor().getAttr().get("serviceQueryMeta") != null)
                .map(srv -> srv.getDescriptor().getAttr().get("serviceQueryMeta"))
                .map(s -> GsonCodec.decode(SpringServiceDescriptor.class, s))
                .filter(s -> s.getPlural().equals(rootTypePlural))
                .forEach(this::addQueryDescriptor);
    }

    private Optional getSpringQueryDescriptor(CloudServiceDescriptor serviceDescriptor) {
        String str = serviceDescriptor.getAttr().get("serviceQueryMeta");
        if (str != null) {
            logger.info("service query descriptor {0}", str);
            SpringServiceDescriptor serviceDesc = GsonCodec.decode(SpringServiceDescriptor.class, str);
            return Optional.of(serviceDesc);
        }
        return Optional.empty();
    }

    private void addCmdDescriptor(SpringServiceDescriptor desc) {
        try {
            this.serviceManager.putCmdContext(desc.getApiContext(), desc.getVersion(), desc);
            addEntities(desc);
        } catch (Exception ex) {
            logger.error("addCmdDescriptor {0}", ex.getMessage());
        }
    }

    private void addQueryDescriptor(SpringServiceDescriptor desc) {
        try {
            this.serviceManager.putQueryContext(desc.getApiContext(), desc.getVersion(), desc);
            addEntities(desc);
        } catch (Exception ex) {
            logger.error("addQueryDescriptor {0}", ex.getMessage());
        }
    }

    @Override
    public CloudMessage apply(CloudMessage req) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    private void addEntities(SpringServiceDescriptor desc) {

        ServiceModule service = eventRepoFactory.createOrGetRepository(ServiceModule.class).getRootById(ServiceModule.class, desc.getDomainOwner() + ":" + desc.getDomainContext() + ":" + desc.getRootType(), null)
                .orElseGet(() -> createMicroService(desc));
        addActions(eventRepoFactory.createOrGetRepository(ServiceModule.class), service.id(), desc.getRootType(), desc, desc.getRootActions());
        desc.entityDescriptors().forEach(ed -> {
            addActions(eventRepoFactory.createOrGetRepository(ServiceModule.class), service.id(), ed.getName(), desc, desc.getChildActions(ed.getName()));
        });
    }

    private ServiceModule createMicroService(SpringServiceDescriptor desc) {
        DomainContext domainContext = createOrGetDomainContext(desc);

        String id = EventRepositoy.TID_PREFIX + "i" + SpringUtil.toMD5(desc.getDomainOwner() + "/" + desc.getDomainContext() + ":" + desc.getRootType());
        ServiceModuleProvisioned provisioned = new ServiceModuleProvisioned(desc.getServiceName(), desc.getDomainOwner() + ":" + desc.getDomainContext() + ":" + desc.getRootType(),
                desc.getVersion(), desc.getApiContext(), desc.getTenancy());
        provisioned.setId(id);
        provisioned.setRootId(id);
        provisioned.setAction(Event.Action.CREATE);
        EntityHelper.setVersion(provisioned, Entity.getVersion(ServiceModule.class));
        EntityHelper.setCreatedDate(provisioned, System.currentTimeMillis());

        String childId = EventRepositoy.TID_PREFIX + "i" + SpringUtil.toMD5(desc.getDomainOwner() + "/" + desc.getDomainContext() + ":" + id);
        ServiceModuleRefCreated refEvent = new ServiceModuleRefCreated(EntityIdHelper.idToRefId(id), domainContext.entityId());
        refEvent.setId(childId);
        refEvent.setRootId(domainContext.id());
        refEvent.setAction(Event.Action.CREATE);
        EntityHelper.setVersion(refEvent, Entity.getVersion(ServiceModuleRef.class));
        EntityHelper.setCreatedDate(refEvent, System.currentTimeMillis());
        eventRepoFactory.createOrGetRepository(DomainContext.class).applyEvent(refEvent);
        return eventRepoFactory.createOrGetRepository(ServiceModule.class).applyEvent(provisioned);
    }

    private void addActions(EventRepositoy eventRepo, String rootId, String targetEntity, SpringServiceDescriptor serviceDesc, Collection actions) {
        actions.stream().filter(action -> action.getActionType() == SpringServiceDescriptor.ActionDescriptor.ActionType.COMMAND_HANDLER).forEach(action -> {
            CommandHandlerRegistered event = new CommandHandlerRegistered(action.getName(), targetEntity, serviceDesc.getRootType());
            String childId = EventRepositoy.TID_PREFIX + "i" + SpringUtil.toMD5(serviceDesc.getDomainOwner() + "/" + serviceDesc.getDomainContext() + ":" + serviceDesc.getRootType() + ":cmd:" + action.getName());
            event.setId(childId);
            event.setRootId(rootId);
            event.setAction(Event.Action.CREATE);
            EntityHelper.setVersion(event, Entity.getVersion(ServiceModule.class));
            EntityHelper.setCreatedDate(event, System.currentTimeMillis());
            eventRepo.applyEvent(event);
        });

        actions.stream().filter(action -> action.getActionType() == SpringServiceDescriptor.ActionDescriptor.ActionType.EVENT_HANDLER).forEach(action -> {
            EventHandlerRegistered event = new EventHandlerRegistered(action.getName(), targetEntity, serviceDesc.getRootType());
            String childId = EventRepositoy.TID_PREFIX + "i" + SpringUtil.toMD5(serviceDesc.getDomainOwner() + "/" + serviceDesc.getDomainContext() + ":" + serviceDesc.getRootType() + ":evt:" + action.getName());
            event.setId(childId);
            event.setRootId(rootId);
            event.setAction(Event.Action.CREATE);
            EntityHelper.setVersion(event, Entity.getVersion(ServiceModule.class));
            EntityHelper.setCreatedDate(event, System.currentTimeMillis());
            eventRepo.applyEvent(event);
        });

        actions.stream().filter(action -> action.getActionType() == SpringServiceDescriptor.ActionDescriptor.ActionType.QUERY_HANDLER).forEach(action -> {
            QueryHandlerRegistered event = new QueryHandlerRegistered(action.getName(), targetEntity, serviceDesc.getRootType());
            String childId = EventRepositoy.TID_PREFIX + "i" + SpringUtil.toMD5(serviceDesc.getDomainOwner() + "/" + serviceDesc.getDomainContext() + ":" + serviceDesc.getRootType() + ":query:" + action.getName());
            event.setId(childId);
            event.setRootId(rootId);
            event.setAction(Event.Action.CREATE);
            EntityHelper.setCreatedDate(event, System.currentTimeMillis());
            EntityHelper.setVersion(event, Entity.getVersion(ServiceModule.class));
            eventRepo.applyEvent(event);
        });
    }

    private DomainContext createOrGetDomainContext(SpringServiceDescriptor serviceDesc) {
        return domainContexts.computeIfAbsent(serviceDesc.getDomainOwner() + "/" + serviceDesc.getDomainContext(), id -> {
            String tid = EventRepositoy.TID_PREFIX + "i" + SpringUtil.toMD5(serviceDesc.getDomainOwner() + "/" + serviceDesc.getDomainContext() + ":" + id);
            DomainContextCreated event = new DomainContextCreated(id, serviceDesc.getDomainOwner(), serviceDesc.getDomainContext());
            event.setId(tid);
            event.setRootId(tid);
            event.setAction(Event.Action.CREATE);
            EntityHelper.setVersion(event, Entity.getVersion(DomainContext.class));
            EntityHelper.setCreatedDate(event, System.currentTimeMillis());
            DomainContext ctx = eventRepoFactory.createOrGetRepository(DomainContext.class).applyEvent(event);
            domainContextsFlux.put(id, ctx);
            return ctx;
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy