br.unb.cic.bionimbuz.services.sched.SchedService.java Source code

Java tutorial

Introduction

Here is the source code for br.unb.cic.bionimbuz.services.sched.SchedService.java

Source

/*
 * BioNimbuZ is a federated cloud platform.
 * Copyright (C) 2012-2015 Laboratory of Bioinformatics and Data (LaBiD),
 * Department of Computer Science, University of Brasilia, Brazil
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package br.unb.cic.bionimbuz.services.sched;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;

import br.unb.cic.bionimbuz.avro.rpc.AvroClient;
import br.unb.cic.bionimbuz.avro.rpc.RpcClient;
import br.unb.cic.bionimbuz.config.BioNimbusConfig;
import br.unb.cic.bionimbuz.model.FileInfo;
import br.unb.cic.bionimbuz.model.Job;
import br.unb.cic.bionimbuz.model.Log;
import br.unb.cic.bionimbuz.model.LogSeverity;
import br.unb.cic.bionimbuz.model.Workflow;
import br.unb.cic.bionimbuz.persistence.dao.WorkflowLoggerDao;
import br.unb.cic.bionimbuz.plugin.PluginFile;
import br.unb.cic.bionimbuz.plugin.PluginInfo;
import br.unb.cic.bionimbuz.plugin.PluginTask;
import br.unb.cic.bionimbuz.plugin.PluginTaskState;
import br.unb.cic.bionimbuz.plugin.linux.LinuxPlugin;
import br.unb.cic.bionimbuz.services.AbstractBioService;
import br.unb.cic.bionimbuz.services.RepositoryService;
import br.unb.cic.bionimbuz.services.UpdatePeerData;
import br.unb.cic.bionimbuz.services.messaging.CloudMessageService;
import br.unb.cic.bionimbuz.services.messaging.CuratorMessageService.Path;
import br.unb.cic.bionimbuz.services.sched.policy.SchedPolicy;
import br.unb.cic.bionimbuz.services.storage.bucket.BioBucket;
import br.unb.cic.bionimbuz.services.storage.bucket.CloudStorageMethods;
import br.unb.cic.bionimbuz.services.storage.bucket.CloudStorageService;
import br.unb.cic.bionimbuz.services.storage.bucket.methods.CloudMethodsAmazonGoogle;
import br.unb.cic.bionimbuz.toSort.Listeners;
import br.unb.cic.bionimbuz.utils.Get;
import br.unb.cic.bionimbuz.utils.Pair;

@Singleton
public class SchedService extends AbstractBioService implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(SchedService.class);
    private final ConcurrentHashMap<String, PluginInfo> cloudMap = new ConcurrentHashMap<>();
    private final ScheduledExecutorService schedExecService = Executors.newScheduledThreadPool(1,
            new BasicThreadFactory.Builder().namingPattern("SchedService-%d").build());
    private final Queue<PluginTask> relocateTasks = new ConcurrentLinkedQueue<>();
    private final List<Job> pendingJobs = new ArrayList<>();
    private final List<Job> dependentJobs = new ArrayList<>();
    private final Map<String, Pair<PluginInfo, PluginTask>> waitingTask = new ConcurrentHashMap<>();
    private Map<String, PluginFile> mapFilesPlugin;
    private final Map<String, Job> jobsWithNoService = new ConcurrentHashMap<>();
    // private final Queue<PluginTask> runningJobs = new ConcurrentLinkedQueue<PluginTask>();
    private final Map<String, PluginInfo> cancelingJobs = new ConcurrentHashMap<>();
    private RpcClient rpcClient;

    // change this to select scheduling policy
    private final SchedPolicy.Policy policy = SchedPolicy.Policy.C99SUPERCOLIDER;
    private String idPlugin;

    private LinuxPlugin myLinuxPlugin;
    private SchedPolicy schedPolicy;

    // Workflow information logger
    private final WorkflowLoggerDao workflowLogger;

    // Workflow
    private Workflow workflow;

    private boolean isClient = true;

    @Inject
    public SchedService(final CloudMessageService cms, final RepositoryService rs) {
        Preconditions.checkNotNull(cms);
        Preconditions.checkNotNull(rs);
        this.cms = cms;
        this.rs = rs;

        // Initializes workflow logger
        this.workflowLogger = new WorkflowLoggerDao();
    }

    public synchronized SchedPolicy getPolicy() {
        if (this.schedPolicy == null) {
            this.schedPolicy = SchedPolicy.getInstance(this.policy, this.cloudMap);
        }

        this.schedPolicy.setCloudMap(this.cloudMap);
        return this.schedPolicy;
    }

    /**
     * Altera a poltica de escalonamento para executar os jobs.
     */
    private void setPolicy() {
        // try {
        // String dataPolicy = cms.getData(JOBS.toString(), null);
        // if (dataPolicy != null && !dataPolicy.isEmpty()) {
        // schedPolicy = SchedPolicy.getInstance(new Integer(dataPolicy), cloudMap);
        // }
        // } catch (KeeperException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // } catch (InterruptedException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // }

        throw new UnsupportedOperationException("METHOD COMMENTED");
    }

    @Override
    public void run() {
        this.checkTasks();

        // try {
        // ObjectMapper mapper = new ObjectMapper();
        // PluginFile pfile = mapper.readValue(cms.getData("/bionimbuz/buckets/bionimbuz-g-us/files/mclovin.png", null), PluginFile.class);
        //
        // FileInfo ifile = new FileInfo();
        // ifile.setId(pfile.getId());
        // ifile.setName(pfile.getName());
        // List<FileInfo> request = new ArrayList<>();
        // request.add(ifile);
        //
        // checkFilesPlugin();
        // requestFile(request);
        //
        // } catch (Throwable t) {
        // LOGGER.error("[SchedService] Exception(run): " + t.getMessage());
        // t.printStackTrace();
        // }
        // LOGGER.debug("[SchedService] File requested");
    }

    @Override
    public void start(List<Listeners> listeners) {
        LOGGER.info("[SchedService] Starting ...");
        this.isClient = BioNimbusConfig.get().isClient();
        this.listeners = listeners;
        // if (listeners != null) {
        listeners.add(this);
        // }
        this.idPlugin = BioNimbusConfig.get().getId();

        this.getPolicy().setRs(this.rs);

        // inicia o valor do zk na politica de escalonamento
        this.getPolicy().setCms(this.cms);

        if (!this.cms.getZNodeExist(Path.PIPELINES.getFullPath(), null)) {
            this.cms.createZNode(CreateMode.PERSISTENT, Path.PIPELINES.getFullPath(), this.policy.toString());
        }
        this.cms.createZNode(CreateMode.PERSISTENT, Path.SCHED.getFullPath(this.idPlugin), null);
        this.cms.createZNode(CreateMode.PERSISTENT, Path.TASKS.getFullPath(this.idPlugin), null);
        this.cms.createZNode(CreateMode.PERSISTENT, Path.SIZE_JOBS.getFullPath(this.idPlugin), null);

        this.cloudMap.putAll(this.getPeers());
        try {
            // adicona watchers para receber um alerta quando um novo job for criado para ser escalonado, e uma nova requisio de latncia existir
            this.cms.getChildren(Path.PIPELINES.getFullPath(), new UpdatePeerData(this.cms, this, null));
            this.cms.getData(Path.PIPELINES.getFullPath(), new UpdatePeerData(this.cms, this, null));
            this.cms.getChildren(Path.PEERS.getFullPath(), new UpdatePeerData(this.cms, this, null));

            this.checkMyPlugin();
            this.checkWaitingTasks();
            this.checkPeers();

        } catch (final KeeperException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final InterruptedException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final IOException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }

        this.schedExecService.scheduleAtFixedRate(this, 1, 1, TimeUnit.MINUTES);
    }

    /**
     * Executa a rotina de escalonamento, aps o zookeeper disparar um aviso que
     * um novo job foi criado para ser escalonado.
     */
    private synchronized void scheduleJobs() throws InterruptedException, KeeperException {
        HashMap<Job, PluginInfo> schedMap;

        // Caso nao exista nenhum pipeline pendente da a chance para o escalonador
        // realocar as tarefas.
        if (!this.pendingJobs.isEmpty()) {
            // Log if workflow not null
            if (this.workflow != null) {
                this.workflowLogger.log(new Log("Job recebido pelo Servio de Escalonamento",
                        this.workflow.getUserId(), this.workflow.getId(), LogSeverity.INFO));
            }

            this.cloudMap.clear();
            this.cloudMap.putAll(this.getPeers());
            // realiza a requisicao dos valores da lantncia antes de escalonar um job

            // sched all pending jobs
            schedMap = this.getPolicy().schedule(this.pendingJobs);

            for (final Map.Entry<Job, PluginInfo> entry : schedMap.entrySet()) {
                final Job jobInfo = entry.getKey();

                final PluginInfo pluginInfo = entry.getValue();
                final PluginTask task = new PluginTask();
                task.setJobInfo(jobInfo);
                if (pluginInfo != null) {

                    task.setState(PluginTaskState.PENDING);
                    task.setPluginExec(pluginInfo.getId());

                    // adiciona o job na lista de execuo do servidor zookeeper
                    this.cms.createZNode(CreateMode.PERSISTENT,
                            Path.NODE_TASK.getFullPath(task.getPluginExec(), jobInfo.getId()), task.toString());

                    // retira o pipeline da lista de pipelines para escanolamento no zookeeper
                    // cms.delete(cms.getPath().NODE_PIPELINE.getFullPath(pipeline.getId()));
                    // retira o pipelineda lista de jobs para escalonamento
                    this.pendingJobs.remove(jobInfo);

                    // adiciona a lista de jobs que aguardam execuo
                    task.setState(PluginTaskState.WAITING);
                    this.waitingTask.put(task.getId(), new Pair<>(pluginInfo, task));

                    // Log it
                    this.workflowLogger.log(new Log(
                            "Job <b>" + jobInfo.getId() + "</b> com arquivo de saida <b>" + jobInfo.getOutputs()
                                    + "</b> enviado para n de processamento do BioNimbuZ",
                            this.workflow.getUserId(), this.workflow.getId(), LogSeverity.INFO));

                    // Log all output files of a given workflow id
                    this.workflowLogger.logOutputFile(this.workflow.getId(), jobInfo.getOutputs());
                } else {
                    LOGGER.info("JobID: " + jobInfo.getId() + " no escalonado");
                }
            }
            // chamada recursiva para escalonar todos os jobs enviados, s  chamada aps um
            this.scheduleJobs();

        }
    }

    /**
     *
     * @param job
     */
    public void setLatencyPlugins(Job job) {

        final HashMap<String, Double> pluginIdLatency = new HashMap<>();
        try {
            // if(!cms.getZNodeExist(cms.getPath().PREFIX_JOB.getFullPath("", "", job.getId())+LATENCY, false)) {
            // for (PluginInfo plugin : getPeers().values()) {
            // //calcula a latencia e regula para segundos
            // pluginIdLatency.put(plugin.getId(),Ping.calculo(plugin.getHost().getAddress())/1000);
            //
            // }
            // cms.createZNode(CreateMode.PERSISTENT, cms.getPath().PREFIX_JOB.getFullPath("", "", job.getId())+LATENCY, new ObjectMapper().writeValueAsString(pluginIdLatency));
            // }
            throw new IOException("REMOVE COMMENTS");

        } catch (final IOException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Rotinas para auxiliar escalonamento,chamado caso seja necessrio cancelar
     * um job. No remove job em execuo.
     *
     * OBS: no utilizado
     *
     * @param jobId
     */
    public void cancelJob(String jobId) {
        // if (getPendingJobs().containsKey(jobId)) {
        // getPendingJobs().remove(jobId);
        // //excluir o job do zookeeper TO DO
        // } else if (waitingTask.containsKey(jobId)) {
        // waitingTask.remove(jobId);
        // }
        //// try {
        // cms.delete(JOBS.toString() + PREFIX_JOB.toString() + jobId);
        //
        //// } catch (KeeperException ex) {
        //// java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        //// } catch (InterruptedException ex) {
        //// java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        //// }
    }

    /**
     * Remove a tarefa da lista de jobs cancelados.Job permanece na lista de
     * jobs a serem escalonados.
     *
     * @param task
     */
    private synchronized void finishCancelJob(PluginTask task) {
        // getCancelingJobs().remove(task.getId());
        // System.out.println("Task canceled " + task.getId());
        //
        // relocateTasks.add(task);
        // // Verifica se todas as requisicoes de cancelamento foram realizadas.
        // // TODO: Provavelmente se o usuario cancelar o job na mao essa
        // // funcao vai buggar. Mas dado o tempo que temos acho que eh a melhor
        // // solucao.
    }

    /**
     * Realiza a requisio do(s) arquivo(s) que no existe(m) no plugin.
     *
     * @param listFiles
     *            lista de arquivos que devem conter no plugin
     */
    private void requestFile(List<FileInfo> listFiles) {

        for (final FileInfo info : listFiles) {

            if (!this.mapFilesPlugin.containsKey(info.getName())) {

                LOGGER.debug("[SchedService] Requesting file: " + info.getName());
                LOGGER.debug("[SchedService] Trying on the CloudStorage Buckets");

                if (BioNimbusConfig.get().getStorageMode().equalsIgnoreCase("1")) {

                    final CloudStorageService cloud_service = new CloudStorageService(this.cms);
                    final BioBucket bucket = cloud_service.findFile(info);

                    if (bucket != null) {
                        LOGGER.debug("[SchedService] File found on bucket: " + bucket.getName());

                        if (CloudStorageService.checkMode(bucket)) {

                            LOGGER.debug("[SchedService] Will execute on mounted-mode");
                            final PluginFile file = new PluginFile();

                            file.setId(info.getId());
                            file.setName(info.getName());

                            final String path = bucket.getMountPoint() + "/" + BioNimbusConfig.get().getDataFolder()
                                    + info.getName();
                            file.setPath(path);

                            this.mapFilesPlugin.put(info.getName(), file);

                            info.setBucket(bucket.getName());

                        } else {

                            LOGGER.debug("[SchedService] Will execute on normal-mode (download file first)");
                            final CloudStorageMethods cloud_methods = new CloudMethodsAmazonGoogle();

                            try {
                                cloud_methods.StorageDownloadFile(bucket, BioNimbusConfig.get().getDataFolder(),
                                        BioNimbusConfig.get().getDataFolder(), info.getName());
                            } catch (final Throwable t) {
                                LOGGER.error("[SchedService] Exception(requestFile): " + t.getMessage());
                                t.printStackTrace();
                            }
                        }

                    }

                } else { // Try old storage method
                    LOGGER.debug("[SchedService] Trying on the instances");
                    final String ipContainsFile = this.getFilesIP(info.getName());

                    LOGGER.debug("[SchedService] ipContainsFile: " + ipContainsFile);

                    final Get conexao = new Get();
                    try {
                        conexao.startSession(info.getName(), ipContainsFile);
                    } catch (final JSchException ex) {
                        java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null,
                                ex);
                    } catch (final SftpException ex) {
                        java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null,
                                ex);
                    }
                }

            }
        }
        this.checkFilesPlugin();
    }

    /**
     * Recebe uma lista de PluginsTasks para serem relanadas ao escalonamento.
     *
     * @param tasks
     *            lista das tarefas
     * @throws org.apache.zookeeper.KeeperException
     * @throws java.lang.InterruptedException
     */
    public void relocateTasks(Collection<PluginTask> tasks) throws KeeperException, InterruptedException {
        this.relocateTasks.addAll(tasks);

        // Adiciona os jobs cancelados a lista de jobs a serem escalonados no servidor zookeeper
        while (!this.relocateTasks.isEmpty()) {
            final PluginTask task = this.relocateTasks.remove();
            try {
                // cms.createZNode(CreateMode.PERSISTENT, JOBS + PREFIX_JOB + task.getJobInfo().getId(), task.getJobInfo().toString());
                throw new KeeperException.UnimplementedException();

            } catch (final Exception ex) {

                // StringBuilder datas = new StringBuilder(cms.getData(cms.getPath().STATUSWAITING.getFullPath(task.getPluginExec(), "", ""), null));
                // cms.setData(cms.getPath().STATUSWAITING.getFullPath(task.getPluginExec(), "", ""), datas.append("E").toString());
                LOGGER.info("[SchedService] COMMENTED cms.setData");
                tasks.add(task);
                java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    /**
     * Realiza a recuperao das tarefas que estavam em execuo no peer que
     * ficou off-line, colocando-as para serem reescalonadas. Ao final exclui o
     * zNode STATUSWAITING para que o peer possa ser excludo do servidor
     * zookeeper
     *
     * @param peerPath
     */
    private synchronized void repairTask(String peerPath) {
        final Collection<PluginTask> repairTasks = new LinkedList<>();
        try {

            if (!this.cms.getZNodeExist(peerPath + Path.STATUSWAITING, new UpdatePeerData(this.cms, this, null))) {
                this.cms.createZNode(CreateMode.PERSISTENT, peerPath + Path.STATUSWAITING, "");
            }
            String dataStatus = this.cms.getData(peerPath + Path.STATUSWAITING,
                    new UpdatePeerData(this.cms, this, null));

            // verifica se recurso j foi recuperado ou est sendo recuperado por outro recurso
            if (dataStatus.contains("B")) {
                return;
            }
            dataStatus = dataStatus.concat("status:B");
            // bloqueio para recuperar tarefas sem que outros recursos realizem a mesma operao
            this.cms.setData(peerPath + Path.STATUSWAITING, dataStatus);

            final List<String> tasksChildren = this.cms.getChildren(peerPath + Path.SCHED + Path.TASKS,
                    new UpdatePeerData(this.cms, this, null));

            for (final String taskChild : tasksChildren) {
                final ObjectMapper mapper = new ObjectMapper();
                final PluginTask pluginTask = mapper.readValue(
                        this.cms.getData(peerPath + Path.SCHED + Path.TASKS + "/" + taskChild, null),
                        PluginTask.class);
                if (pluginTask.getState() != PluginTaskState.DONE
                        && pluginTask.getState() != PluginTaskState.ERRO) {
                    repairTasks.add(pluginTask);
                }
            }
            this.relocateTasks(repairTasks);

            // retira bloqueio de uso e sinaliza que as tarefas do plugin foram recuperadas
            this.cms.delete(peerPath + Path.STATUSWAITING);

        } catch (final KeeperException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final InterruptedException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final IOException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Verifica qual  o Plugin referente ao mesmo do recurso.
     */
    private void checkMyPlugin() {
        for (final Listeners listener : this.listeners) {
            if (listener instanceof LinuxPlugin) {
                this.myLinuxPlugin = (LinuxPlugin) listener;
            }
        }
    }

    /**
     * Realiza a verificao dos peers existentes identificando se existe algum
     * peer aguardando recuperao, se o peer estiver off-line e a recuperao
     * j estiver sido feito, realiza a limpeza do peer. Realizada apenas quando
     * o mdulo inicia.
     */
    private void checkPeers() {
        // try {
        final List<String> listPeers = this.cms.getChildren(Path.PEERS.getFullPath(),
                new UpdatePeerData(this.cms, this, null));
        for (final String peerId : listPeers) {

            if (!this.cms.getZNodeExist(Path.STATUS.getFullPath(peerId), new UpdatePeerData(this.cms, this, null))
                    && !this.cms.getZNodeExist(Path.STATUSWAITING.getFullPath(peerId),
                            new UpdatePeerData(this.cms, this, null))) {
                this.cms.createZNode(CreateMode.PERSISTENT, Path.STATUSWAITING.getFullPath(peerId), "");
            }
            if (this.cms.getZNodeExist(Path.STATUSWAITING.getFullPath(peerId),
                    new UpdatePeerData(this.cms, this, null))) {
                if (!this.cms
                        .getData(Path.STATUSWAITING.getFullPath(peerId), new UpdatePeerData(this.cms, this, null))
                        .contains("")) {
                    this.repairTask(Path.NODE_PEER.getFullPath(peerId));
                }
            }

        }
        // } catch (KeeperException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // } catch (InterruptedException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // } catch (IOException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // }
    }

    /**
     * Verifica quais so as tarefas que j esto escanoladas e adiciona um
     * watcher em cada conjunto de tarefas dos plugins e nas tarefas caso
     * existam. Mtodo  chamado ao iniciar o mdulo de escalonamento.
     *
     * @throws KeeperException
     * @throws InterruptedException
     * @throws IOException
     */
    private void checkWaitingTasks() throws KeeperException, InterruptedException, IOException {
        final List<PluginInfo> plgs = new ArrayList<>(this.getPeers().values());
        List<String> listTasks;
        Watcher watcher;
        LOGGER.info("[SchedService] Checking waiting tasks");

        for (final PluginInfo plugin : plgs) {

            // cria watch para ser adicionado no znode que contm as tarefas escanoladas desse plugin
            if (this.myLinuxPlugin.getMyInfo().getId().equals(plugin.getId())) {
                LOGGER.info("[SchedService] checkWaitingTasks : watcher adicionado no plugin " + plugin.getId());
                watcher = new UpdatePeerData(this.cms, this, null);
            } else {
                watcher = null;
            }
            listTasks = this.cms.getChildren(Path.TASKS.getFullPath(plugin.getId()), watcher);

            for (final String task : listTasks) {
                final ObjectMapper mapper = new ObjectMapper();
                final PluginTask pluginTask = mapper.readValue(
                        this.cms.getData(Path.NODE_TASK.getFullPath(plugin.getId(), task), null), PluginTask.class);

                this.waitingTask.put(pluginTask.getId(), new Pair<>(plugin, pluginTask));
                if (pluginTask.getState() == PluginTaskState.DONE) {
                    this.finalizeTask(pluginTask);
                }

            }

            // adiconando watch para cada peer, realizar recuperao de task escalonadas caso o plugin fique off-line
            this.cms.getData(Path.STATUS.getFullPath(plugin.getId()), new UpdatePeerData(this.cms, this, null));
        }

    }

    /**
     * Verifica no zookeeper qual foi a nova tarefa colocada para execuo,
     * adiciona um watcher na tarefa e adiciona a tarefa na lista de tarefas que
     * esto aguardando execuo.
     *
     * @param peerPath
     *            caminho do local que foi criado a tarefa no zookeeper.
     * @return a pluginTask da tarefas adicionada para execuo
     * @throws KeeperException
     * @throws InterruptedException
     * @throws IOException
     */
    private PluginTask getNewTask(String taskPath) throws KeeperException, InterruptedException, IOException {
        final ObjectMapper mapper = new ObjectMapper();
        PluginTask pluginTask = null;
        final List<String> tasksChildren = this.cms.getChildren(taskPath, new UpdatePeerData(this.cms, this, null));

        for (final String taskChild : tasksChildren) {
            final String datasTask = this.cms.getData(taskPath + "/" + taskChild,
                    new UpdatePeerData(this.cms, this, null));

            final PluginTask task = mapper.readValue(datasTask, PluginTask.class);
            // verifica se a tarefa j estava na lista para no adicionar mais de um watcher
            if (!this.waitingTask.containsKey(task.getId())) {
                // adiciona um watcher na task que foi escanolada
                this.cms.getData(taskPath + "/" + taskChild, new UpdatePeerData(this.cms, this, null));
                if (task.getState() == PluginTaskState.PENDING) {
                    this.waitingTask.put(task.getId(), new Pair<>(this.cloudMap.get(task.getPluginExec()), task));
                    pluginTask = task;
                }
            }
        }
        return pluginTask;
    }

    private void decryptFiles(List<FileInfo> inputs) throws Exception {
        try {
            // realiza uma chama rpc para decriptografar os arquivos que serao usados pela task
            this.rpcClient = new AvroClient(BioNimbusConfig.get().getRpcProtocol(),
                    this.myLinuxPlugin.getMyInfo().getHost().getAddress(),
                    this.myLinuxPlugin.getMyInfo().getHost().getPort());
            for (final FileInfo info : inputs) {
                this.rpcClient.getProxy().decryptPluginFile(info.getName());
            }
            this.rpcClient.close();
        } catch (final IOException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Mtodo que realiza a verificao dos arquivos existentes no plugin para
     * possveis utilizaes durante a execuo das tarefas.
     *
     */
    // TODO ajustar a Storage para realizar alguma foram de atualizao dos arquivos antes e depois de uma execuo e ento inutilizar esse mtodo
    private void checkFilesPlugin() {
        try {
            // realiza uma chama rpc para atualizar a lista de arquivos no zookeeper
            this.rpcClient = new AvroClient(BioNimbusConfig.get().getRpcProtocol(),
                    this.myLinuxPlugin.getMyInfo().getHost().getAddress(),
                    this.myLinuxPlugin.getMyInfo().getHost().getPort());
            this.rpcClient.getProxy().listFilesName();
            this.rpcClient.close();
            if (this.cms.getZNodeExist(Path.FILES.getFullPath(this.myLinuxPlugin.getMyInfo().getId()),
                    new UpdatePeerData(this.cms, this, null))) {
                List<String> filesChildren;
                // verifica se  a primeira vez que  executado e ento cria o watcher e inicia a lista
                if (this.mapFilesPlugin == null) {
                    this.mapFilesPlugin = new HashMap<>();
                    filesChildren = this.cms.getChildren(
                            Path.FILES.getFullPath(this.myLinuxPlugin.getMyInfo().getId()),
                            new UpdatePeerData(this.cms, this, null));
                } else {
                    filesChildren = this.cms.getChildren(
                            Path.FILES.getFullPath(this.myLinuxPlugin.getMyInfo().getId()),
                            new UpdatePeerData(this.cms, this, null));
                }
                final ObjectMapper mapper = new ObjectMapper();

                for (final String fileChild : filesChildren) {
                    final String datasFile = this.cms.getData(
                            Path.NODE_FILE.getFullPath(this.myLinuxPlugin.getMyInfo().getId(), fileChild),
                            new UpdatePeerData(this.cms, this, null));
                    final PluginFile file = mapper.readValue(datasFile, PluginFile.class);
                    // Verificar o que  esse LONG TO DO
                    final Pair<String, Long> pair = new Pair<>(file.getName(), file.getSize());
                    // verifica se o arquivo j estava na lista
                    if (!this.mapFilesPlugin.containsKey(pair.first)) {
                        this.mapFilesPlugin.put(file.getName(), file);
                    }
                }
            }
        } catch (final KeeperException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final InterruptedException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final IOException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final Exception ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Verifica o status da tarefa e se ela pertence ao plugin e executa se
     * satisfizer essas condies.
     */
    private void checkStatusTask() {
        LOGGER.info("[SchedService] checkStatusTask");
        for (final Pair<PluginInfo, PluginTask> pair : this.waitingTask.values()) {
            if (this.myLinuxPlugin.getMyInfo().getId().equals(pair.first.getId())
                    && pair.second.getState() == PluginTaskState.PENDING) {
                try {
                    this.executeTasks(pair.second);
                } catch (final Exception ex) {
                    java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

    }

    /**
     * Verifica se as tarefas que estavam aguardando algum arquivo j foram
     * executadas, se no solicita execuo.
     */
    private void checkTasks() {
        try {

            LOGGER.info("[SchedService] Checking Tasks...");

            // Check if there are any pipelines left to add
            this.updatePipelines();

            if (this.waitingTask != null && !this.waitingTask.isEmpty()) {
                for (final Pair<PluginInfo, PluginTask> pair : this.waitingTask.values()) {
                    if (pair.first.getHost().getAddress()
                            .equals(this.myLinuxPlugin.getMyInfo().getHost().getAddress())) {
                        if (pair.second.getState() == PluginTaskState.WAITING) {
                            this.executeTasks(pair.second);
                            // Consumer<Job> style =(Job p) -> System.out.println("id:"+p.getIpjob().);
                            final List<String> ip = new ArrayList<>();
                            ip.addAll(pair.second.getJobInfo().getIpjob());
                            // remove the others ips attributed to the task, leaving just the ip wich is executing the task
                            for (final String j : ip) {
                                if (!j.equals(this.myLinuxPlugin.getMyInfo().getHost().getAddress())) {
                                    pair.second.getJobInfo().getIpjob().remove(j);
                                }
                            }
                        }
                    }
                    if (pair.second.getState() == PluginTaskState.DONE) {
                        this.finalizeTask(pair.second);
                    }
                }
            }

            // check if any dependent task can be executed
            if (this.dependentJobs != null && !this.dependentJobs.isEmpty()) {
                final List<String> finishedJobs = this.cms.getChildren(Path.FINISHED_TASKS.getFullPath(), null);
                for (final Iterator<Job> it = this.dependentJobs.iterator(); it.hasNext();) {
                    final Job j = it.next();
                    // remove finished dependencies
                    for (final Iterator<String> it2 = j.getDependencies().iterator(); it2.hasNext();) {
                        final String d = it2.next();
                        for (final String f : finishedJobs) {
                            if (f.equals(d)) {
                                it2.remove();
                            }
                        }
                    }
                    // if there are no more dependencies put j on pendingJobs
                    if (j.getDependencies().isEmpty()) {
                        this.pendingJobs.add(j);
                        it.remove();
                    }
                }
            }

            // schedule jobs if there are any
            if (this.pendingJobs != null && !this.pendingJobs.isEmpty()) {
                LOGGER.info("Tamanho da lista de JOBS para execuo :  " + this.pendingJobs.size());
                this.scheduleJobs();
            }

        } catch (final Exception ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Recebe a ltima tarefa enviada para execuo
     *
     * @param task
     */
    private void executeTasks(PluginTask task) throws Exception {
        LOGGER.info("Recebimento do pedido de execuo da tarefa!");
        // TODO otimiza chamada de checagem dos arquivos
        this.checkFilesPlugin();

        // CORREO: CRIAR N FILES E REFAZER ESSA FUNO
        // //verifica se o arquivo existe no plugin se no cria a solicitao de transfrencia do arquivo
        // if (!existFilesCloud(task.getJobInfo().getInputs())) {
        // task.setState(PluginTaskState.ERRO);
        // System.out.println("[SchedService] executeTasks: task " + task.getId() + " error.");
        // return;
        // }
        if (!this.existFiles(task.getJobInfo().getInputFiles())) {
            LOGGER.info("Files from JobInfo(id=" + task.getJobInfo().getId() + ") not found. Requesting file...");

            for (final FileInfo f : task.getJobInfo().getInputFiles()) {
                LOGGER.info("Arquivo: " + f.getName());
            }

            this.requestFile(task.getJobInfo().getInputFiles());

            LOGGER.info("Task " + task.getId() + " files not present.");
        }
        if (this.existFiles(task.getJobInfo().getInputFiles())) {
            this.decryptFiles(task.getJobInfo().getInputFiles());

            // Executes the command line and upload it to ZooKeeper
            this.myLinuxPlugin.startTask(task, this.cms, this.workflow);

            LOGGER.info("Task " + task.getId() + " started.");
        } else {
            task.setState(PluginTaskState.WAITING);
            LOGGER.info("Task " + task.getId() + " waiting.");
        }
    }

    /**
     * Verifica a existncia dos arquivos de entrada no plugin, lista de
     * arquivos  atualizada ao plugin ser iniciado e quando um novo arquivo 
     * adicionado ao plugin.
     *
     * @param listInputFiles
     * @return
     */
    private boolean existFiles(List<FileInfo> listInputFiles) {

        int toFind = listInputFiles.size();

        if (listInputFiles.isEmpty()) {
            return true;
        }

        for (final FileInfo fileInput : listInputFiles) {
            if (this.mapFilesPlugin.containsKey(fileInput.getName())) {
                toFind--;
            }
        }

        if (toFind == 0) {
            return true;
        }

        return false;
    }

    /**
     * MEtodo aparentemente no utilizado Verifica a existncia dos arquivos de
     * entrada na federao, caso no exista retorna false.
     *
     * @param listInputFiles
     * @return false se no existir algum arquivo no zoonimbus
     */
    private boolean existFilesCloud(List<Pair<String, Long>> listInputFiles) {

        for (final Pair<String, Long> fileInput : listInputFiles) {
            if (this.getFilesIP(fileInput.first) == null) {
                LOGGER.info("Arquivo :" + fileInput.first + " no existe no Zoonimbus !!!");
                return false;
            }
        }

        return true;
    }

    /**
     * Realiza a chamada dos mtodos para a finalizao da execuo do job.
     *
     * @param pathTask
     *            endereo do znode, task executada.
     */
    private void finalizeTask(PluginTask task) {
        if (this.waitingTask.containsKey(task.getId())) {
            this.waitingTask.remove(task.getId());
        }

        // try {
        this.getPolicy().jobDone(task);
        this.cms.delete(Path.NODE_TASK.getFullPath(task.getPluginExec(), task.getJobInfo().getId()));

        // chamada de mtodo para atualizar a lista de arquivos
        // TODO ajustar a Storage para realizar alguma foram de atualizao dos arquivos aps uma execuo.
        this.checkFilesPlugin();

        // cria um znode efmero para exibir jobs finalizados,  efmero para poder ser apagado quando peer ficar off-line
        this.cms.createZNode(CreateMode.PERSISTENT,
                Path.NODE_FINISHED_TASK.getFullPath(task.getPluginExec(), task.getJobInfo().getId()),
                task.toString());

        // } catch (KeeperException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // } catch (InterruptedException ex) {
        // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        // }
        LOGGER.info("[SchedService] task finished: " + task.getId());

    }

    /**
     * Metodo para pegar o Ip do peer na federao que esta com o arquivo
     * se o arquivo for encontrado retorna o Ip do peer, caso contrrio
     * retorna null.
     *
     * @param fileId
     * @return
     */
    public String getFilesIP(String fileId) {
        List<String> listFiles;
        // Map<String,List<String>> mapFiles = new HashMap<String, List<String>>();
        // try {
        for (final PluginInfo plugin : this.getPeers().values()) {
            listFiles = this.cms.getChildren(Path.FILES.getFullPath(plugin.getId()), null);
            for (final String checkfile : listFiles) {
                // atualizar

                // String idfile = checkfile.substring(5, checkfile.length());
                if (fileId.equals(checkfile)) {
                    return plugin.getHost().getAddress();
                }
            }
        } // } catch (KeeperException ex) {
          // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
          // } catch (InterruptedException ex) {
          // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
          // } catch (IOException ex) {
          // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
          // }

        return null;

    }

    /**
     * Trata os watchers enviados pelas mudanas realizadas no zookeeper.
     *
     * @param eventType
     *            evento recebido do zookeeper
     */
    @Override
    public void event(WatchedEvent eventType) {

        try {
            switch (eventType.getType()) {

            case NodeChildrenChanged:

                String datas;
                // reconhece um alerta de um novo pipeline

                if (eventType.getPath().contains(Path.PIPELINES.toString()) && !this.isClient) {
                    LOGGER.info("[SchedService] Recebimento de um alerta para um pipeline, NodeChildrenChanged");
                    // checking moved to checkTasks in order to solve racing condition
                    // updatePipelines();

                } else if (eventType.getPath().contains(Path.SCHED.toString() + Path.TASKS)) {
                    LOGGER.info("[SchedService] Recebimento de um alerta para uma TAREFA");

                    // verifica qual foi o job colocado para ser executado
                    final PluginTask pluginTask = this.getNewTask(eventType.getPath());

                    // verifica se um existe algum novo pluginTask
                    if (pluginTask != null) {
                        if (pluginTask.getState() == PluginTaskState.PENDING) {
                            this.executeTasks(pluginTask);
                        }
                    } else if (!this.waitingTask.isEmpty()) {
                        this.checkStatusTask();
                    }

                } else if (eventType.getPath().contains(Path.FILES.toString())) {
                    this.checkFilesPlugin();

                } else if (eventType.getPath().equals(Path.PEERS.toString())) {
                    if (this.cloudMap.size() < this.getPeers().size()) {
                        this.verifyPlugins();
                    }
                }

                break;
            case NodeDataChanged:
                // reconhece o alerta como uma mudana na poltica de escalonamento
                // if (eventType.getPath().contains(JOBS.getCodigo()) && !eventType.getPath().contains(PREFIX_JOB.toString())) {
                // setPolicy();

                // reconhece a mudana no estado da tarefa
                // } else
                if (this.cms.getZNodeExist(eventType.getPath(), null)) {
                    datas = this.cms.getData(eventType.getPath(), null);
                    final PluginTask pluginTask = (PluginTask) this.convertString(PluginTask.class, datas);

                    // retirar depois testes, exibi a tarefa que est em execuo
                    if (pluginTask.getState() == PluginTaskState.RUNNING) {
                        LOGGER.info("Task est rodando: "
                                + Path.NODE_TASK.getFullPath(pluginTask.getPluginExec(), pluginTask.getId()));
                    }
                    if (pluginTask.getState() == PluginTaskState.DONE) {
                        this.finalizeTask(pluginTask);
                    }
                }
                break;

            case NodeDeleted:

                // Trata o evento de quando o zNode status for apagado, ou seja, quando um peer estiver off-line, deve recuperar os jobs
                // que haviam sido escalonados para esse peer
                if (eventType.getPath().contains(Path.STATUS.toString())) {
                    // cloudMap.clear();
                    // cloudMap.putAll(getPeers());
                    // schedPolicy.setCloudMap(cloudMap);
                    this.repairTask(eventType.getPath().subSequence(0, eventType.getPath().indexOf("STATUS") - 1)
                            .toString());
                }

                break;
            }
        } catch (final KeeperException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final InterruptedException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        } catch (final Exception ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void registerPipeline(br.unb.cic.bionimbuz.avro.gen.Workflow workflow) {
        this.cms.createZNode(CreateMode.PERSISTENT, Path.NODE_PIPELINE.getFullPath(workflow.getId()),
                workflow.toString());
    }

    private void updatePipelines() throws IOException, InterruptedException, KeeperException {
        // get all pipelines
        final List<String> pipelinesId = this.cms.getChildren(Path.PIPELINES.getFullPath(), null);
        String datas;

        if (!pipelinesId.isEmpty()) {

            // get pipelines and add them to pendingPipelines
            for (final String pipelineReady : pipelinesId) {
                final ObjectMapper mapper = new ObjectMapper();
                datas = this.cms.getData(Path.NODE_PIPELINE.getFullPath(pipelineReady),
                        new UpdatePeerData(this.cms, this, null));

                // Sets it workflow
                this.workflow = mapper.readValue(datas, Workflow.class);

                this.workflowLogger.log(new Log("Iniciando servio de escalonamento...", this.workflow.getUserId(),
                        this.workflow.getId(), LogSeverity.INFO));

                // add independent jobs to pendingJobs list and jobs with
                // any dependency to the dependentJobs list
                int i = 0;
                for (final Job j : this.workflow.getJobs()) {
                    if (j.getDependencies().isEmpty()) {
                        this.pendingJobs.add(j);
                        i++;
                    } else {
                        this.dependentJobs.add(j);
                    }
                }

                LOGGER.info("Workflow is compound by: " + i + " independent jobs and "
                        + (this.workflow.getJobs().size() - i) + " jobs with dependency");

                // Log it
                this.workflowLogger.log(new Log(" Job(s) independente(s): <b>" + i + "</b>",
                        this.workflow.getUserId(), this.workflow.getId(), LogSeverity.INFO));
                this.workflowLogger.log(
                        new Log("Job(s) com dependncia(s): <b>" + (this.workflow.getJobs().size() - i) + "</b>",
                                this.workflow.getUserId(), this.workflow.getId(), LogSeverity.INFO));

                // remove pipeline from zookeeper
                this.cms.delete(Path.NODE_PIPELINE.getFullPath(pipelineReady));
            }

            if (!this.pendingJobs.isEmpty()) {
                this.scheduleJobs();
            }
        }
    }

    @Override
    public void verifyPlugins() {
        final Collection<PluginInfo> temp = this.getPeers().values();
        temp.removeAll(this.cloudMap.values());
        for (final PluginInfo plugin : temp) {
            // try {
            if (this.cms.getZNodeExist(Path.STATUS.getFullPath(plugin.getId()), null)) {
                this.cms.getData(Path.STATUS.getFullPath(plugin.getId()), new UpdatePeerData(this.cms, this, null));
            }
            // } catch (KeeperException ex) {
            // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
            // } catch (InterruptedException ex) {
            // java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
            // }
        }

    }

    private Object convertString(Class classe, String datas) {
        Object object = null;
        try {
            final ObjectMapper mapper = new ObjectMapper();
            object = mapper.readValue(datas, classe);

        } catch (final IOException ex) {
            java.util.logging.Logger.getLogger(SchedService.class.getName()).log(Level.SEVERE, null, ex);
        }

        return object;

    }

    public synchronized Map<String, PluginInfo> getCancelingJobs() {
        return this.cancelingJobs;
    }

    public synchronized Map<String, Job> getJobsWithNoService() {
        return this.jobsWithNoService;
    }

    @Override
    public void shutdown() {
        this.listeners.remove(this);
        this.schedExecService.shutdownNow();
    }

    @Override
    public void getStatus() {
        // TODO Auto-generated method stub
    }
}