JAL-2422 basic proof of concept of ChimeraX opened/coloured by Jalview
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 13 Dec 2019 14:57:36 +0000 (14:57 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 13 Dec 2019 14:57:36 +0000 (14:57 +0000)
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/jalview/ext/rbvi/chimera/AtomSpecModel.java
src/jalview/ext/rbvi/chimera/ChimeraCommands.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/ws/HttpClientUtils.java
test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java

index a910a5a..a322f0b 100644 (file)
@@ -254,7 +254,7 @@ public class ChimeraManager
     for (ChimeraModel chimeraModel : modelList)
     {
       // get model color
-      Color modelColor = getModelColor(chimeraModel);
+      Color modelColor = isChimeraX() ? null : getModelColor(chimeraModel);
       if (modelColor != null)
       {
         chimeraModel.setModelColor(modelColor);
@@ -265,7 +265,7 @@ public class ChimeraManager
       // chimeraSend("repr stick "+newModel.toSpec());
 
       // Create the information we need for the navigator
-      if (type != ModelType.SMILES)
+      if (type != ModelType.SMILES && !isChimeraX())
       {
         addResidues(chimeraModel);
       }
@@ -473,17 +473,19 @@ public class ChimeraManager
   public List<ChimeraModel> getModelList()
   {
     List<ChimeraModel> modelList = new ArrayList<>();
-    List<String> list = sendChimeraCommand("list models type molecule",
-            true);
-    if (list != null)
-    {
-      for (String modelLine : list)
-      {
-        ChimeraModel chimeraModel = new ChimeraModel(modelLine);
-        modelList.add(chimeraModel);
-      }
-    }
-    return modelList;
+    modelList.add(new ChimeraModel("4zhp", ModelType.PDB_MODEL, 1, 0));
+    return modelList; // ChimeraX doesn't have 'list models' command
+    // List<String> list = sendChimeraCommand("list models type molecule",
+    // true);
+    // if (list != null)
+    // {
+    // for (String modelLine : list)
+    // {
+    // ChimeraModel chimeraModel = new ChimeraModel(modelLine);
+    // modelList.add(chimeraModel);
+    // }
+    // }
+    // return modelList;
   }
 
   /**
@@ -555,6 +557,7 @@ public class ChimeraManager
       {
         // ensure symbolic links are resolved
         chimeraPath = Paths.get(chimeraPath).toRealPath().toString();
+        isChimeraX = chimeraPath.toLowerCase().contains("chimerax");
         File path = new File(chimeraPath);
         // uncomment the next line to simulate Chimera not installed
         // path = new File(chimeraPath + "x");
@@ -567,8 +570,16 @@ public class ChimeraManager
         args.add(chimeraPath);
         // shows Chimera output window but suppresses REST responses:
         // args.add("--debug");
-        args.add("--start");
-        args.add("RESTServer");
+        if (isChimeraX())
+        {
+          args.add("--cmd");
+          args.add("remote rest start");
+        }
+        else
+        {
+          args.add("--start");
+          args.add("RESTServer");
+        }
         ProcessBuilder pb = new ProcessBuilder(args);
         chimera = pb.start();
         error = "";
@@ -616,15 +627,23 @@ public class ChimeraManager
       {
         responses.append("\n" + response);
         // expect: REST server on host 127.0.0.1 port port_number
+        // ChimeraX is the same except "REST server started on host..."
         if (response.startsWith("REST server"))
         {
           String[] tokens = response.split(" ");
-          if (tokens.length == 7 && "port".equals(tokens[5]))
+          for (int i = 0; i < tokens.length - 1; i++)
           {
-            port = Integer.parseInt(tokens[6]);
-            break;
+            if ("port".equals(tokens[i]))
+            {
+              port = Integer.parseInt(tokens[i + 1]);
+              break;
+            }
           }
         }
+        if (port > 0)
+        {
+          break; // hack for hanging readLine()
+        }
         response = lineReader.readLine();
       }
     } catch (Exception e)
@@ -762,6 +781,8 @@ public class ChimeraManager
 
   private volatile boolean busy = false;
 
+  private boolean isChimeraX;
+
   /**
    * Send a command to Chimera.
    * 
@@ -775,7 +796,7 @@ public class ChimeraManager
    */
   public List<String> sendChimeraCommand(String command, boolean reply)
   {
-   // System.out.println("chimeradebug>> " + command);
+    System.out.println("chimeradebug>> " + command);
     if (!isChimeraLaunched() || command == null
             || "".equals(command.trim()))
     {
@@ -822,14 +843,24 @@ public class ChimeraManager
   {
     String restUrl = "http://127.0.0.1:" + this.chimeraRestPort + "/run";
     List<NameValuePair> commands = new ArrayList<>(1);
-    commands.add(new BasicNameValuePair("command", command));
+    String encoded = command.replace(" ", "+").replace("#", "%23")
+            .replace("|", "%7C").replace(";", "%3B");
+    commands.add(new BasicNameValuePair("command", encoded));
 
     List<String> reply = new ArrayList<>();
     BufferedReader response = null;
     try
     {
-      response = HttpClientUtils.doHttpUrlPost(restUrl, commands, CONNECTION_TIMEOUT_MS,
-              REST_REPLY_TIMEOUT_MS);
+      if (isChimeraX())
+      {
+        response = HttpClientUtils.doHttpGet(restUrl, commands,
+                CONNECTION_TIMEOUT_MS, REST_REPLY_TIMEOUT_MS);
+      }
+      else
+      {
+        response = HttpClientUtils.doHttpUrlPost(restUrl, commands,
+                CONNECTION_TIMEOUT_MS, REST_REPLY_TIMEOUT_MS);
+      }
       String line = "";
       while ((line = response.readLine()) != null)
       {
@@ -901,4 +932,9 @@ public class ChimeraManager
   {
     return chimera;
   }
+
+  public boolean isChimeraX()
+  {
+    return isChimeraX;
+  }
 }
index 39d6704..a72844e 100644 (file)
@@ -58,7 +58,7 @@ public class AtomSpecModel
    */
   public AtomSpecModel()
   {
-    atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
+    atomSpec = new TreeMap<>();
   }
 
   /**
@@ -77,7 +77,7 @@ public class AtomSpecModel
     Map<String, List<int[]>> modelData = atomSpec.get(model);
     if (modelData == null)
     {
-      atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
+      atomSpec.put(model, modelData = new TreeMap<>());
     }
 
     /*
@@ -86,7 +86,7 @@ public class AtomSpecModel
     List<int[]> chainData = modelData.get(chain);
     if (chainData == null)
     {
-      chainData = new ArrayList<int[]>();
+      chainData = new ArrayList<>();
       modelData.put(chain, chainData);
     }
 
@@ -150,7 +150,8 @@ public class AtomSpecModel
             /*
              * we have a break so append the last range
              */
-            appendRange(sb, start, end, chain, firstPositionForModel);
+            appendRange(sb, start, end, chain, firstPositionForModel,
+                    false);
             firstPositionForModel = false;
             start = range[0];
             end = range[1];
@@ -162,7 +163,7 @@ public class AtomSpecModel
          */
         if (!rangeList.isEmpty())
         {
-          appendRange(sb, start, end, chain, firstPositionForModel);
+          appendRange(sb, start, end, chain, firstPositionForModel, false);
           firstPositionForModel = false;
         }
       }
@@ -178,7 +179,7 @@ public class AtomSpecModel
    * @param firstPositionForModel
    */
   protected void appendRange(StringBuilder sb, int start, int end,
-          String chain, boolean firstPositionForModel)
+          String chain, boolean firstPositionForModel, boolean isChimeraX)
   {
     if (!firstPositionForModel)
     {
@@ -193,9 +194,88 @@ public class AtomSpecModel
       sb.append(start).append("-").append(end);
     }
 
-    sb.append(".");
-    if (!" ".equals(chain)) {
-      sb.append(chain);
+    if (!isChimeraX)
+    {
+      sb.append(".");
+      if (!" ".equals(chain))
+      {
+        sb.append(chain);
+      }
     }
   }
+
+  /**
+   * Returns the range(s) formatted as a ChimeraX atomspec, for example
+   * <p>
+   * #1/A:2-20,30-40/B:10-20|#2/A:12-30
+   * 
+   * @return
+   */
+  public String getAtomSpecX()
+  {
+    StringBuilder sb = new StringBuilder(128);
+    boolean firstModel = true;
+    for (Integer model : atomSpec.keySet())
+    {
+      if (!firstModel)
+      {
+        sb.append("|");
+      }
+      firstModel = false;
+      sb.append("#").append(model);
+  
+      final Map<String, List<int[]>> modelData = atomSpec.get(model);
+  
+      for (String chain : modelData.keySet())
+      {
+        boolean firstPositionForChain = true;
+        chain = " ".equals(chain) ? chain : chain.trim();
+        sb.append("/").append(chain).append(":");
+        List<int[]> rangeList = modelData.get(chain);
+  
+        /*
+         * sort ranges into ascending start position order
+         */
+        Collections.sort(rangeList, IntRangeComparator.ASCENDING);
+  
+        int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+        int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+  
+        Iterator<int[]> iterator = rangeList.iterator();
+        while (iterator.hasNext())
+        {
+          int[] range = iterator.next();
+          if (range[0] <= end + 1)
+          {
+            /*
+             * range overlaps or is contiguous with the last one
+             * - so just extend the end position, and carry on
+             * (unless this is the last in the list)
+             */
+            end = Math.max(end, range[1]);
+          }
+          else
+          {
+            /*
+             * we have a break so append the last range
+             */
+            appendRange(sb, start, end, chain, firstPositionForChain, true);
+            start = range[0];
+            end = range[1];
+            firstPositionForChain = false;
+          }
+        }
+  
+        /*
+         * and append the last range
+         */
+        if (!rangeList.isEmpty())
+        {
+          appendRange(sb, start, end, chain, firstPositionForChain, true);
+        }
+        firstPositionForChain = false;
+      }
+    }
+    return sb.toString();
+  }
 }
index 3caaac3..01458a8 100644 (file)
@@ -64,17 +64,19 @@ public class ChimeraCommands
    * @param sr
    * @param fr
    * @param viewPanel
+   * @param isChimeraX
    * @return
    */
   public static StructureMappingcommandSet[] getColourBySequenceCommand(
           StructureSelectionManager ssm, String[] files,
           SequenceI[][] sequence, SequenceRenderer sr,
-          AlignmentViewPanel viewPanel)
+          AlignmentViewPanel viewPanel, boolean isChimeraX)
   {
     Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
-            sequence, sr, viewPanel);
+            sequence, sr, viewPanel, isChimeraX);
 
-    List<String> colourCommands = buildColourCommands(colourMap);
+    List<String> colourCommands = buildColourCommands(colourMap,
+            isChimeraX);
 
     StructureMappingcommandSet cs = new StructureMappingcommandSet(
             ChimeraCommands.class, null,
@@ -96,10 +98,11 @@ public class ChimeraCommands
    * </pre>
    * 
    * @param colourMap
+   * @param isChimeraX
    * @return
    */
   protected static List<String> buildColourCommands(
-          Map<Object, AtomSpecModel> colourMap)
+          Map<Object, AtomSpecModel> colourMap, boolean isChimeraX)
   {
     /*
      * This version concatenates all commands into a single String (semi-colon
@@ -117,10 +120,17 @@ public class ChimeraCommands
       {
         sb.append("; ");
       }
-      sb.append("color ").append(colourCode).append(" ");
+      sb.append("color ");
       firstColour = false;
       final AtomSpecModel colourData = colourMap.get(colour);
-      sb.append(colourData.getAtomSpec());
+      if (isChimeraX)
+      {
+        sb.append(colourData.getAtomSpecX()).append(" ").append(colourCode);
+      }
+      else
+      {
+        sb.append(colourCode).append(" ").append(colourData.getAtomSpec());
+      }
     }
     commands.add(sb.toString());
     return commands;
@@ -187,11 +197,19 @@ public class ChimeraCommands
    *             list of start/end ranges
    * Ordering is by order of addition (for colours and positions), natural ordering (for models and chains)
    * </pre>
+   * 
+   * @param ssm
+   * @param files
+   * @param sequence
+   * @param sr
+   * @param viewPanel
+   * @param isChimeraX
+   * @return
    */
   protected static Map<Object, AtomSpecModel> buildColoursMap(
           StructureSelectionManager ssm, String[] files,
           SequenceI[][] sequence, SequenceRenderer sr,
-          AlignmentViewPanel viewPanel)
+          AlignmentViewPanel viewPanel, boolean isChimeraX)
   {
     FeatureRenderer fr = viewPanel.getFeatureRenderer();
     FeatureColourFinder finder = new FeatureColourFinder(fr);
@@ -203,6 +221,7 @@ public class ChimeraCommands
 
     for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
     {
+      final int modelNumber = pdbfnum + (isChimeraX ? 1 : 0);
       StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
 
       if (mapping == null || mapping.length < 1)
@@ -259,8 +278,8 @@ public class ChimeraCommands
               {
                 if (startPos != -1)
                 {
-                  addAtomSpecRange(colourMap, lastColour, pdbfnum, startPos,
-                          lastPos, lastChain);
+                  addAtomSpecRange(colourMap, lastColour, modelNumber,
+                          startPos, lastPos, lastChain);
                 }
                 startPos = pos;
               }
@@ -271,7 +290,7 @@ public class ChimeraCommands
             // final colour range
             if (lastColour != null)
             {
-              addAtomSpecRange(colourMap, lastColour, pdbfnum, startPos,
+              addAtomSpecRange(colourMap, lastColour, modelNumber, startPos,
                       lastPos, lastChain);
             }
             // break;
@@ -316,23 +335,25 @@ public class ChimeraCommands
 
   /**
    * Constructs and returns Chimera commands to set attributes on residues
-   * corresponding to features in Jalview. Attribute names are the Jalview
-   * feature type, with a "jv_" prefix.
+   * corresponding to features in Jalview. Attribute names are the Jalview feature
+   * type, with a "jv_" prefix.
    * 
    * @param ssm
    * @param files
    * @param seqs
    * @param viewPanel
+   * @param isChimeraX
    * @return
    */
   public static StructureMappingcommandSet getSetAttributeCommandsForFeatures(
           StructureSelectionManager ssm, String[] files, SequenceI[][] seqs,
-          AlignmentViewPanel viewPanel)
+          AlignmentViewPanel viewPanel, boolean isChimeraX)
   {
     Map<String, Map<Object, AtomSpecModel>> featureMap = buildFeaturesMap(
             ssm, files, seqs, viewPanel);
 
-    List<String> commands = buildSetAttributeCommands(featureMap);
+    List<String> commands = buildSetAttributeCommands(featureMap,
+            isChimeraX);
 
     StructureMappingcommandSet cs = new StructureMappingcommandSet(
             ChimeraCommands.class, null,
@@ -579,10 +600,12 @@ public class ChimeraCommands
    * </pre>
    * 
    * @param featureMap
+   * @param isChimeraX
    * @return
    */
   protected static List<String> buildSetAttributeCommands(
-          Map<String, Map<Object, AtomSpecModel>> featureMap)
+          Map<String, Map<Object, AtomSpecModel>> featureMap,
+          boolean isChimeraX)
   {
     List<String> commands = new ArrayList<>();
     for (String featureType : featureMap.keySet())
@@ -608,7 +631,9 @@ public class ChimeraCommands
         featureValue = featureValue.replaceAll("\\'", "&#39;");
         sb.append("setattr r ").append(attributeName).append(" '")
                 .append(featureValue).append("' ");
-        sb.append(values.get(value).getAtomSpec());
+        AtomSpecModel atomSpecModel = values.get(value);
+        sb.append(isChimeraX ? atomSpecModel.getAtomSpecX()
+                : atomSpecModel.getAtomSpec());
         commands.add(sb.toString());
       }
     }
index 00446f2..47ada53 100644 (file)
@@ -76,9 +76,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   private static final String ALPHACARBON = "CA";
 
-  private List<String> chainNames = new ArrayList<String>();
+  private List<String> chainNames = new ArrayList<>();
 
-  private Hashtable<String, String> chainFile = new Hashtable<String, String>();
+  private Hashtable<String, String> chainFile = new Hashtable<>();
 
   /*
    * Object through which we talk to Chimera
@@ -106,7 +106,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   /*
    * Map of ChimeraModel objects keyed by PDB full local file name
    */
-  private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<String, List<ChimeraModel>>();
+  private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<>();
 
   String lastHighlightCommand;
 
@@ -122,8 +122,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   /**
    * Open a PDB structure file in Chimera and set up mappings from Jalview.
    * 
-   * We check if the PDB model id is already loaded in Chimera, if so don't
-   * reopen it. This is the case if Chimera has opened a saved session file.
+   * We check if the PDB model id is already loaded in Chimera, if so don't reopen
+   * it. This is the case if Chimera has opened a saved session file.
    * 
    * @param pe
    * @return
@@ -133,8 +133,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     String file = pe.getFile();
     try
     {
-      List<ChimeraModel> modelsToMap = new ArrayList<ChimeraModel>();
-      List<ChimeraModel> oldList = viewer.getModelList();
+      List<ChimeraModel> modelsToMap = new ArrayList<>();
+      List<ChimeraModel> oldList = viewer.isChimeraX() ? new ArrayList<>()
+              : viewer.getModelList();
       boolean alreadyOpen = false;
 
       /*
@@ -156,13 +157,32 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       if (!alreadyOpen)
       {
         viewer.openModel(file, pe.getId(), ModelType.PDB_MODEL);
-        List<ChimeraModel> newList = viewer.getModelList();
-        // JAL-1728 newList.removeAll(oldList) does not work
-        for (ChimeraModel cm : newList)
+        if (viewer.isChimeraX())
         {
-          if (cm.getModelName().equals(pe.getId()))
+          /*
+           * ChimeraX hack: force chimera model name to pdbId
+           */
+          int modelNumber = chimeraMaps.size() + 1;
+          String command = "setattr #" + modelNumber + " models name "
+                  + pe.getId();
+          sendChimeraCommand(command, false);
+          modelsToMap.add(new ChimeraModel(pe.getId(), ModelType.PDB_MODEL,
+                  modelNumber, 0));
+        }
+        else
+        {
+          /*
+           * Chimera: query for actual models and find the one with
+           * matching model name - set in viewer.openModel()
+           */
+          List<ChimeraModel> newList = viewer.getModelList();
+          // JAL-1728 newList.removeAll(oldList) does not work
+          for (ChimeraModel cm : newList)
           {
-            modelsToMap.add(cm);
+            if (cm.getModelName().equals(pe.getId()))
+            {
+              modelsToMap.add(cm);
+            }
           }
         }
       }
@@ -200,9 +220,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * Starts a thread that waits for the Chimera process to finish, so that we
-   * can then close the associated resources. This avoids leaving orphaned
-   * Chimera viewer panels in Jalview if the user closes Chimera.
+   * Starts a thread that waits for the Chimera process to finish, so that we can
+   * then close the associated resources. This avoids leaving orphaned Chimera
+   * viewer panels in Jalview if the user closes Chimera.
    */
   protected void startChimeraProcessMonitor()
   {
@@ -231,8 +251,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * Start a dedicated HttpServer to listen for Chimera notifications, and tell
-   * it to start listening
+   * Start a dedicated HttpServer to listen for Chimera notifications, and tell it
+   * to start listening
    */
   public void startChimeraListener()
   {
@@ -699,7 +719,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel)
   {
     return ChimeraCommands.getColourBySequenceCommand(getSsm(), files,
-            getSequence(), sr, viewPanel);
+            getSequence(), sr, viewPanel, viewer.isChimeraX());
   }
 
   /**
@@ -757,9 +777,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * Construct and send a command to highlight zero, one or more atoms. We do
-   * this by sending an "rlabel" command to show the residue label at that
-   * position.
+   * Construct and send a command to highlight zero, one or more atoms. We do this
+   * by sending an "rlabel" command to show the residue label at that position.
    */
   @Override
   public void highlightAtoms(List<AtomSpec> atoms)
@@ -857,7 +876,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   protected List<AtomSpec> convertStructureResiduesToAlignment(
           List<String> structureSelection)
   {
-    List<AtomSpec> atomSpecs = new ArrayList<AtomSpec>();
+    List<AtomSpec> atomSpecs = new ArrayList<>();
     for (String atomSpec : structureSelection)
     {
       try
@@ -1110,7 +1129,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
     StructureMappingcommandSet commandSet = ChimeraCommands
             .getSetAttributeCommandsForFeatures(getSsm(), files,
-                    getSequence(), avp);
+                    getSequence(), avp, viewer.isChimeraX());
     String[] commands = commandSet.commands;
     if (commands.length > 10)
     {
@@ -1127,9 +1146,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * Write commands to a temporary file, and send a command to Chimera to open
-   * the file as a commands script. For use when sending a large number of
-   * separate commands would overload the REST interface mechanism.
+   * Write commands to a temporary file, and send a command to Chimera to open the
+   * file as a commands script. For use when sending a large number of separate
+   * commands would overload the REST interface mechanism.
    * 
    * @param commands
    */
index b19d606..8f97226 100644 (file)
@@ -34,6 +34,7 @@ import org.apache.http.NameValuePair;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntity;
@@ -167,4 +168,65 @@ public class HttpClientUtils
       return null;
     }
   }
+
+  /**
+   * do an HTTP GET with URL-Encoded parameters passed in the Query string
+   * 
+   * @param url
+   * @param vals
+   * @return Reader containing content, if any, or null if no entity returned.
+   * @throws IOException
+   * @throws ClientProtocolException
+   * @throws Exception
+   */
+  public static BufferedReader doHttpGet(String url,
+          List<NameValuePair> vals, int connectionTimeoutMs,
+          int readTimeoutMs) throws ClientProtocolException, IOException
+  {
+    // todo use HttpClient 4.3 or later and class RequestConfig
+    HttpParams params = new BasicHttpParams();
+    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
+            HttpVersion.HTTP_1_1);
+    if (connectionTimeoutMs > 0)
+    {
+      HttpConnectionParams.setConnectionTimeout(params,
+              connectionTimeoutMs);
+    }
+    if (readTimeoutMs > 0)
+    {
+      HttpConnectionParams.setSoTimeout(params, readTimeoutMs);
+    }
+    boolean first = true;
+    for (NameValuePair param : vals)
+    {
+      if (first)
+      {
+        url += "?";
+      }
+      else
+      {
+        url += "&";
+      }
+      url += param.getName();
+      url += "=";
+      url += param.getValue();
+    }
+    HttpClient httpclient = new DefaultHttpClient(params);
+    HttpGet httpGet = new HttpGet(url);
+    // UrlEncodedFormEntity ue = new UrlEncodedFormEntity(vals, "UTF-8");
+    // httpGet.setEntity(ue);
+    HttpResponse response = httpclient.execute(httpGet);
+    HttpEntity resEntity = response.getEntity();
+  
+    if (resEntity != null)
+    {
+      BufferedReader r = new BufferedReader(
+              new InputStreamReader(resEntity.getContent()));
+      return r;
+    }
+    else
+    {
+      return null;
+    }
+  }
 }
index 06a09df..8e68d86 100644 (file)
@@ -59,7 +59,7 @@ public class ChimeraCommandsTest
   public void testBuildColourCommands()
   {
 
-    Map<Object, AtomSpecModel> map = new LinkedHashMap<Object, AtomSpecModel>();
+    Map<Object, AtomSpecModel> map = new LinkedHashMap<>();
     ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 2, 5, "A");
     ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 7, 7, "B");
     ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 9, 23, "A");
@@ -72,7 +72,7 @@ public class ChimeraCommandsTest
 
     // Colours should appear in the Chimera command in the order in which
     // they were added; within colour, by model, by chain, ranges in start order
-    String command = ChimeraCommands.buildColourCommands(map).get(0);
+    String command = ChimeraCommands.buildColourCommands(map, false).get(0);
     assertEquals(
             command,
             "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:3-5.A,8.A; color #ff0000 #0:3-9.A");
@@ -84,8 +84,8 @@ public class ChimeraCommandsTest
     /*
      * make a map of { featureType, {featureValue, {residue range specification } } }
      */
-    Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<String, Map<Object, AtomSpecModel>>();
-    Map<Object, AtomSpecModel> featureValues = new HashMap<Object, AtomSpecModel>();
+    Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<>();
+    Map<Object, AtomSpecModel> featureValues = new HashMap<>();
     
     /*
      * start with just one feature/value...
@@ -94,7 +94,7 @@ public class ChimeraCommandsTest
     ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 8, 20, "A");
   
     List<String> commands = ChimeraCommands
-            .buildSetAttributeCommands(featuresMap);
+            .buildSetAttributeCommands(featuresMap, false);
     assertEquals(1, commands.size());
 
     /*
@@ -107,7 +107,8 @@ public class ChimeraCommandsTest
     ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 3, 9, "A");
     // same feature value, contiguous range
     ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "A");
-    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+            false);
     assertEquals(1, commands.size());
     assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:3-25.A");
 
@@ -115,14 +116,16 @@ public class ChimeraCommandsTest
     ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "B");
     // same feature value and chain, different model
     ChimeraCommands.addAtomSpecRange(featureValues, "X", 1, 26, 30, "A");
-    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+            false);
     assertEquals(1, commands.size());
     assertEquals(commands.get(0),
             "setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A");
 
     // same feature, different value
     ChimeraCommands.addAtomSpecRange(featureValues, "Y", 0, 40, 50, "A");
-    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+            false);
     assertEquals(2, commands.size());
     // commands are ordered by feature type but not by value
     // so use contains to test for the expected command:
@@ -138,7 +141,8 @@ public class ChimeraCommandsTest
             "A");
     // feature names are sanitised to change non-alphanumeric to underscore
     // feature values are sanitised to encode single quote characters
-    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+    commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+            false);
     assertTrue(commands
             .contains("setattr r jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> &#39;ion!' #0:7-15.A"));
   }
@@ -189,7 +193,7 @@ public class ChimeraCommandsTest
     /*
      * map residues 1-10 to residues 21-30 (atoms 105-150) in structures
      */
-    HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
+    HashMap<Integer, int[]> map = new HashMap<>();
     for (int pos = 1; pos <= seq1.getLength(); pos++)
     {
       map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
@@ -202,7 +206,8 @@ public class ChimeraCommandsTest
     ssm.addStructureMapping(sm2);
 
     StructureMappingcommandSet[] commands = ChimeraCommands
-            .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
+            .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel,
+                    false);
     assertEquals(1, commands.length);
     assertEquals(1, commands[0].commands.length);
     String theCommand = commands[0].commands[0];