JAL-2325 applied BSD license for chimera/StrucViz2 code
[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 org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
48
49 /***************************************************
50  *                 Thread Classes                  *
51  **************************************************/
52
53 /**
54  * Reply listener thread
55  */
56 public class ListenerThreads extends Thread
57 {
58   private BufferedReader lineReader = null;
59
60   private Process chimera = null;
61
62   private Map<String, List<String>> replyLog = null;
63
64   private Logger logger;
65
66   private StructureManager structureManager = null;
67
68   private boolean stopMe = false;
69
70   /**
71    * Create a new listener thread to read the responses from Chimera
72    * 
73    * @param chimera
74    *          a handle to the Chimera Process
75    * @param structureManager
76    *          a handle to the Chimera structure manager
77    */
78   public ListenerThreads(Process chimera, StructureManager structureManager)
79   {
80     this.chimera = chimera;
81     this.structureManager = structureManager;
82     replyLog = new HashMap<String, List<String>>();
83     // Get a line-oriented reader
84     InputStream readChan = chimera.getInputStream();
85     lineReader = new BufferedReader(new InputStreamReader(readChan));
86     logger = LoggerFactory
87             .getLogger(ext.edu.ucsf.rbvi.strucviz2.port.ListenerThreads.class);
88   }
89
90   /**
91    * Start the thread running
92    */
93   public void run()
94   {
95     // System.out.println("ReplyLogListener running");
96     while (!stopMe)
97     {
98       try
99       {
100         chimeraRead();
101       } catch (IOException e)
102       {
103         logger.warn("UCSF Chimera has exited: " + e.getMessage());
104         return;
105       } finally
106       {
107         if (lineReader != null)
108         {
109           try
110           {
111             lineReader.close();
112           } catch (IOException e)
113           {
114           }
115         }
116       }
117     }
118   }
119
120   public List<String> getResponse(String command)
121   {
122     List<String> reply;
123     // System.out.println("getResponse: "+command);
124     // TODO do we need a maximum wait time before aborting?
125     while (!replyLog.containsKey(command))
126     {
127       try
128       {
129         Thread.currentThread().sleep(100);
130       } catch (InterruptedException e)
131       {
132       }
133     }
134
135     synchronized (replyLog)
136     {
137       reply = replyLog.get(command);
138       // System.out.println("getResponse ("+command+") = "+reply);
139       replyLog.remove(command);
140     }
141     return reply;
142   }
143
144   public void clearResponse(String command)
145   {
146     try
147     {
148       Thread.currentThread().sleep(100);
149     } catch (InterruptedException e)
150     {
151     }
152     if (replyLog.containsKey(command))
153     {
154       replyLog.remove(command);
155     }
156     return;
157   }
158
159   /**
160    * Read input from Chimera
161    * 
162    * @return a List containing the replies from Chimera
163    */
164   private void chimeraRead() throws IOException
165   {
166     if (chimera == null)
167     {
168       return;
169     }
170
171     String line = null;
172     while ((line = lineReader.readLine()) != null)
173     {
174       // System.out.println("From Chimera-->" + line);
175       if (line.startsWith("CMD"))
176       {
177         chimeraCommandRead(line.substring(4));
178       }
179       else if (line.startsWith("ModelChanged: "))
180       {
181         (new ModelUpdater()).start();
182       }
183       else if (line.startsWith("SelectionChanged: "))
184       {
185         (new SelectionUpdater()).start();
186       }
187       else if (line.startsWith("Trajectory residue network info:"))
188       {
189         (new NetworkUpdater(line)).start();
190       }
191     }
192     return;
193   }
194
195   private void chimeraCommandRead(String command) throws IOException
196   {
197     // Generally -- looking for:
198     // CMD command
199     // ........
200     // END
201     // We return the text in between
202     List<String> reply = new ArrayList<String>();
203     boolean updateModels = false;
204     boolean updateSelection = false;
205     boolean importNetwork = false;
206     String line = null;
207
208     synchronized (replyLog)
209     {
210       while ((line = lineReader.readLine()) != null)
211       {
212         // System.out.println("From Chimera (" + command + ") -->" + line);
213         if (line.startsWith("CMD"))
214         {
215           logger.warn("Got unexpected command from Chimera: " + line);
216
217         }
218         else if (line.startsWith("END"))
219         {
220           break;
221         }
222         if (line.startsWith("ModelChanged: "))
223         {
224           updateModels = true;
225         }
226         else if (line.startsWith("SelectionChanged: "))
227         {
228           updateSelection = true;
229         }
230         else if (line.length() == 0)
231         {
232           continue;
233         }
234         else if (!line.startsWith("CMD"))
235         {
236           reply.add(line);
237         }
238         else if (line.startsWith("Trajectory residue network info:"))
239         {
240           importNetwork = true;
241         }
242       }
243       replyLog.put(command, reply);
244     }
245     if (updateModels)
246     {
247       (new ModelUpdater()).start();
248     }
249     if (updateSelection)
250     {
251       (new SelectionUpdater()).start();
252     }
253     if (importNetwork)
254     {
255       (new NetworkUpdater(line)).start();
256     }
257     return;
258   }
259
260   /**
261    * Model updater thread
262    */
263   class ModelUpdater extends Thread
264   {
265
266     public ModelUpdater()
267     {
268     }
269
270     public void run()
271     {
272       structureManager.updateModels();
273       structureManager.modelChanged();
274     }
275   }
276
277   /**
278    * Selection updater thread
279    */
280   class SelectionUpdater extends Thread
281   {
282
283     public SelectionUpdater()
284     {
285     }
286
287     public void run()
288     {
289       try
290       {
291         logger.info("Responding to chimera selection");
292         structureManager.chimeraSelectionChanged();
293       } catch (Exception e)
294       {
295         logger.warn("Could not update selection", e);
296       }
297     }
298   }
299
300   /**
301    * Selection updater thread
302    */
303   class NetworkUpdater extends Thread
304   {
305
306     private String line;
307
308     public NetworkUpdater(String line)
309     {
310       this.line = line;
311     }
312
313     public void run()
314     {
315       try
316       {
317         // ((TaskManager<?, ?>) structureManager.getService(TaskManager.class))
318         // .execute(new ImportTrajectoryRINTaskFactory(structureManager, line)
319         // .createTaskIterator());
320       } catch (Exception e)
321       {
322         logger.warn("Could not import trajectory network", e);
323       }
324     }
325   }
326
327   /**
328    * Set a flag that this thread should clean up and exit.
329    */
330   public void requestStop()
331   {
332     this.stopMe = true;
333   }
334 }