001    package opendreams.proxy;
002    
003    import java.util.List;
004    import java.util.Vector;
005    
006    import tecgraf.openbus.DRMAA.JobInfo;
007    import tecgraf.openbus.DRMAA.Session;
008    import tecgraf.openbus.opendreams.IOpenDreams;
009    import tecgraf.openbus.opendreams.OpenDreamsJobTemplate;
010    
011    /**
012     * Classe utilitária para disparar a execução de um algoritmo em uma thread
013     * separada.
014     * 
015     * Permite a adição de listeners que são chamados ao término da execução.
016     * 
017     * @author Tecgraf PUC-Rio
018     */
019    public class AsynchronousExecutor extends Thread {
020      /** Comando que executa um algoritmo do repositório */
021      public static final String SIMPLE_ALGORITHM = "execAlgo";
022      /** Nome do projeto usado para execução do comando */
023      private String projectName;
024      /** Nome do algoritmo referente ao comando executado */
025      private String algorithmName;
026      /** Versão do algoritmo referente ao comando executado */
027      private String algorithmVersion;
028      /** Email a ser notificado do término do comando */
029      private String email;
030      /** Descrição do comando */
031      private String description;
032      /** Parâmetros para o comando a ser executado */
033      private List<String[]> parameters;
034      /** Nome para o comando */
035      private String jobName;
036      /** Tempo limite para aguardar o término de comando */
037      private long timeout = Session.TIMEOUT_WAIT_FOREVER;
038      /** Sessão OpenDreams usada para execução do comando */
039      private Session session;
040      /**
041       * Lista com os listeners interessados em ser notificados sobre a execução do
042       * algoritmo submetido para execução no OpenDreams.
043       */
044      private List<AsynchronousExecutorListener> executorListeners;
045    
046      /**
047       * Construtor.
048       */
049      public AsynchronousExecutor() {
050        this.executorListeners = new Vector<AsynchronousExecutorListener>();
051        this.parameters = new Vector<String[]>();
052      }
053    
054      /**
055       * Executa o algoritmo remotamente, usando o OpenDreams. Ao final da execução,
056       * notifica os listeners cadastrados.
057       * 
058       */
059      @Override
060      public void run() {
061        remoteExecute();
062      }
063    
064      /**
065       * Adiciona um listener interessado em ser notificados sobre a execução do
066       * algoritmo submetido para execução no OpenDreams.
067       * 
068       * @param listener o listener para a execução do algoritmo
069       */
070      public void addExecutorListener(AsynchronousExecutorListener listener) {
071        executorListeners.add(listener);
072      }
073    
074      /**
075       * Altera o nome do projeto usado para execução do comando.
076       * @param projectName nome do projeto
077       */
078      public void setProjectName(String projectName) {
079        this.projectName = projectName;
080      }
081    
082      /**
083       * Altera o nome do algoritmo usado para execução do comando.
084       * @param algorithmName nome do algoritmo
085       */
086      public void setAlgorithmName(String algorithmName) {
087        this.algorithmName = algorithmName;
088      }
089    
090      /**
091       * Altera a versão do algoritmo usado para execução do comando.
092       * @param algorithmVersion versão do algoritmo
093       */
094      public void setAlgorithmVersion(String algorithmVersion) {
095        this.algorithmVersion = algorithmVersion;
096      }
097    
098      /**
099       * Adiciona um parâmetro do algoritmo.
100       * @param parameterName nome do parâmetro
101       * @param parameterValue valor do parâmetro 
102       */
103      public void setParameter(String parameterName, String parameterValue) {
104        parameters.add(new String[] { parameterName, parameterValue });
105      }
106    
107      /**
108       * Altera o email a ser notificado ao término da execução do comando.
109       * @param email email para notificação
110       */
111      public void setEmail(String email) {
112        this.email = email;
113      }
114    
115      /**
116       * Altera a descrição do comando a ser executado.
117       * @param description descrição do comando
118       */
119      public void setDescription(String description) {
120        this.description = description;
121      }
122    
123      /**
124       * Executa o algoritmo remotamente. Ao final da execução ou em falha na chamada ao
125       * OpenDreams, notifica os listeners cadastrados.
126       */
127      private void remoteExecute() {
128        try {
129          OpenDreamsProxy openDreams = new OpenDreamsProxy();
130          openDreams.init();
131          IOpenDreams opendreams = openDreams.getIOpenDreams();
132    
133          session = opendreams.getSession(projectName);
134          session.init("");
135          OpenDreamsJobTemplate jt =
136            (OpenDreamsJobTemplate) session.createJobTemplate();
137          jt.setRemoteCommand(SIMPLE_ALGORITHM);
138          jt.setArgs(new String[] { "-name", algorithmName, "-version",
139              algorithmVersion });
140          for (String[] parameter : parameters) {
141            jt.addJobParameter(parameter[0], parameter[1]);
142          }
143          if (email != null) {
144            jt.setEmail(new String[] { email });
145          }
146          if (description != null) {
147            jt.setJobDescription(description);
148          }
149          this.jobName = session.runJob(jt);
150          session.deleteJobTemplate(jt);
151          JobInfo jobInfo = session._wait(jobName, timeout);
152          openDreams.logout();
153          int result = jobInfo.exitStatus;
154          if (result == 0) {
155            notifyListeners(AsynchronousExecutorListener.SUCCESS,
156              "Execução remota do comando terminou com sucesso");
157          }
158          else {
159            notifyListeners(AsynchronousExecutorListener.FAILURE,
160              "Execução remota do comando terminou com erro: " + result);
161          }
162        }
163        catch (Exception e) {
164          notifyListeners(AsynchronousExecutorListener.FAILURE,
165            "Falha na chamada ao OpenDreams: " + e.getMessage());
166        }
167      }
168    
169      /**
170       * Notifica os listeners sobre a execução do algoritmo.
171       * 
172       * @param result SUCCESS, caso o algoritmo tenha executado com êxito, ou
173       *        FAILURE, caso contrário.
174       * @param msg a mensagem a ser enviada.
175       */
176      private void notifyListeners(int result, String msg) {
177        for (AsynchronousExecutorListener listener : executorListeners) {
178          listener.executionFinished(result, msg);
179        }
180      }
181    }