JAL-3190 rough Proof of Concept of JalviewJS - Chimera
[jalview.git] / src / ext / edu / ucsf / rbvi / strucviz2 / port / ListenerThreads.java
1 /* vim: set ts=2: */
2 /**
3  * Copyright (c) 2006 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions, and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions, and the following
13  *      disclaimer in the documentation and/or other materials provided
14  *      with the distribution.
15  *   3. Redistributions must acknowledge that this software was
16  *      originally developed by the UCSF Computer Graphics Laboratory
17  *      under support by the NIH National Center for Research Resources,
18  *      grant P41-RR01081.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 package ext.edu.ucsf.rbvi.strucviz2.port;
34
35 import java.io.BufferedReader;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43
44 import ext.edu.ucsf.rbvi.strucviz2.Logger;
45
46 //import org.slf4j.Logger;
47 //import org.slf4j.LoggerFactory;
48
49 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
50
51 /***************************************************
52  *                 Thread Classes                  *
53  **************************************************/
54
55 /**
56  * Reply listener thread
57  */
58 public class ListenerThreads extends Thread
59 {
60   private BufferedReader lineReader = null;
61
62   private Process chimera = null;
63
64   private Map<String, List<String>> replyLog = null;
65
66   private Logger logger = new Logger();
67
68   private StructureManager structureManager = null;
69
70   private boolean stopMe = false;
71
72   /**
73    * Create a new listener thread to read the responses from Chimera
74    * 
75    * @param chimera
76    *          a handle to the Chimera Process
77    * @param structureManager
78    *          a handle to the Chimera structure manager
79    */
80   public ListenerThreads(Process chimera, StructureManager structureManager)
81   {
82     this.chimera = chimera;
83     this.structureManager = structureManager;
84     replyLog = new HashMap<String, List<String>>();
85     // Get a line-oriented reader
86     InputStream readChan = chimera.getInputStream();
87     lineReader = new BufferedReader(new InputStreamReader(readChan));
88     logger =new Logger();
89     //LoggerFactory.getLogger(ext.edu.ucsf.rbvi.strucviz2.port.ListenerThreads.class);
90   }
91
92   /**
93    * Start the thread running
94    */
95   public void run()
96   {
97     // System.out.println("ReplyLogListener running");
98     while (!stopMe)
99     {
100       try
101       {
102         chimeraRead();
103       } catch (IOException e)
104       {
105         logger.warn("UCSF Chimera has exited: " + e.getMessage());
106         return;
107       } finally
108       {
109         if (lineReader != null)
110         {
111           try
112           {
113             lineReader.close();
114           } catch (IOException e)
115           {
116           }
117         }
118       }
119     }
120   }
121
122   public List<String> getResponse(String command)
123   {
124     List<String> reply;
125     // System.out.println("getResponse: "+command);
126     // TODO do we need a maximum wait time before aborting?
127     while (!replyLog.containsKey(command))
128     {
129       try
130       {
131         Thread.currentThread().sleep(100);
132       } catch (InterruptedException e)
133       {
134       }
135     }
136
137     synchronized (replyLog)
138     {
139       reply = replyLog.get(command);
140       // System.out.println("getResponse ("+command+") = "+reply);
141       replyLog.remove(command);
142     }
143     return reply;
144   }
145
146   public void clearResponse(String command)
147   {
148     try
149     {
150       Thread.currentThread().sleep(100);
151     } catch (InterruptedException e)
152     {
153     }
154     if (replyLog.containsKey(command))
155     {
156       replyLog.remove(command);
157     }
158     return;
159   }
160
161   /**
162    * Read input from Chimera
163    * 
164    * @return a List containing the replies from Chimera
165    */
166   private void chimeraRead() throws IOException
167   {
168     if (chimera == null)
169     {
170       return;
171     }
172
173     String line = null;
174     while ((line = lineReader.readLine()) != null)
175     {
176       // System.out.println("From Chimera-->" + line);
177       if (line.startsWith("CMD"))
178       {
179         chimeraCommandRead(line.substring(4));
180       }
181       else if (line.startsWith("ModelChanged: "))
182       {
183         (new ModelUpdater()).start();
184       }
185       else if (line.startsWith("SelectionChanged: "))
186       {
187         (new SelectionUpdater()).start();
188       }
189       else if (line.startsWith("Trajectory residue network info:"))
190       {
191         (new NetworkUpdater(line)).start();
192       }
193     }
194     return;
195   }
196
197   private void chimeraCommandRead(String command) throws IOException
198   {
199     // Generally -- looking for:
200     // CMD command
201     // ........
202     // END
203     // We return the text in between
204     List<String> reply = new ArrayList<String>();
205     boolean updateModels = false;
206     boolean updateSelection = false;
207     boolean importNetwork = false;
208     String line = null;
209
210     synchronized (replyLog)
211     {
212       while ((line = lineReader.readLine()) != null)
213       {
214         // System.out.println("From Chimera (" + command + ") -->" + line);
215         if (line.startsWith("CMD"))
216         {
217           logger.warn("Got unexpected command from Chimera: " + line);
218
219         }
220         else if (line.startsWith("END"))
221         {
222           break;
223         }
224         if (line.startsWith("ModelChanged: "))
225         {
226           updateModels = true;
227         }
228         else if (line.startsWith("SelectionChanged: "))
229         {
230           updateSelection = true;
231         }
232         else if (line.length() == 0)
233         {
234           continue;
235         }
236         else if (!line.startsWith("CMD"))
237         {
238           reply.add(line);
239         }
240         else if (line.startsWith("Trajectory residue network info:"))
241         {
242           importNetwork = true;
243         }
244       }
245       replyLog.put(command, reply);
246     }
247     if (updateModels)
248     {
249       (new ModelUpdater()).start();
250     }
251     if (updateSelection)
252     {
253       (new SelectionUpdater()).start();
254     }
255     if (importNetwork)
256     {
257       (new NetworkUpdater(line)).start();
258     }
259     return;
260   }
261
262   /**
263    * Model updater thread
264    */
265   class ModelUpdater extends Thread
266   {
267
268     public ModelUpdater()
269     {
270     }
271
272     public void run()
273     {
274       structureManager.updateModels();
275       structureManager.modelChanged();
276     }
277   }
278
279   /**
280    * Selection updater thread
281    */
282   class SelectionUpdater extends Thread
283   {
284
285     public SelectionUpdater()
286     {
287     }
288
289     public void run()
290     {
291       try
292       {
293         logger.info("Responding to chimera selection");
294         structureManager.chimeraSelectionChanged();
295       } catch (Exception e)
296       {
297         logger.warn("Could not update selection", e);
298       }
299     }
300   }
301
302   /**
303    * Selection updater thread
304    */
305   class NetworkUpdater extends Thread
306   {
307
308     private String line;
309
310     public NetworkUpdater(String line)
311     {
312       this.line = line;
313     }
314
315     public void run()
316     {
317       try
318       {
319         // ((TaskManager<?, ?>) structureManager.getService(TaskManager.class))
320         // .execute(new ImportTrajectoryRINTaskFactory(structureManager, line)
321         // .createTaskIterator());
322       } catch (Exception e)
323       {
324         logger.warn("Could not import trajectory network", e);
325       }
326     }
327   }
328
329   /**
330    * Set a flag that this thread should clean up and exit.
331    */
332   public void requestStop()
333   {
334     this.stopMe = true;
335   }
336 }