40b0ff0b2c86bcb4682e8c7008c8e695dc2c88f3
[jalview.git] / src / jalview / ext / rbvi / chimera / ChimeraListener.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ext.rbvi.chimera;
22
23 import jalview.httpserver.AbstractRequestHandler;
24 import jalview.structure.SelectionSource;
25
26 import java.net.BindException;
27
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 /**
32  * This is a simple Http handler that can listen for selections in Chimera.
33  * <p/>
34  * Lifecycle:
35  * <ul>
36  * <li>Start the Chimera process</li>
37  * <li>Start the REST service on Chimera, get the port number it is listening on
38  * </li>
39  * <li>Start the ChimeraListener, get the URL it is listening on</li>
40  * <li>The first listener started will start the singleton HttpServer</li>
41  * <li>Send a 'listen' command to Chimera with the URL of the listener</li>
42  * <li>When Jalview's Chimera window is closed, shut down the
43  * ChimeraListener</li>
44  * <li>Multiple linked Chimera instances will each have a separate listener (but
45  * share one Http server)</li>
46  * </ul>
47  * 
48  * @author gmcarstairs
49  *
50  */
51 public class ChimeraListener extends AbstractRequestHandler
52         implements SelectionSource
53 {
54   /*
55    * Chimera notification parameter name
56    */
57   private static final String CHIMERA_NOTIFICATION = "chimeraNotification";
58
59   /*
60    * Chimera model changed notifications start with this
61    */
62   private static final String MODEL_CHANGED = "ModelChanged: ";
63
64   /*
65    * Chimera selection changed notification message
66    */
67   private static final String SELECTION_CHANGED = "SelectionChanged: selection changed\n";
68
69   /*
70    * A static counter so each listener can be associated with a distinct context
71    * root (/chimera0,1,2,3...). This is needed so we can fetch selections from
72    * multiple Chimera instances without confusion.
73    */
74   private static int chimeraId = 0;
75
76   /*
77    * Prefix for path below context root (myChimeraId is appended)
78    */
79   private static final String PATH_PREFIX = "chimera";
80
81   /*
82    * Value of chimeraId (0, 1, 2...) for this instance
83    */
84   private int myChimeraId = 0;
85
86   /*
87    * A reference to the object by which we can talk to Chimera
88    */
89   private JalviewChimeraBinding chimeraBinding;
90
91   /**
92    * Constructor that registers this as an Http request handler on path
93    * /chimeraN, where N is incremented for each instance. Call getUri to get the
94    * resulting URI for this handler.
95    * 
96    * @param chimeraBinding
97    * @throws BindException
98    *           if no free port can be assigned
99    */
100   public ChimeraListener(JalviewChimeraBinding binding) throws BindException
101   {
102     myChimeraId = chimeraId++;
103     this.chimeraBinding = binding;
104     setPath(PATH_PREFIX + myChimeraId);
105     registerHandler();
106   }
107
108   /**
109    * Process a message from Chimera
110    */
111   @Override
112   protected void processRequest(HttpServletRequest request,
113           HttpServletResponse response)
114   {
115     // dumpRequest(request);
116     String message = request.getParameter(CHIMERA_NOTIFICATION);
117     if (message == null)
118     {
119       message = request.getParameter("chimerax_notification");
120     }
121     if (message != null)
122     {
123       if (message.startsWith("SelectionChanged"))
124       {
125         this.chimeraBinding.highlightChimeraSelection();
126       }
127       else if (message.startsWith(MODEL_CHANGED))
128       {
129         System.err.println(message);
130         processModelChanged(message.substring(MODEL_CHANGED.length()));
131       }
132       else
133       {
134         System.err.println("Unexpected chimeraNotification: " + message);
135       }
136     }
137   }
138
139   /**
140    * Handle a ModelChanged notification from Chimera
141    * 
142    * @param substring
143    */
144   protected void processModelChanged(String message)
145   {
146     // System.out.println(message + " (not implemented in Jalview)");
147   }
148
149   /**
150    * Returns a display name for this service
151    */
152   @Override
153   public String getName()
154   {
155     return "ChimeraListener";
156   }
157 }