// Path: src/main/java/com/github/hermannpencole/nifi/config/model/ConfigException.java
// public class ConfigException extends RuntimeException {
//     public ConfigException(Throwable e) {
//         super(e);
//     }
// 
//     public ConfigException(String s, Throwable e) {
//         super(s,e);
//     }
// 
//     public ConfigException(String s) {
//         super(s);
//     }
// }
// 
// Path: src/main/java/com/github/hermannpencole/nifi/config/model/TimeoutException.java
// public class TimeoutException extends RuntimeException {
//     public TimeoutException(Throwable e) {
//         super(e);
//     }
// 
//     public TimeoutException(String s, Throwable e) {
//         super(s,e);
//     }
// 
//     public TimeoutException(String s) {
//         super(s);
//     }
// }
// 
// Path: src/main/java/com/github/hermannpencole/nifi/config/utils/FunctionUtils.java
// public final class FunctionUtils {
//     /**
//      * The logger.
//      */
//     private final static Logger LOG = LoggerFactory.getLogger(FunctionUtils.class);
// 
//     private FunctionUtils() { }
// 
//     public static void runTimeout(Runnable function, int timeout) {
//         java.util.concurrent.ExecutorService executor = Executors.newSingleThreadExecutor();
//         final Future future = executor.submit(function);
//         try {
//             if (timeout < 0 ) {
//                 future.get();
//             } else {
//                 future.get(timeout, TimeUnit.SECONDS);
//             }
//         } catch (ExecutionException e) {
//             LOG.debug(e.getMessage(),e);
//             future.cancel(true);
//             if (e.getCause() instanceof ConfigException) {
//                 throw (ConfigException)e.getCause();
//             }
//             throw new ConfigException(e.getCause());
//         } catch (InterruptedException e) {
//             future.cancel(true);
//             throw new ConfigException(e);
//         } catch (java.util.concurrent.TimeoutException e) {
//             future.cancel(true);
//             throw new TimeoutException(e);
//         } finally {
//             executor.shutdownNow();
//         }
// 
//     }
// 
//     public static void runWhile(Supplier<Boolean> function, int interval) {
//        while (function.get()) {
//            try {
//                //interval are in second
//                Thread.sleep(interval * 1000);
//            } catch (InterruptedException e) {
//                throw new ConfigException(e);
//            }
//        }
//     }
// 
//     public static void runWhile(Supplier<Boolean> function, int interval, int timeout) {
//         runTimeout(() -> runWhile(function, interval ), timeout);
//     }
// 
//     public static Optional<ProcessGroupEntity> findByComponentName(List<ProcessGroupEntity> listGroup, String name) {
//         return listGroup.stream()
//                 .filter(item -> item.getComponent() != null && item.getComponent().getName().trim().equals(name.trim()))
//                 .findFirst();
//     }
// }
// 
// Path: src/main/java/com/github/hermannpencole/nifi/config/utils/FunctionUtils.java
// public static Optional<ProcessGroupEntity> findByComponentName(List<ProcessGroupEntity> listGroup, String name) {
//     return listGroup.stream()
//             .filter(item -> item.getComponent() != null && item.getComponent().getName().trim().equals(name.trim()))
//             .findFirst();
// }


import com.github.hermannpencole.nifi.config.model.ConfigException;
import com.github.hermannpencole.nifi.config.model.TimeoutException;
import com.github.hermannpencole.nifi.config.utils.FunctionUtils;
import com.github.hermannpencole.nifi.swagger.ApiException;
import com.github.hermannpencole.nifi.swagger.client.FlowApi;
import com.github.hermannpencole.nifi.swagger.client.ProcessGroupsApi;
import com.github.hermannpencole.nifi.swagger.client.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
import static com.github.hermannpencole.nifi.config.utils.FunctionUtils.findByComponentName;

                    }
                }
            }
            for (ProcessGroupEntity procGroupInConf : processGroupFlow.getProcessGroupFlow().getFlow().getProcessGroups()) {
                ProcessGroupFlowEntity processGroupFlowEntity = flowapi.getFlow(procGroupInConf.getId());
                stop(processGroupFlowEntity);
            }
            setState(processGroupFlow.getProcessGroupFlow().getId(), ScheduleComponentsEntity.StateEnum.STOPPED);
        } catch (Exception e) {
            setState(processGroupFlow.getProcessGroupFlow().getId(), ScheduleComponentsEntity.StateEnum.RUNNING);
            throw e;
        }
    }

    /**
     * reorder for have the processor that consume stream -&gt; connection -&gt; processor connected etc ...in the good order.
     *
     * Just put the first at the first and the other after trick for bypass cycle
     *
     * @param processGroupFlow processGroupFlow
     * @return the list of component reordered
     */
    public List<Set<?>> reorder(ProcessGroupFlowDTO processGroupFlow) {
        List<Set<?>> level = new ArrayList<>();

        Set<ProcessGroupFlowDTO> allProcessGroupFlow = getAllProcessGroupFlow(processGroupFlow);
        Set<ConnectionEntity> allConnections = allProcessGroupFlow.stream().flatMap(p->p.getFlow().getConnections().stream()).collect(Collectors.toSet());
        Set<ProcessorEntity> allProcessors = allProcessGroupFlow.stream().flatMap(p->p.getFlow().getProcessors().stream()).collect(Collectors.toSet());

        //get the first

// Path: src/main/java/com/github/hermannpencole/nifi/config/model/ConfigException.java
// public class ConfigException extends RuntimeException {
//     public ConfigException(Throwable e) {
//         super(e);
//     }
// 
//     public ConfigException(String s, Throwable e) {
//         super(s,e);
//     }
// 
//     public ConfigException(String s) {
//         super(s);
//     }
// }
// 
// Path: src/main/java/com/github/hermannpencole/nifi/config/model/TimeoutException.java
// public class TimeoutException extends RuntimeException {
//     public TimeoutException(Throwable e) {
//         super(e);
//     }
// 
//     public TimeoutException(String s, Throwable e) {
//         super(s,e);
//     }
// 
//     public TimeoutException(String s) {
//         super(s);
//     }
// }
// 
// Path: src/main/java/com/github/hermannpencole/nifi/config/utils/FunctionUtils.java
// public final class FunctionUtils {
//     /**
//      * The logger.
//      */
//     private final static Logger LOG = LoggerFactory.getLogger(FunctionUtils.class);
// 
//     private FunctionUtils() { }
// 
//     public static void runTimeout(Runnable function, int timeout) {
//         java.util.concurrent.ExecutorService executor = Executors.newSingleThreadExecutor();
//         final Future future = executor.submit(function);
//         try {
//             if (timeout < 0 ) {
//                 future.get();
//             } else {
//                 future.get(timeout, TimeUnit.SECONDS);
//             }
//         } catch (ExecutionException e) {
//             LOG.debug(e.getMessage(),e);
//             future.cancel(true);
//             if (e.getCause() instanceof ConfigException) {
//                 throw (ConfigException)e.getCause();
//             }
//             throw new ConfigException(e.getCause());
//         } catch (InterruptedException e) {
//             future.cancel(true);
//             throw new ConfigException(e);
//         } catch (java.util.concurrent.TimeoutException e) {
//             future.cancel(true);
//             throw new TimeoutException(e);
//         } finally {
//             executor.shutdownNow();
//         }
// 
//     }
// 
//     public static void runWhile(Supplier<Boolean> function, int interval) {
//        while (function.get()) {
//            try {
//                //interval are in second
//                Thread.sleep(interval * 1000);
//            } catch (InterruptedException e) {
//                throw new ConfigException(e);
//            }
//        }
//     }
// 
//     public static void runWhile(Supplier<Boolean> function, int interval, int timeout) {
//         runTimeout(() -> runWhile(function, interval ), timeout);
//     }
// 
//     public static Optional<ProcessGroupEntity> findByComponentName(List<ProcessGroupEntity> listGroup, String name) {
//         return listGroup.stream()
//                 .filter(item -> item.getComponent() != null && item.getComponent().getName().trim().equals(name.trim()))
//                 .findFirst();
//     }
// }
// 
// Path: src/main/java/com/github/hermannpencole/nifi/config/utils/FunctionUtils.java
// public static Optional<ProcessGroupEntity> findByComponentName(List<ProcessGroupEntity> listGroup, String name) {
//     return listGroup.stream()
//             .filter(item -> item.getComponent() != null && item.getComponent().getName().trim().equals(name.trim()))
//             .findFirst();
// }


// Path: src/main/java/com/github/hermannpencole/nifi/config/service/ProcessGroupService.java
import com.github.hermannpencole.nifi.config.model.ConfigException;
import com.github.hermannpencole.nifi.config.model.TimeoutException;
import com.github.hermannpencole.nifi.config.utils.FunctionUtils;
import com.github.hermannpencole.nifi.swagger.ApiException;
import com.github.hermannpencole.nifi.swagger.client.FlowApi;
import com.github.hermannpencole.nifi.swagger.client.ProcessGroupsApi;
import com.github.hermannpencole.nifi.swagger.client.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
import static com.github.hermannpencole.nifi.config.utils.FunctionUtils.findByComponentName;

                    }
                }
            }
            for (ProcessGroupEntity procGroupInConf : processGroupFlow.getProcessGroupFlow().getFlow().getProcessGroups()) {
                ProcessGroupFlowEntity processGroupFlowEntity = flowapi.getFlow(procGroupInConf.getId());
                stop(processGroupFlowEntity);
            }
            setState(processGroupFlow.getProcessGroupFlow().getId(), ScheduleComponentsEntity.StateEnum.STOPPED);
        } catch (Exception e) {
            setState(processGroupFlow.getProcessGroupFlow().getId(), ScheduleComponentsEntity.StateEnum.RUNNING);
            throw e;
        }
    }

    /**
     * reorder for have the processor that consume stream -&gt; connection -&gt; processor connected etc ...in the good order.
     *
     * Just put the first at the first and the other after trick for bypass cycle
     *
     * @param processGroupFlow processGroupFlow
     * @return the list of component reordered
     */
    public List<Set<?>> reorder(ProcessGroupFlowDTO processGroupFlow) {
        List<Set<?>> level = new ArrayList<>();

        Set<ProcessGroupFlowDTO> allProcessGroupFlow = getAllProcessGroupFlow(processGroupFlow);
        Set<ConnectionEntity> allConnections = allProcessGroupFlow.stream().flatMap(p->p.getFlow().getConnections().stream()).collect(Collectors.toSet());
        Set<ProcessorEntity> allProcessors = allProcessGroupFlow.stream().flatMap(p->p.getFlow().getProcessors().stream()).collect(Collectors.toSet());

        //get the first

        Set<String> destination = new HashSet<>();
