--- /dev/null
+package jalview.ext.rbvi.chimera;
+
+import java.net.BindException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import jalview.httpserver.AbstractRequestHandler;
+import jalview.httpserver.HttpServer;
+import jalview.structure.SelectionSource;
+
+/**
+ * This is a simple Http handler that can listen for selections in Chimera.
+ * <p/>
+ * Lifecycle:
+ * <ul>
+ * <li>Start the Chimera process</li>
+ * <li>Start the REST service on Chimera, get the port number it is listening on
+ * </li>
+ * <li>Start the ChimeraListener, get the port number it is listening on</li>
+ * <li>Send a 'listen' command to Chimera with the URL of the listener</li>
+ * </ul>
+ *
+ * @author gmcarstairs
+ *
+ */
+public class ChimeraListener extends AbstractRequestHandler implements
+ SelectionSource
+{
+ /*
+ * A static counter so each listener can be associated with a distinct context
+ * root (/chimera0,1,2,3...). This is needed so we can fetch selections from
+ * multiple Chimera instances without confusion.
+ */
+ private static int chimeraId = 0;
+
+ /*
+ * Path below context root that identifies this handler
+ */
+ private static final String LISTENER_PATH = "chimera";
+
+ /*
+ * Value of chimeraId (0, 1, 2...) for this instance
+ */
+ private int myChimeraId = 0;
+
+ /*
+ * A reference to the object by which we can talk to Chimera
+ */
+ private JalviewChimeraBinding chimeraBinding;
+
+ /*
+ * The URI of this listener
+ */
+ private String uri;
+
+ /**
+ * Constructor that also registers this as an Http request handler on path
+ * /chimeraN, where N is incremented for each instance. Call getUri to get the
+ * resulting URI for this handler.
+ *
+ * @param chimeraBinding
+ * @throws BindException
+ * if no free port can be assigned
+ */
+ public ChimeraListener(JalviewChimeraBinding binding)
+ throws BindException
+ {
+ myChimeraId = chimeraId++;
+ this.chimeraBinding = binding;
+ final String path = LISTENER_PATH + myChimeraId;
+ this.uri = HttpServer.getInstance().registerHandler(path, this);
+ }
+
+ /**
+ * Returns the URI on which we are listening
+ *
+ * @return
+ */
+ public String getUri()
+ {
+ return this.uri;
+ }
+
+ /**
+ * Process a message from Chimera
+ */
+ @Override
+ protected void processRequest(HttpServletRequest request,
+ HttpServletResponse response)
+ {
+ // dumpRequest(request);
+ String message = request.getParameter("chimeraNotification");
+ if ("selection changed".equals(message))
+ {
+ this.chimeraBinding.highlightChimeraSelection();
+ }
+ else
+ {
+ System.err.println("Unexpected chimeraNotification: " + message);
+ // do it anyway for now!
+ this.chimeraBinding.highlightChimeraSelection();
+ }
+ }
+
+ /**
+ * Deregister this listener and close it down
+ *
+ * @throws Exception
+ */
+ public void shutdown()
+ {
+ try
+ {
+ HttpServer.getInstance().removeHandler(this);
+ stop();
+ } catch (Exception e)
+ {
+ System.err.println("Error stopping chimera listener: "
+ + e.getMessage());
+ }
+ }
+}