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

net.aequologica.neo.dagr.Dags Maven / Gradle / Ivy

The newest version!
package net.aequologica.neo.dagr;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.type.TypeReference;
import net.aequologica.neo.dagr.DagOnSteroids.DagCleaner;
import net.aequologica.neo.dagr.bus.Bus;
import net.aequologica.neo.dagr.model.Dag;
import net.aequologica.neo.dagr.model.Dag.Node;
import net.aequologica.neo.geppaequo.document.DocumentHelper;
import net.aequologica.neo.geppaequo.document.impl.DocumentHelperFactory;
import net.aequologica.neo.serioulizer.Serioulizer;
import net.aequologica.neo.serioulizer.jackson.SeriousReaderWriter;

@Singleton
public class Dags extends Observable {
    
    @Inject
    private Serioulizer serioulizer;

    private SeriousReaderWriter     serializer;
    private final Logger                 log             = LoggerFactory.getLogger(Dags.class);
    private final FileSystem             fileSystem      = FileSystems.getDefault();
    private final String                 DAGS_DIRECTORY  = "/dags";
    
    private final DocumentHelper                documentHelper  = DocumentHelperFactory.DOCUMENTHELPERFACTORY.getDocumentHelper();
    private final Lock                          lockOnIO;
    private final Map    map;
    
    Dags() {
        this.lockOnIO   = new ReentrantLock();
        this.map        = new HashMap<>();
    }

    @PostConstruct
    void postConstruct() {
        serializer= new SeriousReaderWriter<>(new TypeReference() {}, serioulizer);
        
        loadDags();
        DagBerk.PROFOND_DESESPOIR.cdiEstDeLaMerdeEnPot(this);
    }

    /////////////////////////////
    // collections getters
    public Set getDagNames() {
        return this.map.keySet();
    }
    public Collection getDagOnSteroidss() {
        return this.map.values();
    }
    public List getDAGs() {
        return this.map.values().stream().map(b -> b.getDag()).collect(Collectors.toList());
    }
    
    /////////////////////////////
    // elements getters
    public DagOnSteroids getDagOnSteroids(final String dagkey) {
        return this.map.get(dagkey);
    } 
    public Dag getDAG(final String dagkey) {
        DagOnSteroids dagOnSteroids = this.map.get(dagkey); 
        return dagOnSteroids == null ? null : dagOnSteroids.getDag();
    }
    public Bus getBus(final String dagkey, final Scope scope) {
        final DagOnSteroids dagOnSteroids = this.map.get(dagkey); 
        if (dagOnSteroids == null) {
            return null;
        }
        final DagCleaner dagCleaner = dagOnSteroids.getDagCleaner(scope);
        if (dagCleaner == null) {
            return null;
        }
        return dagCleaner.getBus();
    }
    
    /////////////////////////////
    // loaders
    public Collection>>> loadDags() {
        
        this.lockOnIO.lock(); // block until condition holds
        try {
            final Collection>>> allExceptions = new ArrayList<>();

            // notify before clear
            setChanged();
            notifyObservers(Boolean.TRUE);
            this.map.clear();

            List sources;
            try {
                sources = privateGetDagSources();
            } catch (Exception e) {
                Collection> bigError = new ArrayList<>();
                bigError.add(tuple(e.getClass().getSimpleName(), e.getMessage()));
                allExceptions.add(tuple("", bigError));
                return allExceptions;
            }

            for (Path source : sources) {
                PathMatcher matcher = fileSystem.getPathMatcher("regex:^.*\\.(properties|yml|hbs|gitmodules|xml|pom)$");
                if (matcher.matches(source.getFileName())) {
                    continue;
                }
                allExceptions.add(privateLoadDag(null, source));
            }

            // notify after puts
            setChanged();
            notifyObservers(allExceptions);
            return allExceptions;
        } finally {
            this.lockOnIO.unlock();
        }
    }

    public Map.Entry>> loadDag(String dagName) {
        this.lockOnIO.lock(); // block until condition holds
        try {
            // notify before clear
            setChanged();
            notifyObservers(dagName);
            
            final Dag  dag = getDAG(dagName);
            final Path source;
            if (dag != null) {
                source = Paths.get(dag.getSource());
            } else {
                try {
                    source = privateLocateSourceWithDagName(dagName);
                } catch (IOException e) {
                    Collection> exceptions = new ArrayList<>();
                    exceptions.add(tuple(e.getClass().getSimpleName(), e.getMessage()));
                    return tuple(dagName, exceptions);
                }
            }
            
            final Map.Entry>> thisDagExceptions = privateLoadDag(dagName, source);
                    
            // notify after puts
            setChanged();
            notifyObservers(thisDagExceptions);
            return thisDagExceptions;
        } finally {
            this.lockOnIO.unlock();
        }
    }

    private class PropertiesAndExceptions {
        Map properties;
        final Collection> exceptions = new ArrayList<>();
        
        void load(Path propertiesPath) {
            
           // properties is optional, not an issue if it does not exists, simply return null
            try (final InputStream inputStream = documentHelper.getInputStream(propertiesPath);) {
                if (inputStream == null) {
                    throw new IOException("no ["+ propertiesPath + "] in document service");
                }
    
                try {
                    final Properties properties = new Properties();
                    properties.load(new InputStreamReader(inputStream, "UTF-8"));
                    this.properties = properties.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString()));
                } catch (Exception accumulated) {
                    // if properties exists, and there is an error loading / java8streamingCollecting it, please report the error
                    exceptions.add(tuple(propertiesPath.getFileName().toString(), accumulated.getClass().getSimpleName() + " - " + accumulated.getMessage()));
                    this.properties = null;
                }
                
            } catch (Exception ignored) {
                log.info("ignored exception {} {}", ignored.getClass().getSimpleName(), ignored.getMessage());
                this.properties = null;
            }
        }
    }


    private Map.Entry>> privateLoadDag(String dagName, final Path source) {
        if (source == null) {
            throw new IllegalArgumentException("source must be not null");
        } 
        
        final Collection> exceptions = new ArrayList<>();

        try {
            final Dag dag = serializer.read(source);
            
            dag.setSource(source.toString());
            
            if (dagName == null) {
                dagName = dag.getName();
            }
            
            this.map.remove(dagName);
            
            final Path sourceWithoutJSONExtensionIFAny;
            int indexJsonExtension = source.toString().lastIndexOf(".json");
            if (0 < indexJsonExtension) {
                sourceWithoutJSONExtensionIFAny = Paths.get(source.toString().substring(0, indexJsonExtension));
            } else {
                sourceWithoutJSONExtensionIFAny = source;
            }
            
            // aliases
            PropertiesAndExceptions aliasesPAE = new PropertiesAndExceptions();
            aliasesPAE.load(Paths.get(sourceWithoutJSONExtensionIFAny+".aliases.properties"));
            if (aliasesPAE.exceptions != null && aliasesPAE.exceptions.size() > 0) {
                exceptions.addAll(aliasesPAE.exceptions);
            }
            
            // cleaner
            PropertiesAndExceptions cleanerPAE = new PropertiesAndExceptions();
            cleanerPAE.load(Paths.get(sourceWithoutJSONExtensionIFAny+".cleaner.properties"));
            if (cleanerPAE.exceptions != null && cleanerPAE.exceptions.size() > 0) {
                exceptions.addAll(cleanerPAE.exceptions);
            }
            
            loadSubs(dag);
            
            map.put(dag.getName(), new DagOnSteroids(dag, aliasesPAE.properties, cleanerPAE.properties));

        } catch (Exception e) {
            exceptions.add(tuple(e.getClass().getSimpleName(), e.getMessage()));
        }
        
        return tuple(dagName!=null ? dagName : source.getFileName().toString(), exceptions);
    }
    
    public Path saveSub(Dag dag, String subDagId, String description) throws IOException {
        
        final Path         path  = Paths.get(DAGS_DIRECTORY, dag.getName(), "subs", description+"__"+subDagId);
        final List nodes = dag.getNodes(subDagId).stream().map(n -> n.getName()).collect(Collectors.toList());
        
        Collections.sort(nodes);
        
        StringWriter sw = new StringWriter();
        for (String node : nodes) {
            sw.write(node);
            sw.write('\n');
        }
        
        documentHelper.write(path, Serioulizer.createStream(sw.toString()));
        
        return path;
    }
    
    private void loadSubs(Dag dag) throws IOException {
        
        List subs = Collections.emptyList();;
        try {
            subs = documentHelper.list(Paths.get(DAGS_DIRECTORY, dag.getName(), "subs"));
        } catch (Exception ignored) {
            return;
        }
        
        for (final Path sub : subs) {
            String nodeNamesAsString = Serioulizer.read(documentHelper.getInputStream(sub));
            Set nodeNames = new HashSet(Arrays.asList(nodeNamesAsString.split("\n")));
            dag.registerSubDag(nodeNames);
        }
    }

    void packageDumpDag(Path path, Dag dag) throws IOException {
        serializer.write(path, dag);
    }

    private  Map.Entry tuple(final String a, final T b) {
        return new AbstractMap.SimpleImmutableEntry<>(a, b);
    }
    
    private Path privateLocateSourceWithDagName(final String dagName) throws IOException {
        final List sources = privateGetDagSources();
        for (final Path source : sources) {
            final Dag dag = serializer.read(source);
            if (dag.getName().equals(dagName)) {
                return source;
            }
        }
        List collect = sources
            .stream()
            .map(s -> s.getFileName().toString())
            .collect(Collectors.toList()); 
        throw new IOException("no dag with name /" + dagName + "/ found in " + collect);
    }
    
    private List privateGetDagSources() throws IOException {
        final List  potentials = documentHelper.list(Paths.get(DAGS_DIRECTORY));
        final List  sources    = new ArrayList<>();
        final PathMatcher extExclude = fileSystem.getPathMatcher("regex:^.*\\.(properties|yml|hbs|gitmodules|xml|pom|txt)$");
        final PathMatcher dirExclude = fileSystem.getPathMatcher("regex:^.*[\\/\\\\]+(subs)[\\/\\\\]+.*$");
        for (final Path source : potentials) {
            if (extExclude.matches(source.getFileName())) {
                continue;
            }
            if (dirExclude.matches(source)) {
                continue;
            }
            sources.add(source);
        }
        return sources;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy