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

org.sysfoundry.kiln.base.ss.srv.ServerLifecycleManager Maven / Gradle / Ivy

There is a newer version: 0.1.3
Show newest version
/*
 * Copyright 2019 Sysfoundry (www.sysfoundry.org)
 *
 * 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 org.sysfoundry.kiln.base.ss.srv;

import com.google.common.eventbus.Subscribe;
import lombok.extern.slf4j.Slf4j;
import org.sysfoundry.kiln.base.LifecycleException;
import org.sysfoundry.kiln.base.srv.Server;
import org.sysfoundry.kiln.base.srv.ServerSet;
import org.sysfoundry.kiln.base.evt.Event;
import org.sysfoundry.kiln.base.evt.EventBus;
import org.sysfoundry.kiln.base.sys.Args;

import javax.inject.Inject;
import java.util.*;
import java.util.stream.Collectors;

import static org.sysfoundry.kiln.base.sys.Sys.*;

@Slf4j
class ServerLifecycleManager {

    private EventBus eventBus;
    private Set servers;
    private Map> serverGroupMap;
    private Object lockObject = new Object(); //object used for synchronizing access during initialization
    private Optional> unknownLevelListOptional;
    private Optional> orphanLevelListOptional;
    private Optional>> orderedServersListOption;
    private String[] args;

    @Inject
    ServerLifecycleManager(EventBus eventBus, @ServerSet Set servers, @Args String[] args){
        this.eventBus = eventBus;
        this.servers = servers;
        this.args = args;
        this.eventBus.register(this);
    }


    private boolean isInitialized(){
        boolean retVal = false;

        if(serverGroupMap != null){
            retVal = true;
        }

        return retVal;
    }

    @Subscribe
    public void onEvent(Event event){
        String eventName = event.getName();

        log.trace("Received Event {}",eventName);

        switch(eventName){
            case INITIALIZING_EVENT:
                initializeServerGroup(event);
                break;
            case STARTING_EVENT:
                startServers(event);
                break;
            case STOPPING_EVENT:
                stopServers(event);
        }
    }

    private void initializeServerGroup(Event event) {
        log.trace("Initializing the ServerLifecycleManager...");
        if(!isInitialized()){
            synchronized (lockObject){
                if(!isInitialized()){
                    List sortedServerList = sort(new ArrayList(servers));
                    Map> groupedServerMap = group(sortedServerList);
                    this.serverGroupMap = groupedServerMap;

                    this.unknownLevelListOptional = getUnknownLevelList(this.serverGroupMap);
                    this.orphanLevelListOptional = getOrphanLevelList(this.serverGroupMap);
                    this.orderedServersListOption = getOrderedServerMetaList(this.serverGroupMap);

                    log.trace("Server Group Map {}",serverGroupMap);
                }
            }
        }
    }

    private Optional>> getOrderedServerMetaList(Map> serverGroupMap) {
        Set levels = serverGroupMap.keySet();
        List levelList = new ArrayList<>(levels);
        Collections.sort(levelList);
        List finalListOfLevels = levelList.stream().filter(v -> {
            return ((v == Server.ORPHAN_LEVEL) || (v == Server.UNKNOWN_LEVEL)) ? false : true;
        }).collect(Collectors.toList());

        List> finalList = new ArrayList<>();
        for (Integer level : finalListOfLevels) {
            finalList.add(serverGroupMap.get(level));
        }

        return Optional.of(finalList);
    }

    private Optional> getOrphanLevelList(Map> serverGroupMap) {
        Optional> orphanServerListOptional = Optional.empty();
        if(serverGroupMap.containsKey(Server.ORPHAN_LEVEL)){
            orphanServerListOptional = Optional.ofNullable(serverGroupMap.get(Server.ORPHAN_LEVEL));
        }
        return orphanServerListOptional;
    }

    private Optional> getUnknownLevelList(Map> serverGroupMap) {
        Optional> unKnownServerListOptional = Optional.empty();
        if(serverGroupMap.containsKey(Server.UNKNOWN_LEVEL)){
            unKnownServerListOptional = Optional.ofNullable(serverGroupMap.get(Server.UNKNOWN_LEVEL));
        }
        return unKnownServerListOptional;
    }

    private void stopServers(Event event) {
        if(!isInitialized()){
            throw new RuntimeException("Server Lifecycle Manager has not been initialized!");
        }
        log.trace("Stopping All Servers in order...");

        this.orderedServersListOption.ifPresent(serverListOfList->{
            ArrayList> newServerListOfList = new ArrayList<>();
            newServerListOfList.addAll(serverListOfList);

            //reverse the list
            Collections.reverse(newServerListOfList);

            newServerListOfList.forEach(serverList->{
                serverList.forEach(server -> {
                    try {
                        server.stop();
                    } catch (LifecycleException e) {
                        e.printStackTrace();
                    }
                });
            });
        });
    }

    private void startServers(Event event) {
        if(!isInitialized()){
            throw new RuntimeException("Server Lifecycle Manager has not been initialized!");
        }

        log.trace("Starting all Servers in order...");

        this.orderedServersListOption.ifPresent(serverListOfList->{
            log.trace("Servers to be started {} count {}",serverListOfList,serverListOfList.size());
            serverListOfList.forEach(serverList->{
                serverList.forEach(server -> {
                    try {
                        server.start(args);
                    } catch (LifecycleException e) {
                        e.printStackTrace();
                    }
                });
            });
        });

        this.unknownLevelListOptional.ifPresent(serverList->{
            serverList.forEach(server -> {
                log.warn("Server - {} is in an unknown state and cannot be started!",server.getName());
            });
        });

        this.orphanLevelListOptional.ifPresent(serverList->{
            serverList.forEach(server -> {
                log.warn("Server - {} is in an orphaned state and cannot be started. " +
                        "Please verify the requirements of this server!",server.getName());
            });
        });

    }

    public static Map> group(List serverListToBeGrouped){
        Map> groupMap = new HashMap<>();
        for (Server server : serverListToBeGrouped) {
            int level = server.getStartLevel();
            List serverList = null;
            boolean newList = false;
            if(groupMap.containsKey(level)){
                serverList = groupMap.get(level);
            }else{
                serverList = new ArrayList<>();
                newList = true;
            }
            serverList.add(server);
            if(newList){
                groupMap.put(level,serverList);
            }
        }
        return groupMap;
    }

    private  List sort(List serverList){
        ArrayList sortedList = new ArrayList<>();

        ArrayList availableCapabilityList = new ArrayList<>();
        ArrayList unsortedList = new ArrayList<>(serverList);
        List currentSortedList = new ArrayList<>();

        currentSortedList = sort_internal(availableCapabilityList,unsortedList,currentSortedList,0);


        sortedList.addAll(currentSortedList);

        return sortedList;
    }

    private  List sort_internal(List availableCapabilityList,
                                                  List unsortedList,
                                                  List currentSortedList,int level) {
        List newServerList = new ArrayList<>();

        for (Server server : unsortedList) {

            if(server.areRequirementsSatisfied(availableCapabilityList)){
                server.setStartLevel(level+1);
                newServerList.add(server);
            }
        }

        List newUnsortedList = new ArrayList<>();

        unsortedList.forEach(server -> {
            if(!newServerList.contains(server)){
                newUnsortedList.add(server);
            }
        });

        List newAvailableCapabilityList = new ArrayList<>();
        newAvailableCapabilityList.addAll(availableCapabilityList);

        List newCurrentSortedList = new ArrayList<>();
        newCurrentSortedList.addAll(currentSortedList);

        for (Server server : newServerList) {
            //add the new capabilities to the newAvailabilityList
            if(server.getProvidedCapabilities().isPresent()){
                String[] newCapabilities = server.getProvidedCapabilities().get();

                for (String newCapability : newCapabilities) {
                    if(!newAvailableCapabilityList.contains(newCapability)){
                        //add it to the new list
                        newAvailableCapabilityList.add(newCapability);
                    }
                }

            }
            //add to the newCurrentSortedList
            newCurrentSortedList.add(server);
        }

        if(newServerList.size() > 0){
            //recursively loop only if new servers are identified in the list
            return sort_internal(newAvailableCapabilityList,newUnsortedList,newCurrentSortedList,level+1);
        }else{

            if(unsortedList.size()>0){
                List newAvailableCapabilityListForPending = new ArrayList<>();
                newAvailableCapabilityListForPending.addAll(newAvailableCapabilityList);
                List orphanList = new ArrayList<>();

                //add the pending items capability list
                for (Server server : unsortedList) {
                    if(server.getProvidedCapabilities().isPresent()) {
                        String[] capabilities = server.getProvidedCapabilities().get();
                        for (String capability : capabilities) {
                            if(!newAvailableCapabilityListForPending.contains(capability)){
                                newAvailableCapabilityListForPending.add(capability);
                            }
                        }

                    }
                }

                //now iterate and check if the pending items are satisfied
                for (Server server : unsortedList) {
                    if(server.areRequirementsSatisfied(newAvailableCapabilityListForPending)){
                        server.setStartLevel(level+1); //jump to the next level
                        newServerList.add(server);
                    }else{
                        //these are orphans
                        orphanList.add(server);
                    }
                }


                //finally add the rest of the orphans with the appropriate level
                for (Server server : orphanList) {
                    if(server.hasRequirement("*")){
                        server.setStartLevel(Integer.MAX_VALUE); //should be the last to be started
                    }else {
                        server.setStartLevel(Server.ORPHAN_LEVEL); //-2 represents orphans
                    }
                    newServerList.add(server);
                }

                //finally add them to the sorted list
                for (Server server : newServerList) {
                    newCurrentSortedList.add(server);
                }

            }

            return newCurrentSortedList;
        }


    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy