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 }