Merge branch 'feature/JAL-3954-ebi-phmmer' into mmw/JAL-4199-task-execution-update
[jalview.git] / src / jalview / ws2 / actions / hmmer / PhmmerTask.java
1 package jalview.ws2.actions.hmmer;
2
3 import static jalview.util.Comparison.GapChars;
4
5 import java.io.IOException;
6 import java.util.List;
7
8 import jalview.analysis.AlignSeq;
9 import jalview.bin.Console;
10 import jalview.datamodel.AlignmentAnnotation;
11 import jalview.datamodel.AlignmentI;
12 import jalview.datamodel.AlignmentView;
13 import jalview.datamodel.Annotation;
14 import jalview.datamodel.Sequence;
15 import jalview.datamodel.SequenceI;
16 import jalview.util.Comparison;
17 import jalview.ws.params.ArgumentI;
18 import jalview.ws2.actions.BaseJob;
19 import jalview.ws2.actions.BaseTask;
20 import jalview.ws2.actions.ServiceInputInvalidException;
21 import jalview.ws2.api.Credentials;
22 import jalview.ws2.api.JobStatus;
23 import jalview.ws2.client.api.AlignmentWebServiceClientI;
24
25 class PhmmerTask extends BaseTask<BaseJob, AlignmentI>
26 {
27   private final AlignmentWebServiceClientI client;
28   private final AlignmentView view;
29
30   PhmmerTask(AlignmentWebServiceClientI client, List<ArgumentI> args,
31           Credentials credentials, AlignmentView view)
32   {
33     super(client, args, credentials);
34     this.client = client;
35     this.view = view;
36   }
37
38   @Override
39   protected List<BaseJob> prepareJobs() throws ServiceInputInvalidException
40   {
41     Console.info("Preparing sequence for phmmer job");
42     var sequence = view.getVisibleAlignment('-').getSequenceAt(0);
43     var seq = new Sequence(sequence.getName(),
44             AlignSeq.extractGaps(GapChars, sequence.getSequenceAsString()));
45     var job = new BaseJob(List.of(seq))
46     {
47       @Override
48       public boolean isInputValid()
49       {
50         return true;
51       }
52     };
53     job.setStatus(JobStatus.READY);
54     return List.of(job);
55   }
56
57   @Override
58   protected AlignmentI collectResult(List<BaseJob> jobs) throws IOException
59   {
60     var job = jobs.get(0);
61     var status = job.getStatus();
62     Console.info(String.format("phmmer finished job \"%s\" with status %s",
63             job.getServerJob().getJobId(), status));
64     if (status != JobStatus.COMPLETED)
65       return null;
66     var outputAlignment = client.getAlignment(job.getServerJob());
67     var querySeq = job.getInputSequences().get(0).deriveSequence();
68     {
69       AlignmentAnnotation refpos = null;
70       for (var annot : outputAlignment.getAlignmentAnnotation())
71       {
72         if (annot.sequenceRef == null && annot.label.equals("Reference Positions"))
73         {
74           refpos = annot;
75           break;
76         }
77       }
78       if (refpos != null)
79       {
80         querySeq = alignQeuryToReferencePositions(querySeq, refpos);
81       }
82     }
83     outputAlignment.insertSequenceAt(0, querySeq);
84     return outputAlignment;
85   }
86
87   private SequenceI alignQeuryToReferencePositions(SequenceI query, AlignmentAnnotation refpos)
88   {
89     var sequenceBuilder = new StringBuilder();
90     var index = 0;
91     for (Annotation a : refpos.annotations)
92     {
93       // TODO: we assume that the number of "x" annotations is equal to the number
94       // of residues. may need a safeguard against invalid input
95       if (a != null && a.displayCharacter.equals("x"))
96       {
97         char c;
98         do
99           c = query.getCharAt(index++);
100         while (Comparison.isGap(c));
101         sequenceBuilder.append(c);
102       }
103       else
104       {
105         sequenceBuilder.append(Comparison.GAP_DASH);
106       }
107     }
108     query.setSequence(sequenceBuilder.toString());
109     return query;
110   }
111 }