more fixes and extension to allow return data types to be specified JAL-715
authorjprocter <Jim Procter>
Tue, 14 Dec 2010 18:02:26 +0000 (18:02 +0000)
committerjprocter <Jim Procter>
Tue, 14 Dec 2010 18:02:26 +0000 (18:02 +0000)
src/jalview/ws/rest/HttpResultSet.java
src/jalview/ws/rest/InputType.java
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestJob.java
src/jalview/ws/rest/RestJobThread.java
src/jalview/ws/rest/RestServiceDescription.java
src/jalview/ws/rest/params/Alignment.java

index b99d538..5a70211 100644 (file)
@@ -2,12 +2,18 @@ package jalview.ws.rest;
 
 import jalview.bin.Cache;
 import jalview.io.FileParse;
+import jalview.io.packed.DataProvider;
+import jalview.io.packed.ParsePackedSet;
+import jalview.io.packed.SimpleDataProvider;
+import jalview.io.packed.DataProvider.JvDataType;
 import jalview.ws.io.mime.JalviewMimeContentHandler;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
@@ -55,17 +61,40 @@ public class HttpResultSet extends FileParse
     initDataSource(con);
   }
 
-  private void initDataSource(HttpResponse con) throws IOException
+  /**
+   * construct a set of dataproviders to parse a result set from this service
+   * 
+   * @param resSet
+   * @return
+   */
+  public List<DataProvider> createResultDataProviders()
   {
-    en = con.getEntity();
-    repeatable = en.isRepeatable();
+    List<DataProvider> dp = new ArrayList<DataProvider>();
+    for (JvDataType type : restJob.rsd.getResultDataTypes())
+    {
+      dp.add(new SimpleDataProvider(type, this, null));
+    }
+    return dp;
+  }
+
+  public Object[] parseResultSet() throws Exception, Error
+  {
+    List<DataProvider> dp = new ArrayList<DataProvider>();
+    Object[] results = null;
 
+    if (en == null)
+    {
+      throw new Error(
+              "Implementation Error: need to have an HttpResponse to process.");
+    }
+    jalview.io.packed.JalviewDataset ds = restJob.newJalviewDataset();
+    // Decide how we deal with content.
     if (en instanceof MultipartEntity)
     {
+      // Multipart messages should be properly typed, so we parse them as we go.
       MultipartEntity mpe = (MultipartEntity) en;
       // multipart
-      jalview.io.packed.JalviewDataset ds = restJob.newJalviewDataset();
-      ContentHandler handler = new JalviewMimeContentHandler(ds);
+      JalviewMimeContentHandler handler = new JalviewMimeContentHandler(ds);
       MimeStreamParser parser = new MimeStreamParser();
       parser.setContentHandler(handler);
       try
@@ -78,15 +107,35 @@ public class HttpResultSet extends FileParse
         Cache.log.warn("Failed to parse MIME multipart content", me);
         en.consumeContent();
       }
+      return new ParsePackedSet().getAlignment(ds,
+              handler.getJalviewDataProviders());
     }
     else
     {
+      // Need to use hints from rest service description.
+      dp = createResultDataProviders();
+      ParsePackedSet pps = new ParsePackedSet();
+      return pps.getAlignment(ds, dp);
+    }
+  }
+
+  private void initDataSource(HttpResponse con) throws IOException
+  {
+    en = con.getEntity();
+    repeatable = en.isRepeatable();
+
+    if (!(en instanceof MultipartEntity))
+    {
       // assume content is simple text stream that can be read from
-      String enc = (en.getContentEncoding()==null) ? null : en.getContentEncoding().getValue();
-      if (en.getContentType()!=null) {
-        Cache.log.info("Result Type: " + en.getContentType().toString());
-      } else {
-        Cache.log.info("No Result Type Specified.");
+      String enc = (en.getContentEncoding() == null) ? null : en
+              .getContentEncoding().getValue();
+      if (en.getContentType() != null)
+      {
+        Cache.log.debug("Result Type: " + en.getContentType().toString());
+      }
+      else
+      {
+        Cache.log.debug("No Result Type Specified.");
       }
       if (enc == null || enc.length() < 1)
       {
@@ -94,7 +143,7 @@ public class HttpResultSet extends FileParse
       }
       else
       {
-        Cache.log.debug("Result Encoded as : "+enc);
+        Cache.log.debug("Result Encoded as : " + enc);
       }
       // attempt to identify file and construct an appropriate DataSource
       // identifier for it.
@@ -118,7 +167,7 @@ public class HttpResultSet extends FileParse
       if (br != null)
       {
         dataIn = new BufferedReader(br);
-        error=false;
+        error = false;
       }
     }
   }
index 77583b7..9a4f297 100644 (file)
@@ -15,8 +15,12 @@ import org.apache.http.entity.mime.content.StringBody;
 import sun.io.CharacterEncoding;
 import sun.misc.CharacterEncoder;
 
-/** Service Input info { a sequence of [ Sequence Id vector (min,max,moltype, separator,regex,colrange(start-end)), Sequence(format-bare or alignment, moltype, min, max, separator)), Alignment(format, moltype),
- */ 
+/***
+ * InputType is the abstract model of each input parameter that a rest service might take.
+ * It enables the engine to validate input by providing 
+ * { formatter for type, parser for type }
+ *  
+ */
 public abstract class InputType {
   /**
    * not used yet
index 5a4cf61..04c9561 100644 (file)
@@ -20,8 +20,10 @@ import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceGroup;
 import jalview.gui.AlignFrame;
 import jalview.gui.AlignViewport;
+import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.WebserviceInfo;
+import jalview.io.packed.DataProvider.JvDataType;
 import jalview.ws.WSClient;
 import jalview.ws.WSClientI;
 import jalview.ws.WSMenuEntryProviderI;
@@ -82,6 +84,7 @@ public class RestClient extends WSClient implements WSClientI,
     {
       wsInfo = new WebserviceInfo(WebServiceJobTitle, WebServiceName + "\n"
               + WebServiceReference);
+      wsInfo.setRenderAsHtml(true);
     }
 
   }
@@ -266,6 +269,7 @@ public class RestClient extends WSClient implements WSClientI,
     }
     else
     {
+      // TODO: try to tell the user why the job couldn't be started.
       JOptionPane.showMessageDialog(Desktop.desktop,
               "Unable to start web service analysis",
               "Internal Jalview Error", JOptionPane.WARNING_MESSAGE);
@@ -302,7 +306,28 @@ public class RestClient extends WSClient implements WSClientI,
             name,
             "http://www.ibi.vu.nl/programs/shmrwww/index.php?tool=jalview",// ?tool=jalview&mbjob[method]=shmr&mbjob[description]=step1",
             "?tool=jalview", iparams, true, false, '-');
+    // a priori knowledge of the data returned from the service
+    shmrService.addResultDatatype(JvDataType.ANNOTATION);
     return new RestClient(shmrService);
   }
 
+  public AlignmentPanel recoverAlignPanelForView()
+  {
+    AlignmentPanel[] aps = Desktop.getAlignmentPanels(av.getSequenceSetId());
+    for (AlignmentPanel alp:aps)
+    {
+      if (alp.av == av)
+      {
+        return alp;
+      }
+    }
+    return null;
+  }
+
+  public boolean isShowResultsInNewView()
+  {
+    // TODO make this a property of the service
+    return true;
+  }
+
 }
index c7df482..80f4ac6 100644 (file)
 package jalview.ws.rest;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.Vector;
 
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.io.packed.DataProvider;
 import jalview.io.packed.JalviewDataset;
+import jalview.io.packed.ParsePackedSet;
+import jalview.io.packed.SimpleDataProvider;
+import jalview.io.packed.DataProvider.JvDataType;
 import jalview.ws.AWsJob;
 import jalview.ws.rest.params.Alignment;
 import jalview.ws.rest.params.SeqGroupIndexVector;
 
 public class RestJob extends AWsJob
 {
-  
+
   // TODO: input alignmentview and other data for this job
   RestServiceDescription rsd;
+
   // boolean submitted;
   boolean gotresponse;
+
   boolean error;
+
   boolean waiting;
+
   boolean gotresult;
+
   Hashtable squniq;
-  
+
+  /**
+   * dataset associated with this input data.
+   */
+  AlignmentI dsForIO;
+
+  AlignmentOrder inputOrder;
+
+  /**
+   * context of input data with respect to an AlignmentView's visible contigs.
+   */
+  int[] origviscontig;
+
+  private AlignmentI contextAl=null;
+
   /**
-   * create a rest job using data bounded by the given start/end column. 
+   * create a rest job using data bounded by the given start/end column.
+   * 
    * @param addJobPane
    * @param restJobThread
    * @param _input
+   * @param viscontigs
+   *          visible contigs of an alignment view from which _input was derived
    */
   public RestJob(int jobNum, RestJobThread restJobThread,
-          AlignmentI _input)
+          AlignmentI _input, int[] viscontigs)
   {
     rsd = restJobThread.restClient.service;
     jobnum = jobNum;
+    if (viscontigs != null)
+    {
+      origviscontig = new int[viscontigs.length];
+      System.arraycopy(viscontigs, 0, origviscontig, 0, viscontigs.length);
+    }
     // get sequences for the alignmentI
     // get groups trimmed to alignment columns
     // get any annotation trimmed to start/end columns, too.
-    
+
     // prepare input
-    // form alignment+groups+annotation,preprocess and then record references for formatters
+    // form alignment+groups+annotation,preprocess and then record references
+    // for formatters
     ArrayList<InputType> alinp = new ArrayList<InputType>();
-    int paramsWithData=0;
-    // we cheat for moment - since we know a-priori what data is available and what inputs we have implemented so far
-    for (Map.Entry<String,InputType>prm: rsd.inputParams.entrySet())
+    int paramsWithData = 0;
+    // we cheat for moment - since we know a-priori what data is available and
+    // what inputs we have implemented so far
+    for (Map.Entry<String, InputType> prm : rsd.inputParams.entrySet())
     {
       if (!prm.getValue().isConstant())
       {
         if (prm.getValue() instanceof Alignment)
-      {
-        alinp.add(prm.getValue());
-      } else
-      {
-        if ((prm.getValue() instanceof SeqGroupIndexVector)
-              &&(_input.getGroups()!=null && _input.getGroups().size()>0))
         {
           alinp.add(prm.getValue());
         }
-      } 
-      } else {
+        else
+        {
+          if ((prm.getValue() instanceof SeqGroupIndexVector)
+                  && (_input.getGroups() != null && _input.getGroups()
+                          .size() > 0))
+          {
+            alinp.add(prm.getValue());
+          }
+        }
+      }
+      else
+      {
         paramsWithData++;
       }
     }
-    if ((paramsWithData+alinp.size())==rsd.inputParams.size())
+    if ((paramsWithData + alinp.size()) == rsd.inputParams.size())
     {
+      inputOrder = new AlignmentOrder(_input);
+      if ((dsForIO = _input.getDataset()) == null)
+      {
+        _input.setDataset(null);
+      }
+      dsForIO = _input.getDataset();
+      if (contextAl==null)
+      {
+        contextAl = _input;
+      }
       setAlignmentForInputs(alinp, _input);
-      validInput=true;
-    } else {
+      validInput = true;
+    }
+    else
+    {
       // not enough data, so we bail.
-      validInput=false;
+      validInput = false;
     }
   }
-  boolean validInput=false;
+
+  boolean validInput = false;
+
   @Override
   public boolean hasResults()
   {
@@ -93,7 +147,8 @@ public class RestJob extends AWsJob
   @Override
   public boolean isRunning()
   {
-    return running; // TODO: can we check the response body for status messages ?
+    return running; // TODO: can we check the response body for status messages
+                    // ?
   }
 
   @Override
@@ -105,7 +160,7 @@ public class RestJob extends AWsJob
   @Override
   public boolean isFinished()
   {
-    return resSet!=null;
+    return resSet != null;
   }
 
   @Override
@@ -136,6 +191,7 @@ public class RestJob extends AWsJob
   }
 
   protected String statMessage = null;
+
   public HttpResultSet resSet;
 
   @Override
@@ -147,34 +203,37 @@ public class RestJob extends AWsJob
   @Override
   public boolean hasResponse()
   {
-    return statMessage!=null || resSet!=null;
+    return statMessage != null || resSet != null;
   }
 
   @Override
   public void clearResponse()
   {
-    // only clear the transient server response 
+    // only clear the transient server response
     // statMessage=null;
   }
 
-  /* (non-Javadoc)
+  /*
+   * (non-Javadoc)
+   * 
    * @see jalview.ws.AWsJob#getState()
    */
   @Override
   public String getState()
   {
-    // TODO generate state string - prolly should have a default abstract method for this
+    // TODO generate state string - prolly should have a default abstract method
+    // for this
     return "Job is clueless";
   }
 
   public String getPostUrl()
   {
-    
+
     // TODO Auto-generated method stub
     return rsd.postUrl;
   }
 
-  public Set<Map.Entry<String,InputType>> getInputParams()
+  public Set<Map.Entry<String, InputType>> getInputParams()
   {
     return rsd.inputParams.entrySet();
   }
@@ -187,30 +246,40 @@ public class RestJob extends AWsJob
 
   /**
    * 
-   * @return new context for parsing results from service
+   * @return the context for parsing results from service
    */
   public JalviewDataset newJalviewDataset()
   {
-    /*
-     * TODO: initialise dataset with correct input context 
-     */
-    JalviewDataset njd = new JalviewDataset();
-    return njd;
+    if (context == null)
+    {
+      context = new JalviewDataset(dsForIO, null, squniq, null);
+      if (contextAl!=null)
+      {
+        context.addAlignment(contextAl);
+      }
+      
+    }
+    return context;
   }
 
   /**
-   * Extract list of sequence IDs for input parameter 'token' with given molecule type
+   * Extract list of sequence IDs for input parameter 'token' with given
+   * molecule type
+   * 
    * @param token
    * @param type
    * @return
    */
-  public SequenceI[] getSequencesForInput(String token, InputType.molType type) throws NoValidInputDataException
+  public SequenceI[] getSequencesForInput(String token,
+          InputType.molType type) throws NoValidInputDataException
   {
     Object sgdat = inputData.get(token);
     // can we form an alignment from this data ?
-    if (sgdat==null)
+    if (sgdat == null)
     {
-      throw new NoValidInputDataException("No Sequence vector data bound to input '"+token+"' for service at "+rsd.postUrl);
+      throw new NoValidInputDataException(
+              "No Sequence vector data bound to input '" + token
+                      + "' for service at " + rsd.postUrl);
     }
     if (sgdat instanceof AlignmentI)
     {
@@ -218,49 +287,61 @@ public class RestJob extends AWsJob
     }
     if (sgdat instanceof SequenceGroup)
     {
-      return ((SequenceGroup)sgdat).getSequencesAsArray(null);
+      return ((SequenceGroup) sgdat).getSequencesAsArray(null);
     }
     if (sgdat instanceof Vector)
     {
-      if (((Vector)sgdat).size()>0 && ((Vector)sgdat).get(0) instanceof SequenceI)
+      if (((Vector) sgdat).size() > 0
+              && ((Vector) sgdat).get(0) instanceof SequenceI)
       {
-        SequenceI[] sq = new SequenceI[((Vector)sgdat).size()];
-        ((Vector)sgdat).copyInto(sq);
+        SequenceI[] sq = new SequenceI[((Vector) sgdat).size()];
+        ((Vector) sgdat).copyInto(sq);
         return sq;
       }
     }
-    throw new NoValidInputDataException("No Sequence vector data bound to input '"+token+"' for service at "+rsd.postUrl);
+    throw new NoValidInputDataException(
+            "No Sequence vector data bound to input '" + token
+                    + "' for service at " + rsd.postUrl);
   }
+
   /**
-   * binding between input data (AlignmentI, SequenceGroup, NJTree) and input param names.
+   * binding between input data (AlignmentI, SequenceGroup, NJTree) and input
+   * param names.
    */
-  private Hashtable<String,Object> inputData=new Hashtable<String,Object>();
+  private Hashtable<String, Object> inputData = new Hashtable<String, Object>();
+
   /**
    * is the job fully submitted to server and apparently in progress ?
    */
-  public boolean running=false;
+  public boolean running = false;
+
   /**
    * 
    * @param itypes
-   * @param al - reference to object to be stored as input. Note - input data may be modifed by formatter
+   * @param al
+   *          - reference to object to be stored as input. Note - input data may
+   *          be modifed by formatter
    */
-  public void setAlignmentForInputs(Collection<InputType> itypes, AlignmentI al)
+  public void setAlignmentForInputs(Collection<InputType> itypes,
+          AlignmentI al)
   {
-    for (InputType itype: itypes) {
+    for (InputType itype : itypes)
+    {
       if (!rsd.inputParams.values().contains(itype))
       {
-        throw new IllegalArgumentException("InputType "+itype.getClass()+
-                " is not valid for service at "+rsd.postUrl);
+        throw new IllegalArgumentException("InputType " + itype.getClass()
+                + " is not valid for service at " + rsd.postUrl);
       }
       if (itype instanceof AlignmentProcessor)
       {
-        ((AlignmentProcessor)itype).prepareAlignment(al);
+        ((AlignmentProcessor) itype).prepareAlignment(al);
       }
       // stash a reference for recall when the alignment data is formatted
       inputData.put(itype.token, al);
     }
-    
+
   }
+
   /**
    * 
    * @param token
@@ -268,30 +349,51 @@ public class RestJob extends AWsJob
    * @return alignment object bound to the given token
    * @throws NoValidInputDataException
    */
-  public AlignmentI getAlignmentForInput(String token, InputType.molType type) throws NoValidInputDataException
+  public AlignmentI getAlignmentForInput(String token,
+          InputType.molType type) throws NoValidInputDataException
   {
     Object al = inputData.get(token);
     // can we form an alignment from this data ?
-    if (al==null || !(al instanceof AlignmentI))
+    if (al == null || !(al instanceof AlignmentI))
     {
-      throw new NoValidInputDataException("No alignment data bound to input '"+token+"' for service at "+rsd.postUrl);
+      throw new NoValidInputDataException(
+              "No alignment data bound to input '" + token
+                      + "' for service at " + rsd.postUrl);
     }
     return (AlignmentI) al;
   }
 
   /**
    * test to see if the job has data of type cl that's needed for the job to run
+   * 
    * @param cl
    * @return true or false
    */
   public boolean hasDataOfType(Class cl)
   {
-    if (AlignmentI.class.isAssignableFrom(cl)) {
+    if (AlignmentI.class.isAssignableFrom(cl))
+    {
       return true;
     }
-    // TODO: add more source data types 
+    // TODO: add more source data types
+
     return false;
   }
 
+  /**
+   * context used to parse results from service
+   */
+  JalviewDataset context = null;
+
+  Object[] jvresultobj = null;
+
+  /**
+   * process the results obtained from the server into jalview datamodel objects
+   * ready to be merged/added to the users' view.
+   */
+  public void parseResultSet() throws Exception, Error
+  {
+    jvresultobj = resSet.parseResultSet();
+  }
+
 }
index bd71813..67ccd3a 100644 (file)
@@ -2,6 +2,8 @@ package jalview.ws.rest;
 
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.gui.AlignFrame;
 import jalview.gui.WebserviceInfo;
 import jalview.io.packed.DataProvider;
 import jalview.io.packed.JalviewDataset;
@@ -11,6 +13,7 @@ import jalview.io.packed.DataProvider.JvDataType;
 import jalview.ws.AWSThread;
 import jalview.ws.AWsJob;
 
+import java.awt.Desktop;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.IOException;
@@ -60,13 +63,15 @@ public class RestJobThread extends AWSThread
       jobs = new RestJob[1];
       jobs[0] = new RestJob(0, this,
               restClient._input.getVisibleAlignment(restClient.service
-                      .getGapCharacter()));
+                      .getGapCharacter()),
+              restClient._input.getVisibleContigs());
       // need a function to get a range on a view/alignment and return both
       // annotation, groups and selection subsetted to just that region.
 
     }
     else
     {
+      int[] viscontig = restClient._input.getVisibleContigs();
       AlignmentI[] viscontigals = restClient._input
               .getVisibleContigAlignments(restClient.service
                       .getGapCharacter());
@@ -75,13 +80,15 @@ public class RestJobThread extends AWSThread
         jobs = new RestJob[viscontigals.length];
         for (int j = 0; j < jobs.length; j++)
         {
+          int[] visc = new int[]
+          { viscontig[j * 2], viscontig[j * 2 + 1] };
           if (j != 0)
           {
-            jobs[j] = new RestJob(j, this, viscontigals[j]);
+            jobs[j] = new RestJob(j, this, viscontigals[j], visc);
           }
           else
           {
-            jobs[j] = new RestJob(0, this, viscontigals[j]);
+            jobs[j] = new RestJob(0, this, viscontigals[j], visc);
           }
         }
       }
@@ -178,7 +185,8 @@ public class RestJobThread extends AWSThread
           throws Exception
   {
     StringBuffer respText = new StringBuffer();
-    // con.setContentHandlerFactory(new jalview.ws.io.mime.HttpContentHandler());
+    // con.setContentHandlerFactory(new
+    // jalview.ws.io.mime.HttpContentHandler());
     HttpRequestBase request = null;
     String messages = "";
     if (stg == Stage.SUBMIT)
@@ -244,8 +252,12 @@ public class RestJobThread extends AWSThread
         processResultSet(rj, response, request);
         break;
       case 202:
-        rj.statMessage = "Job submitted successfully. Results available at this URL:\n"
-                + rj.getJobId() + "\n";
+        rj.statMessage = "<br>Job submitted successfully. Results available at this URL:\n"
+                + "<a href="
+                + rj.getJobId()
+                + "\">"
+                + rj.getJobId()
+                + "</a><br>";
         rj.running = true;
         break;
       case 302:
@@ -274,6 +286,7 @@ public class RestJobThread extends AWSThread
         rj.setAllowedServerExceptions(0);
         rj.setSubjobComplete(true);
         rj.error = true;
+        rj.running = false;
         completeStatus(rj, response, "" + getStage(stg)
                 + "failed. Reason below:\n");
         break;
@@ -346,9 +359,24 @@ public class RestJobThread extends AWSThread
     }
     HttpEntity en = con.getEntity();
     /*
-     * Just show the content as a string.
+     * Just append the content as a string.
      */
-    rj.statMessage = EntityUtils.toString(en);
+    String f;
+    StringBuffer content = new StringBuffer(f = EntityUtils.toString(en));
+    f = f.toLowerCase();
+    int body = f.indexOf("<body");
+    if (body > -1)
+    {
+      content.delete(0, f.indexOf(">", body));
+    }
+    if (body > -1 && sb.length() > 0)
+    {
+      sb.append("\n");
+      content.insert(0, sb);
+      sb = null;
+    }
+    f = null;
+    rj.statMessage = content.toString();
   }
 
   @Override
@@ -379,51 +407,90 @@ public class RestJobThread extends AWSThread
   public void parseResult()
   {
     // crazy users will see this message
-    System.err.println("WARNING: Rest job result parser is INCOMPLETE!");
+    // TODO: finish this! and remove the message below!
+    Cache.log.warn("Rest job result parser is currently INCOMPLETE!");
+    int validres = 0;
     for (RestJob rj : (RestJob[]) jobs)
     {
-      // TODO: call each jobs processResults() method and collect valid
-      // contexts.
       if (rj.hasResponse() && rj.resSet != null && rj.resSet.isValid())
       {
         String ln = null;
-        System.out.println("Parsing data for job " + rj.getJobId());
-        if (!restClient.isAlignmentModified())
+        try
         {
-          try
-          {
-            /*
-             * while ((ln=rj.resSet.nextLine())!=null) { System.out.println(ln);
-             * } }
-             */
-            List<DataProvider> dp = new ArrayList<DataProvider>();
-            restClient.af.newView_actionPerformed(null);
-            dp.add(new SimpleDataProvider(JvDataType.ANNOTATION, rj.resSet, null));
-            JalviewDataset context = new JalviewDataset(restClient.av.getAlignment().getDataset(), null, null,restClient.av.getAlignment());
-            ParsePackedSet pps = new ParsePackedSet();
-            pps.getAlignment(context, dp);
-            
-            // do an ap.refresh restClient.av.alignmentChanged(Desktop.getAlignmentPanels(restClient.av.getViewId())[0]);
-            System.out.println("Finished parsing data for job "
-                    + rj.getJobId());
-
-          } catch (Exception ex)
+          Cache.log.debug("Parsing data for job " + rj.getJobId());
+          rj.parseResultSet();
+          if (rj.hasResults())
           {
-            System.out.println("Failed to finish parsing data for job "
-                    + rj.getJobId());
-            ex.printStackTrace();
+            validres++;
           }
+          Cache.log.debug("Finished parsing data for job " + rj.getJobId());
+
+        } catch (Error ex)
+        {
+          Cache.log.warn("Failed to finish parsing data for job "
+                  + rj.getJobId());
+          ex.printStackTrace();
+        } catch (Exception ex)
+        {
+          Cache.log.warn("Failed to finish parsing data for job "
+                  + rj.getJobId());
+          ex.printStackTrace();
         }
       }
     }
-    /**
-     * decisions based on job result content + state of alignFrame that
-     * originated the job:
-     */
-    /*
-     * 1. Can/Should this job automatically open a new window for results
-     */
-    wsInfo.setViewResultsImmediatly(false);
+    if (validres > 0)
+    {
+      // add listeners and activate result display gui elements
+      /**
+       * decisions based on job result content + state of alignFrame that
+       * originated the job:
+       */
+      /*
+       * 1. Can/Should this job automatically open a new window for results
+       */
+      if (true)
+      {
+        wsInfo.setViewResultsImmediatly(false);
+      }
+      else
+      {
+        // realiseResults(true, true);
+      }
+      // otherwise, should automatically view results
+
+      // TODO: check if at least one or more contexts are valid - if so, enable
+      // gui
+      wsInfo.showResultsNewFrame.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          realiseResults(false);
+        }
+
+      });
+      wsInfo.mergeResults.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          realiseResults(true);
+        }
+
+      });
+
+      wsInfo.setResultsReady();
+    }
+    else
+    {
+      // tell the user nothing was returned.
+    }
+  }
+
+  public void realiseResults(boolean merge)
+  {
     /*
      * 2. Should the job modify the parent alignment frame/view(s) (if they
      * still exist and the alignment hasn't been edited) in order to display new
@@ -457,30 +524,45 @@ public class RestJobThread extends AWSThread
      * aligned to it ?
      * 
      */
-    // TODO: check if at least one or more contexts are valid - if so, enable
-    // gui
-    wsInfo.showResultsNewFrame.addActionListener(new ActionListener()
+    jalview.gui.AlignmentPanel destPanel = null;
+    if (merge)
     {
-
-      @Override
-      public void actionPerformed(ActionEvent e)
+      if (!restClient.isAlignmentModified())
       {
-        // TODO: call method to show results in new window
+        destPanel = restClient.recoverAlignPanelForView();
+        if (restClient.isShowResultsInNewView())
+        {
+          destPanel = destPanel.alignFrame.newView(false);
+        }
       }
-
-    });
-    wsInfo.mergeResults.addActionListener(new ActionListener()
+    }
+    if (destPanel == null)
     {
-
-      @Override
-      public void actionPerformed(ActionEvent e)
+      Object[] idat = input.getAlignmentAndColumnSelection(restClient.av.getGapCharacter());
+      AlignFrame af = new AlignFrame((AlignmentI) idat[0],
+              (ColumnSelection) idat[1], AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
+      jalview.gui.Desktop.addInternalFrame(af,
+              "Results for " + restClient.service.details.Name + " "
+                      + restClient.service.details.Action + " on "
+                      + restClient.af.getTitle(), AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
+      destPanel = af.alignPanel;
+      // create totally new alignment from stashed data/results
+    }
+    else
+    {
+      for (int j = 0; j < jobs.length; j++)
       {
-        // TODO: call method to merge results into existing window
+        RestJob rj = (RestJob) jobs[j];
+        if (rj.jvresultobj!=null && rj.jvresultobj.length>0) {
+          // transfer results onto panel
+          
+        }
       }
-
-    });
-
-    wsInfo.setResultsReady();
+    }
+    destPanel.adjustAnnotationHeight();
+    
 
   }
 
index 6794a8d..befae8f 100644 (file)
@@ -19,14 +19,19 @@ package jalview.ws.rest;
 
 
 import jalview.datamodel.SequenceI;
+import jalview.io.packed.DataProvider;
+import jalview.io.packed.SimpleDataProvider;
+import jalview.io.packed.DataProvider.JvDataType;
 import jalview.util.GroupUrlLink.UrlStringTooLongException;
 import jalview.util.Platform;
 import jalview.ws.rest.params.Alignment;
 import jalview.ws.rest.params.AnnotationFile;
 import jalview.ws.rest.params.SeqGroupIndexVector;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 
 
@@ -76,16 +81,26 @@ public class RestServiceDescription
    */
   String urlSuffix;
   
-  /***
-   * modelling the io: 
-   * validation of input
-   * { formatter for type, parser for type }
-   *  
-   */
   /** input info given as key/value pairs - mapped to post arguments 
    */ 
   Map<String,InputType> inputParams=new HashMap();
   /**
+   * assigns the given inputType it to its corresponding input parameter token it.token  
+   * @param it
+   */
+  public void setInputParam(InputType it)
+  {
+    inputParams.put(it.token, it);
+  }
+  /**
+   * remove the given input type it from the set of service input parameters.
+   * @param it
+   */
+  public void removeInputParam(InputType it)
+  {
+    inputParams.remove(it.token);
+  }
+  /**
    * service requests alignment data
    */
   boolean aligndata;
@@ -908,4 +923,25 @@ public class RestServiceDescription
     // TODO: correctly write ?/& appropriate to result URL format.
     return jobId+urlSuffix;
   }
+  private List<JvDataType> resultData;
+  public void addResultDatatype(JvDataType dt)
+  {
+    if (resultData==null)
+    {
+      resultData = new ArrayList<JvDataType>();
+    }
+    resultData.add(dt);
+  }
+  public boolean removeRsultDatatype(JvDataType dt)
+  {
+    if (resultData!=null)
+    {
+      return resultData.remove(dt);
+    }
+    return false;
+  }
+  public List<JvDataType> getResultDataTypes()
+  {
+    return resultData;
+  }
 }
index 23c8746..922f933 100644 (file)
@@ -53,8 +53,8 @@ public class Alignment extends InputType {
       throw new NoValidInputDataException("Couldn't write out alignment to file.",ex);
     }
     } else {
-    StringBody sb = new StringBody(new jalview.io.FormatAdapter().formatSequences(format, alignment, jvsuffix), "text/plain", Charset.forName("UTF-8"));
-    sb.getContentTypeParameters().put("filename", "alignment.fa");
+    StringBody sb = new StringBody(new jalview.io.FormatAdapter().formatSequences(format, alignment, jvsuffix)); // , "text/plain", Charset.forName("UTF-8"));
+    // sb.getContentTypeParameters().put("filename", "alignment.fa");
     return sb; 
     }
   }