1 /*******************************************************************************
2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3 * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
17 *******************************************************************************/
18 package jalview.ws.rest;
20 import jalview.bin.Cache;
21 import jalview.datamodel.Alignment;
22 import jalview.datamodel.AlignmentAnnotation;
23 import jalview.datamodel.AlignmentI;
24 import jalview.datamodel.AlignmentOrder;
25 import jalview.datamodel.Annotation;
26 import jalview.datamodel.ColumnSelection;
27 import jalview.datamodel.SequenceGroup;
28 import jalview.datamodel.SequenceI;
29 import jalview.gui.AlignFrame;
30 import jalview.gui.Desktop;
31 import jalview.gui.PaintRefresher;
32 import jalview.gui.WebserviceInfo;
33 import jalview.io.NewickFile;
34 import jalview.io.packed.JalviewDataset;
35 import jalview.io.packed.JalviewDataset.AlignmentSet;
36 import jalview.ws.AWSThread;
37 import jalview.ws.AWsJob;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.Enumeration;
44 import java.util.Hashtable;
45 import java.util.List;
46 import java.util.Map.Entry;
47 import java.util.Vector;
49 import org.apache.axis.transport.http.HTTPConstants;
50 import org.apache.http.Header;
51 import org.apache.http.HttpEntity;
52 import org.apache.http.HttpResponse;
53 import org.apache.http.client.ClientProtocolException;
54 import org.apache.http.client.methods.HttpGet;
55 import org.apache.http.client.methods.HttpPost;
56 import org.apache.http.client.methods.HttpRequestBase;
57 import org.apache.http.entity.mime.HttpMultipartMode;
58 import org.apache.http.entity.mime.MultipartEntity;
59 import org.apache.http.impl.client.DefaultHttpClient;
60 import org.apache.http.protocol.BasicHttpContext;
61 import org.apache.http.protocol.HttpContext;
62 import org.apache.http.util.EntityUtils;
64 public class RestJobThread extends AWSThread
71 protected RestClient restClient;
73 public RestJobThread(RestClient restClient)
75 super(restClient.af, null, restClient._input,
76 restClient.service.postUrl);
77 this.restClient = restClient; // may not be needed
79 // minimal job - submit given input and parse result onto alignment as
80 // annotation/whatever
82 // look for tree data, etc.
84 // for moment do following job type only
85 // input=visiblealignment,groupsindex
86 // ie one subjob using groups defined on alignment.
87 if (!restClient.service.isHseparable())
89 jobs = new RestJob[1];
90 jobs[0] = new RestJob(0, this,
91 restClient._input.getVisibleAlignment(restClient.service
93 restClient._input.getVisibleContigs());
94 // need a function to get a range on a view/alignment and return both
95 // annotation, groups and selection subsetted to just that region.
100 int[] viscontig = restClient._input.getVisibleContigs();
101 AlignmentI[] viscontigals = restClient._input
102 .getVisibleContigAlignments(restClient.service
104 if (viscontigals != null && viscontigals.length > 0)
106 jobs = new RestJob[viscontigals.length];
107 for (int j = 0; j < jobs.length; j++)
109 int[] visc = new int[]
110 { viscontig[j * 2], viscontig[j * 2 + 1] };
113 jobs[j] = new RestJob(j, this, viscontigals[j], visc);
117 jobs[j] = new RestJob(0, this, viscontigals[j], visc);
124 * subjob types row based: per sequence in alignment/selected region { input
125 * is one sequence or sequence ID } per alignment/selected region { input is
126 * set of sequences, alignment, one or more sets of sequence IDs,
129 if (!restClient.service.isHseparable())
132 // create a bunch of subjobs per visible contig to ensure result honours
134 // TODO: determine if a 'soft' hSeperable property is needed - e.g. if
135 // user does SS-pred on sequence with big hidden regions, its going to be
140 // create a single subjob for the visible/selected input
143 // TODO: decide if vSeperable exists: eg. column wide analysis where hidden
144 // rows do not affect output - generally no analysis that generates
145 // alignment annotation is vSeparable -
149 * create gui components for monitoring jobs
151 * @param webserviceInfo
153 public void setWebServiceInfo(WebserviceInfo webserviceInfo)
155 wsInfo = webserviceInfo;
156 for (int j = 0; j < jobs.length; j++)
159 // Copy over any per job params
162 wsInfo.setProgressName("region " + jobs[j].getJobnum(),
163 jobs[j].getJobnum());
167 wsInfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
172 private String getStage(Stage stg)
174 if (stg == Stage.SUBMIT)
175 return "submitting ";
176 if (stg == Stage.POLL)
177 return "checking status of ";
179 return (" being confused about ");
182 private void doPoll(RestJob rj) throws Exception
184 String postUrl = rj.getPollUrl();
185 doHttpReq(Stage.POLL, rj, postUrl);
189 * construct the post and handle the response.
193 public void doPost(RestJob rj) throws Exception
195 String postUrl = rj.getPostUrl();
196 doHttpReq(Stage.SUBMIT, rj, postUrl);
201 * do the HTTP request - and respond/set statuses appropriate to the current
206 * - provides any data needed for posting and used to record state
208 * - actual URL to post/get from
211 protected void doHttpReq(Stage stg, RestJob rj, String postUrl)
214 StringBuffer respText = new StringBuffer();
215 // con.setContentHandlerFactory(new
216 // jalview.ws.io.mime.HttpContentHandler());
217 HttpRequestBase request = null;
218 String messages = "";
219 if (stg == Stage.SUBMIT)
222 // http://evgenyg.wordpress.com/2010/05/01/uploading-files-multipart-post-apache/
224 HttpPost htpost = new HttpPost(postUrl);
225 MultipartEntity postentity = new MultipartEntity(
226 HttpMultipartMode.STRICT);
227 for (Entry<String, InputType> input : rj.getInputParams())
229 if (input.getValue().validFor(rj))
231 postentity.addPart(input.getKey(), input.getValue()
232 .formatForInput(rj));
236 messages += "Skipped an input (" + input.getKey()
237 + ") - Couldn't generate it from available data.";
240 htpost.setEntity(postentity);
245 request = new HttpGet(postUrl);
249 DefaultHttpClient httpclient = new DefaultHttpClient();
251 HttpContext localContext = new BasicHttpContext();
252 HttpResponse response = null;
255 response = httpclient.execute(request);
256 } catch (ClientProtocolException he)
258 rj.statMessage = "Web Protocol Exception when "
259 + getStage(stg) + "Job. <br>Problematic url was <a href=\""+request.getURI()+"\">"+request.getURI()+"</a><br>See Console output for details.";
260 rj.setAllowedServerExceptions(0);// unrecoverable;
262 Cache.log.fatal("Unexpected REST Job " + getStage(stg)
263 + "exception for URL " + rj.rsd.postUrl);
265 } catch (IOException e)
267 rj.statMessage = "IO Exception when "
268 + getStage(stg) + "Job. <br>Problematic url was <a href=\""+request.getURI()+"\">"+request.getURI()+"</a><br>See Console output for details.";
269 Cache.log.warn("IO Exception for REST Job " + getStage(stg)
270 + "exception for URL " + rj.rsd.postUrl);
274 switch (response.getStatusLine().getStatusCode())
278 Cache.log.debug("Processing result set.");
279 processResultSet(rj, response, request);
282 rj.statMessage = "<br>Job submitted successfully. Results available at this URL:\n"
292 if (!rj.isSubmitted()
294 .getHeaders(HTTPConstants.HEADER_LOCATION)) != null
300 .warn("Ignoring additional "
302 + " location(s) provided in response header ( next one is '"
303 + loc[1].getValue() + "' )");
305 rj.setJobId(loc[0].getValue());
306 rj.setSubmitted(true);
308 completeStatus(rj, response);
312 rj.setSubmitted(true);
313 rj.setAllowedServerExceptions(0);
314 rj.setSubjobComplete(true);
317 completeStatus(rj, response, "" + getStage(stg)
318 + "failed. Reason below:\n");
321 // Some other response. Probably need to pop up the content in a window.
322 // TODO: deal with all other HTTP response codes from server.
323 Cache.log.warn("Unhandled response status when " + getStage(stg)
324 + "for " + postUrl + ": " + response.getStatusLine());
327 response.getEntity().consumeContent();
328 } catch (IOException e)
330 Cache.log.debug("IOException when consuming unhandled response",
339 * job has completed. Something valid should be available from con
344 * is a stateless request - expected to return the same data
345 * regardless of how many times its called.
347 private void processResultSet(RestJob rj, HttpResponse con,
350 if (rj.statMessage == null)
354 rj.statMessage += "Job Complete.\n";
357 rj.resSet = new HttpResultSet(rj, con, req);
359 } catch (IOException e)
361 rj.statMessage += "Couldn't parse results. Failed.";
363 rj.gotresult = false;
367 private void completeStatus(RestJob rj, HttpResponse con)
370 completeStatus(rj, con, null);
374 private void completeStatus(RestJob rj, HttpResponse con, String prefix)
377 StringBuffer sb = new StringBuffer();
383 if (rj.statMessage != null && rj.statMessage.length() > 0)
385 sb.append(rj.statMessage);
387 HttpEntity en = con.getEntity();
389 * Just append the content as a string.
392 StringBuffer content = new StringBuffer(f = EntityUtils.toString(en));
394 int body = f.indexOf("<body");
397 content.delete(0, f.indexOf(">", body));
399 if (body > -1 && sb.length() > 0)
402 content.insert(0, sb);
406 rj.statMessage = content.toString();
410 public void pollJob(AWsJob job) throws Exception
412 assert (job instanceof RestJob);
413 System.err.println("Debug RestJob: Polling Job");
414 doPoll((RestJob) job);
418 public void StartJob(AWsJob job)
420 assert (job instanceof RestJob);
423 System.err.println("Debug RestJob: Posting Job");
424 doPost((RestJob) job);
426 catch (NoValidInputDataException erex)
428 job.setSubjobComplete(true);
429 job.setSubmitted(true);
430 ((RestJob)job).statMessage="<br>It looks like there was a problem with the data sent to the service :<br>"+erex.getMessage()+"\n";
431 ((RestJob)job).error=true;
436 job.setSubjobComplete(true);
437 job.setAllowedServerExceptions(-1);
438 Cache.log.error("Exception when trying to start Rest Job.", ex);
443 public void parseResult()
445 // crazy users will see this message
446 // TODO: finish this! and remove the message below!
447 Cache.log.warn("Rest job result parser is currently INCOMPLETE!");
449 for (RestJob rj : (RestJob[]) jobs)
451 if (rj.hasResponse() && rj.resSet != null && rj.resSet.isValid())
456 Cache.log.debug("Parsing data for job " + rj.getJobId());
462 Cache.log.debug("Finished parsing data for job " + rj.getJobId());
466 Cache.log.warn("Failed to finish parsing data for job "
468 ex.printStackTrace();
469 } catch (Exception ex)
471 Cache.log.warn("Failed to finish parsing data for job "
473 ex.printStackTrace();
477 rj.statMessage = "Error whilst parsing data for this job.<br>URL for job response is :<a href=\""+rj.resSet.getUrl()+"\">"+rj.resSet.getUrl()+"</a><br>";
483 // add listeners and activate result display gui elements
485 * decisions based on job result content + state of alignFrame that
486 * originated the job:
489 * 1. Can/Should this job automatically open a new window for results
493 // preserver current jalview behaviour
494 wsInfo.setViewResultsImmediatly(true);
498 // realiseResults(true, true);
500 // otherwise, should automatically view results
502 // TODO: check if at least one or more contexts are valid - if so, enable
504 wsInfo.showResultsNewFrame.addActionListener(new ActionListener()
508 public void actionPerformed(ActionEvent e)
510 realiseResults(false);
514 wsInfo.mergeResults.addActionListener(new ActionListener()
518 public void actionPerformed(ActionEvent e)
520 realiseResults(true);
525 wsInfo.setResultsReady();
529 // tell the user nothing was returned.
530 wsInfo.setStatus(wsInfo.STATE_STOPPED_ERROR);
531 wsInfo.setFinishedNoResults();
536 * instructions for whether to create new alignment view on current alignment
537 * set, add to current set, or create new alignFrame
539 private enum AddDataTo
542 * add annotation, trees etc to current view
546 * create a new view derived from current view and add data to that
550 * create a new alignment frame for the result set and add annotation to
556 public void realiseResults(boolean merge)
559 * 2. Should the job modify the parent alignment frame/view(s) (if they
560 * still exist and the alignment hasn't been edited) in order to display new
561 * annotation/features.
564 * alignment panels derived from each alignment set returned by service.
566 ArrayList<jalview.gui.AlignmentPanel> destPanels = new ArrayList<jalview.gui.AlignmentPanel>();
568 * list of instructions for how to process each distinct alignment set
569 * returned by the job set
571 ArrayList<AddDataTo> resultDest = new ArrayList<AddDataTo>();
573 * when false, zeroth pane is panel derived from input deta.
575 boolean newAlignment = false;
577 * gap character to be used for alignment reconstruction
579 char gapCharacter = restClient.av.getGapCharacter();
580 // Now, iterate over all alignment sets returned from all jobs:
581 // first inspect jobs and collate results data in order to count alignments
583 // then assemble results from decomposed (v followed by h-separated) jobs
584 // finally, new views and alignments will be created and displayed as
586 boolean hsepjobs = restClient.service.isHseparable();
587 boolean vsepjobs = restClient.service.isVseparable();
588 // total number of distinct alignment sets generated by job set.
589 int numAlSets = 0, als = 0;
590 List<AlignmentI> destAls = new ArrayList<AlignmentI>();
591 List<jalview.datamodel.ColumnSelection> destColsel = new ArrayList<jalview.datamodel.ColumnSelection>();
592 List<List<NewickFile>> trees = new ArrayList<List<NewickFile>>();
597 // iterate over each alignment set returned from each subjob. Treating
598 // each one returned in parallel with others.
599 // Result collation arrays
602 * mapping between index of sequence in alignment that was submitted to
603 * server and index of sequence in the input alignment
605 int[][] ordermap = new int[jobs.length][];
606 SequenceI[][] rseqs = new SequenceI[jobs.length][];
607 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
608 AlignmentAnnotation[][] alan = new AlignmentAnnotation[jobs.length][];
609 SequenceGroup[][] sgrp = new SequenceGroup[jobs.length][];
610 // Now collect all data for alignment Set als from job array
611 for (int j = 0; j < jobs.length; j++)
613 RestJob rj = (RestJob) jobs[j];
616 JalviewDataset rset = rj.context;
617 if (rset.hasAlignments())
619 if (numAlSets < rset.getAl().size())
621 numAlSets = rset.getAl().size();
623 if (als < rset.getAl().size()
624 && rset.getAl().get(als).isModified())
626 // Collate result data
627 // TODO: decide if all alignmentI should be collected rather than
628 // specific alignment data containers
629 // for moment, we just extract content, but this means any
630 // alignment properties may be lost.
631 AlignmentSet alset = rset.getAl().get(als);
632 alan[j] = alset.al.getAlignmentAnnotation();
633 if (alset.al.getGroups() != null)
635 sgrp[j] = new SequenceGroup[alset.al.getGroups().size()];
636 alset.al.getGroups().toArray(sgrp[j]);
642 orders[j] = new AlignmentOrder(alset.al);
643 rseqs[j] = alset.al.getSequencesArray();
644 ordermap[j] = rj.getOrderMap();
645 // if (rj.isInputUniquified()) {
646 // jalview.analysis.AlignmentSorter.recoverOrder(rseqs[als]);
649 if (alset.trees != null)
651 trees.add(new ArrayList<NewickFile>(alset.trees));
655 trees.add(new ArrayList<NewickFile>());
661 // Now aggregate and present results from this frame of alignment data.
662 int nvertsep = 0, nvertseps = 1;
665 // Jobs relate to different rows of input alignment.
666 // Jobs are subdivided by rows before columns,
667 // so there will now be a number of subjobs according tohsep for each
669 // TODO: get vertical separation intervals for each job and set
671 // TODO: merge data from each group/sequence onto whole
675 * index into rest jobs subdivided vertically
678 // Destination alignments for all result data.
679 ArrayList<SequenceGroup> visgrps = new ArrayList<SequenceGroup>();
680 Hashtable<String, SequenceGroup> groupNames = new Hashtable<String, SequenceGroup>();
681 ArrayList<AlignmentAnnotation> visAlAn = null;
682 for (nvertsep = 0; nvertsep < nvertseps; nvertsep++)
684 // TODO: set scope w.r.t. original alignment view for vertical
687 // results for a job exclude hidden columns of input data, so map
688 // back on to all visible regions
690 * rest job result we are working with
694 RestJob rj = (RestJob) jobs[nrj];
695 int contigs[] = input.getVisibleContigs();
696 AlignmentI destAl = null;
697 jalview.datamodel.ColumnSelection destCs = null;
698 // Resolve destAl for this data.
699 if (als == 0 && rj.isInputContextModified())
701 // special case: transfer features, annotation, groups, etc,
703 // context to align panel derived from input data
704 if (destAls.size() > als)
706 destAl = destAls.get(als);
710 if (!restClient.isAlignmentModified() && merge)
712 destAl = restClient.av.getAlignment();
713 destCs = restClient.av.getColumnSelection();
715 .add(restClient.isShowResultsInNewView() ? AddDataTo.newView
716 : AddDataTo.currentView);
717 destPanels.add(restClient.recoverAlignPanelForView());
722 // recreate the input alignment data
723 Object[] idat = input
724 .getAlignmentAndColumnSelection(gapCharacter);
725 destAl = new Alignment((SequenceI[]) idat[0]);
726 destCs = (ColumnSelection) idat[1];
727 resultDest.add(AddDataTo.newAlignment);
728 // but do not add to the alignment panel list - since we need to
729 // create a whole new alignFrame set.
732 destColsel.add(destCs);
737 // alignment(s) returned by service is to be re-integrated and
739 if (destAls.size() > als)
743 // TODO: decide if multiple multiple alignments returned by
744 // non-vseparable services are allowed.
746 .warn("dealing with multiple alignment products returned by non-vertically separable service.");
748 // recover reference to last alignment created for this rest frame
749 // ready for extension
750 destAl = destAls.get(als);
751 destCs = destColsel.get(als);
759 // single alignment for any job that gets mapped back on to
760 // input data. Reconstruct by interleaving parts of returned
761 // alignment with hidden parts of input data.
762 SequenceI[][] nsq = splitSeqsOnVisibleContigs(rseqs[nrj],
763 contigs, gapCharacter);
764 AlignmentOrder alo[] = new AlignmentOrder[nsq.length];
765 for (int no = 0; no < alo.length; no++)
767 alo[no] = new AlignmentOrder(orders[nrj].getOrder());
769 newview = input.getUpdatedView(nsq, orders, gapCharacter);
773 // each job maps to a single visible contig, and all need to be
774 // stitched back together.
775 // reconstruct using sub-region based MSA alignment construction
777 newview = input.getUpdatedView(rseqs, orders, gapCharacter);
779 destAl = new Alignment((SequenceI[]) newview[0]);
780 destCs = (ColumnSelection) newview[1];
782 // TODO create alignment from result data with propagated
785 destColsel.add(destCs);
786 resultDest.add(AddDataTo.newAlignment);
787 throw new Error("Impl. Error! TODO: ");
791 * save initial job in this set in case alignment is h-separable
795 for (int ncnt = 0; ncnt < contigs.length; ncnt += 2)
799 // single alignment for any job that gets mapped back on to input
804 // each job maps to a single visible contig, and all need to be
805 // stitched back together.
810 // TODO: apply options for group merging and annotation merging.
811 // If merging not supported, then either clear hashtables now or
812 // use them to rename the new annotation/groups for each contig if
813 // a conflict occurs.
815 if (sgrp[nrj] != null)
817 for (SequenceGroup sg : sgrp[nrj])
819 boolean recovered = false;
820 SequenceGroup exsg = null;
821 if (sg.getName() != null)
823 exsg = groupNames.get(sg.getName());
827 exsg = new SequenceGroup(sg);
828 groupNames.put(exsg.getName(), exsg);
830 exsg.setStartRes(sg.getStartRes() + contigs[ncnt]);
831 exsg.setEndRes(sg.getEndRes() + contigs[ncnt]);
835 // now replace any references from the result set with
836 // corresponding refs from alignment input set.
838 // TODO: cope with recovering hidden sequences from
841 Vector sqs = sg.getSequences(null);
842 for (int sqsi = 0, iSize = sqs.size(); sqsi < iSize; sqsi++)
844 SequenceI oseq = (SequenceI) sqs.get(sqsi);
845 SequenceI nseq = getNewSeq(oseq, rseqs[nrj],
846 ordermap[nrj], destAl);
851 exsg.deleteSequence(oseq, false);
853 exsg.addSequence(nseq, false);
858 .warn("Couldn't resolve original sequence for new sequence.");
863 if (exsg.getSeqrep() == sg.getSeqrep())
865 // lift over sequence rep reference too
866 SequenceI oseq = sg.getSeqrep();
867 SequenceI nseq = getNewSeq(oseq, rseqs[nrj],
868 ordermap[nrj], destAl);
871 exsg.setSeqrep(nseq);
878 // adjust boundaries of recovered group w.r.t. new group being
879 // merged on to original alignment.
880 int start = sg.getStartRes() + contigs[ncnt], end = sg
881 .getEndRes() + contigs[ncnt];
882 if (start < exsg.getStartRes())
884 exsg.setStartRes(start);
886 if (end > exsg.getEndRes())
896 // and finally add in annotation and any trees for each job
897 for (int ncnt = 0; ncnt < contigs.length; ncnt += 2)
901 // single alignment for any job that gets mapped back on to input
906 // each job maps to a single visible contig, and all need to be
907 // stitched back together.
914 // merge alignmentAnnotation into one row
915 if (alan[nrj] != null)
917 for (int an = 0; an < alan[nrj].length; an++)
919 SequenceI sqass = null;
920 SequenceGroup grass = null;
921 if (alan[nrj][an].sequenceRef != null)
923 // TODO: ensure this relocates sequence reference to local
925 sqass = getNewSeq(alan[nrj][an].sequenceRef, rseqs[nrj],
926 ordermap[nrj], destAl);
928 if (alan[nrj][an].groupRef != null)
930 // TODO: verify relocate group reference to local context
932 grass = groupNames.get(alan[nrj][an].groupRef.getName());
936 .error("Couldn't relocate group referemce for group "
937 + alan[nrj][an].groupRef.getName());
942 visAlAn = new ArrayList<AlignmentAnnotation>();
944 AlignmentAnnotation visan = null;
945 for (AlignmentAnnotation v : visAlAn)
948 && v.label.equals(alan[nrj][an].label))
955 visan = new AlignmentAnnotation(alan[nrj][an]);
956 // copy annotations, and wipe out/update refs.
957 visan.annotations = new Annotation[input.getWidth()];
958 visan.groupRef = grass;
959 visan.sequenceRef = sqass;
962 if (contigs[ncnt]+alan[nrj][an].annotations.length>visan.annotations.length)
964 // increase width of annotation row
965 Annotation[] newannv = new Annotation[contigs[ncnt]+alan[nrj][an].annotations.length];
966 System.arraycopy(visan.annotations, 0, newannv, 0, visan.annotations.length);
967 visan.annotations=newannv;
969 // now copy local annotation data into correct position
970 System.arraycopy(alan[nrj][an].annotations, 0,
971 visan.annotations, contigs[ncnt],
972 alan[nrj][an].annotations.length);
977 if (trees.get(nrj).size() > 0)
979 for (NewickFile nf : trees.get(nrj))
981 // TODO: process each newick file, lifting over sequence refs to
982 // current alignment, if necessary.
984 .error("Tree recovery from restjob not yet implemented.");
989 } // end of vseps loops.
992 for (AlignmentAnnotation v : visAlAn)
994 destAls.get(als).addAnnotation(v);
999 for (SequenceGroup sg : visgrps)
1001 destAls.get(als).addGroup(sg);
1004 } while (++als < numAlSets);
1005 // Finally, assemble each new alignment, and create new gui components to
1008 * current AlignFrame where results will go.
1010 AlignFrame destaf = restClient.recoverAlignFrameForView();
1012 * current pane being worked with
1014 jalview.gui.AlignmentPanel destPanel = restClient
1015 .recoverAlignPanelForView();
1017 for (AddDataTo action : resultDest)
1020 ColumnSelection destcs;
1021 String alTitle = restClient.service.details.Action + " using "
1022 + restClient.service.details.Name + " on "+restClient.viewTitle;
1026 destal = destAls.get(als);
1027 destcs = destColsel.get(als);
1028 destaf = new AlignFrame(destal, destcs, AlignFrame.DEFAULT_WIDTH,
1029 AlignFrame.DEFAULT_HEIGHT);
1030 PaintRefresher.Refresh(destaf, destaf.getViewport().getSequenceSetId());
1031 // todo transfer any feature settings and colouring
1033 * destaf.getFeatureRenderer().transferSettings(this.featureSettings);
1034 * // update orders if (alorders.size() > 0) { if (alorders.size() == 1)
1035 * { af.addSortByOrderMenuItem(WebServiceName + " Ordering",
1036 * (AlignmentOrder) alorders.get(0)); } else { // construct a
1037 * non-redundant ordering set Vector names = new Vector(); for (int i =
1038 * 0, l = alorders.size(); i < l; i++) { String orderName = new
1039 * String(" Region " + i); int j = i + 1;
1041 * while (j < l) { if (((AlignmentOrder) alorders.get(i))
1042 * .equals(((AlignmentOrder) alorders.get(j)))) { alorders.remove(j);
1043 * l--; orderName += "," + j; } else { j++; } }
1045 * if (i == 0 && j == 1) { names.add(new String("")); } else {
1046 * names.add(orderName); } } for (int i = 0, l = alorders.size(); i < l;
1047 * i++) { af.addSortByOrderMenuItem( WebServiceName + ((String)
1048 * names.get(i)) + " Ordering", (AlignmentOrder) alorders.get(i)); } } }
1050 // TODO: modify this and previous alignment's title if many alignments have been returned.
1051 Desktop.addInternalFrame(destaf, alTitle, AlignFrame.DEFAULT_WIDTH,
1052 AlignFrame.DEFAULT_HEIGHT);
1056 // TODO: determine title for view
1064 if (restClient.isShowResultsInNewView())
1066 // destPanel = destPanel.alignFrame.newView(false);
1074 * if (als) // add the destination panel to frame zero of result panel set }
1075 * } if (destPanels.size()==0) { AlignFrame af = new AlignFrame((AlignmentI)
1076 * idat[0], (ColumnSelection) idat[1], AlignFrame.DEFAULT_WIDTH,
1077 * AlignFrame.DEFAULT_HEIGHT);
1079 * jalview.gui.Desktop.addInternalFrame(af, "Results for " +
1080 * restClient.service.details.Name + " " + restClient.service.details.Action
1081 * + " on " + restClient.af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1082 * AlignFrame.DEFAULT_HEIGHT); destPanel = af.alignPanel; // create totally
1083 * new alignment from stashed data/results
1090 * alignments. New alignments are added to dataset, and subsequently
1091 * annotated/visualised accordingly. 1. New alignment frame created for new
1092 * alignment. Decide if any vis settings should be inherited from old
1093 * alignment frame (e.g. sequence ordering ?). 2. Subsequent data added to
1094 * alignment as below:
1097 * annotation update to original/newly created context alignment: 1.
1098 * identify alignment where annotation is to be loaded onto. 2. Add
1099 * annotation, excluding any duplicates. 3. Ensure annotation is visible on
1100 * alignment - honouring ordering given by file.
1103 * features updated to original or newly created context alignment: 1.
1104 * Features are(or were already) added to dataset. 2. Feature settings
1105 * modified to ensure all features are displayed - honouring any ordering
1106 * given by result file. Consider merging action with the code used by the
1107 * DAS fetcher to update alignment views with new info.
1110 * Seq associated data files (PDB files). 1. locate seq association in
1111 * current dataset/alignment context and add file as normal - keep handle of
1112 * any created ref objects. 2. decide if new data should be displayed : PDB
1113 * display: if alignment has PDB display already, should new pdb files be
1117 // destPanel.adjustAnnotationHeight();
1122 * split the given array of sequences into blocks of subsequences
1123 * corresponding to each visible contig
1128 * padding character for ragged ends of visible contig region.
1131 private SequenceI[][] splitSeqsOnVisibleContigs(SequenceI[] sequenceIs,
1132 int[] contigs, char gapChar)
1134 int nvc = contigs == null ? 1 : contigs.length / 2;
1135 SequenceI[][] blocks = new SequenceI[nvc][];
1136 if (contigs == null)
1138 blocks[0] = new SequenceI[sequenceIs.length];
1139 System.arraycopy(sequenceIs, 0, blocks[0], 0, sequenceIs.length);
1143 // deja vu - have I written this before ?? propagateGaps does this in a
1145 char[] gapset = null;
1146 int start = 0, width = 0;
1147 for (int c = 0; c < nvc; c++)
1149 width = contigs[c * 2 + 1] - contigs[c * 2] + 1;
1150 for (int s = 0; s < sequenceIs.length; s++)
1152 int end = sequenceIs[s].getLength();
1155 if (start + width < end)
1157 blocks[c][s] = sequenceIs[s].getSubSequence(start, start
1162 blocks[c][s] = sequenceIs[s].getSubSequence(start, end);
1163 String sq = blocks[c][s].getSequenceAsString();
1164 for (int n = start + width; n > end; n--)
1172 if (gapset == null || gapset.length < width)
1174 char ng[] = new char[width];
1178 System.arraycopy(gapset, 0, ng, 0, gs = gapset.length);
1180 while (gs < ng.length)
1185 blocks[c][s] = sequenceIs[s].getSubSequence(end, end);
1186 blocks[c][s].setSequence(gapset.toString().substring(0, width));
1191 // adjust window for next visible segnment
1192 start += contigs[c * 2 + 1] - contigs[c * 2];
1200 * recover corresponding sequence from original input data corresponding to
1201 * sequence in a specific job's input data.
1209 private SequenceI getNewSeq(SequenceI oseq, SequenceI[] sequenceIs,
1210 int[] is, AlignmentI destAl)
1213 while (p < sequenceIs.length && sequenceIs[p] != oseq)
1217 if (p < sequenceIs.length && p < destAl.getHeight())
1219 return destAl.getSequenceAt(is[p]);
1226 * @return true if the run method is safe to call
1228 public boolean isValid()
1230 ArrayList<String> _warnings=new ArrayList<String>();
1231 boolean validt=true;
1234 for (RestJob rj : (RestJob[]) jobs)
1236 if (!rj.hasValidInput())
1238 // invalid input for this job
1239 System.err.println("Job " + rj.getJobnum()
1240 + " has invalid input. ( "+rj.getStatus()+")");
1241 if (rj.hasStatus() && !_warnings.contains(rj.getStatus()))
1243 _warnings.add(rj.getStatus());
1252 for (String st : _warnings) {
1253 if (warnings.length()>0) { warnings+="\n";
1262 protected String warnings;
1263 public boolean hasWarnings()
1265 // TODO Auto-generated method stub
1266 return warnings!=null && warnings.length()>0;
1270 * get any informative messages about why the job thread couldn't start.
1273 public String getWarnings()
1275 return isValid() ? "Job can be started. No warnings." : hasWarnings() ? warnings : "";