Clover icon

Coverage Report

  1. Project Clover database Tue Mar 10 2026 14:58:44 GMT
  2. Package jalview.ws2.actions.alignment

File AlignmentTask.java

 

Coverage histogram

../../../../img/srcFileCovDistChart0.png
0% of files have more coverage

Code metrics

30
87
4
1
217
180
23
0.26
21.75
4
5.75

Classes

Class Line # Actions
AlignmentTask 39 87 23
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    package jalview.ws2.actions.alignment;
2   
3    import static java.lang.String.format;
4   
5    import java.io.IOException;
6    import java.util.ArrayList;
7    import java.util.Arrays;
8    import java.util.HashMap;
9    import java.util.List;
10    import java.util.Map;
11   
12    import jalview.analysis.AlignmentSorter;
13    import jalview.analysis.SeqsetUtils;
14    import jalview.analysis.SeqsetUtils.SequenceInfo;
15    import jalview.api.AlignViewportI;
16    import jalview.bin.Console;
17    import jalview.datamodel.AlignedCodonFrame;
18    import jalview.datamodel.Alignment;
19    import jalview.datamodel.AlignmentI;
20    import jalview.datamodel.AlignmentOrder;
21    import jalview.datamodel.AlignmentView;
22    import jalview.datamodel.HiddenColumns;
23    import jalview.datamodel.Sequence;
24    import jalview.datamodel.SequenceI;
25    import jalview.ws.params.ArgumentI;
26    import jalview.ws2.actions.BaseTask;
27    import jalview.ws2.actions.ServiceInputInvalidException;
28    import jalview.ws2.api.Credentials;
29    import jalview.ws2.api.JobStatus;
30    import jalview.ws2.client.api.AlignmentWebServiceClientI;
31   
32    /**
33    * Implementation of an abstract pollable task used by alignment service
34    * actions.
35    *
36    * @author mmwarowny
37    *
38    */
 
39    class AlignmentTask extends BaseTask<AlignmentJob, AlignmentResult>
40    {
41    /* task parameters set in the constructor */
42    private final AlignmentWebServiceClientI client;
43   
44    private final AlignmentAction action;
45   
46    private final AlignmentView msa; // a.k.a. input
47   
48    private final boolean submitGaps;
49   
50    private final AlignmentI currentView;
51   
52    private final AlignmentI dataset;
53   
54    private final char gapChar;
55   
56    private final List<AlignedCodonFrame> codonFrame = new ArrayList<>();
57   
 
58  0 toggle AlignmentTask(AlignmentWebServiceClientI client, AlignmentAction action,
59    List<ArgumentI> args, Credentials credentials,
60    AlignViewportI viewport, boolean submitGaps)
61    {
62  0 super(client, args, credentials);
63  0 this.client = client;
64  0 this.action = action;
65  0 this.msa = viewport.getAlignmentView(true);
66  0 this.submitGaps = submitGaps;
67  0 this.currentView = viewport.getAlignment();
68  0 this.dataset = viewport.getAlignment().getDataset();
69  0 this.gapChar = viewport.getGapCharacter();
70  0 List<AlignedCodonFrame> cf = viewport.getAlignment().getCodonFrames();
71  0 if (cf != null)
72  0 this.codonFrame.addAll(cf);
73    }
74   
 
75  0 toggle @Override
76    protected List<AlignmentJob> prepareJobs() throws ServiceInputInvalidException
77    {
78  0 Console.info(format("starting alignment service %s:%s",
79    client.getClientName(), action.getName()));
80  0 SequenceI[][] conmsa = msa.getVisibleContigs(gapChar);
81  0 if (conmsa == null)
82    {
83  0 throw new ServiceInputInvalidException("no visible contigs for alignment");
84    }
85  0 List<AlignmentJob> jobs = new ArrayList<>(conmsa.length);
86  0 boolean validInput = false;
87  0 for (int i = 0; i < conmsa.length; i++)
88    {
89  0 AlignmentJob job = AlignmentJob.create(conmsa[i], 2, submitGaps);
90  0 validInput |= job.isInputValid(); // at least one input is valid
91  0 job.setStatus(job.isInputValid() ? JobStatus.READY : JobStatus.INVALID);
92  0 jobs.add(job);
93    }
94  0 this.jobs = jobs;
95  0 if (!validInput)
96    {
97  0 throw new ServiceInputInvalidException("no valid sequences for alignment");
98    }
99  0 return jobs;
100    }
101   
 
102  0 toggle @Override
103    protected AlignmentResult collectResult(List<AlignmentJob> jobs) throws IOException
104    {
105  0 IOException lastIOE = null;
106  0 for (AlignmentJob job : jobs)
107    {
108  0 if (job.isInputValid() && job.getStatus() == JobStatus.COMPLETED &&
109    !job.hasResult())
110    {
111  0 try
112    {
113  0 job.setAlignmentResult(client.getAlignment(job.getServerJob()));
114    } catch (IOException e)
115    {
116  0 lastIOE = e;
117    }
118    }
119    }
120  0 if (lastIOE != null)
121  0 throw lastIOE; // do not proceed unless all results has been retrieved
122   
123  0 List<AlignmentOrder> alorders = new ArrayList<>();
124  0 SequenceI[][] results = new SequenceI[jobs.size()][];
125  0 AlignmentOrder[] orders = new AlignmentOrder[jobs.size()];
126  0 for (int i = 0; i < jobs.size(); i++)
127    {
128    /* alternative implementation of MsaWSJob#getAlignment */
129  0 AlignmentJob job = jobs.get(i);
130  0 if (!job.hasResult())
131  0 continue;
132  0 AlignmentI alignment = job.getAlignmentResult();
133  0 int alnSize = alignment.getSequences().size();
134  0 char gapChar = alnSize > 0 ? alignment.getGapCharacter() : '-';
135  0 List<SequenceI> emptySeqs = job.getEmptySequences();
136  0 List<SequenceI> alnSeqs = new ArrayList<>(alnSize);
137    // create copies of all sequences involved
138  0 for (SequenceI seq : alignment.getSequences())
139    {
140  0 alnSeqs.add(new Sequence(seq));
141    }
142  0 for (SequenceI seq : emptySeqs)
143    {
144  0 alnSeqs.add(new Sequence(seq));
145    }
146    // find the width of the longest sequence
147  0 int width = 0;
148  0 for (var seq: alnSeqs)
149  0 width = Integer.max(width, seq.getLength());
150    // make a sequence of gaps only to cut/paste
151  0 String gapSeq;
152    {
153  0 char[] gaps = new char[width];
154  0 Arrays.fill(gaps, gapChar);
155  0 gapSeq = new String(gaps);
156    }
157  0 for (var seq: alnSeqs)
158    {
159  0 if (seq.getLength() < width)
160    {
161    // pad sequences shorter than the target width with gaps
162  0 seq.setSequence(seq.getSequenceAsString()
163    + gapSeq.substring(seq.getLength()));
164    }
165    }
166  0 SequenceI[] result = alnSeqs.toArray(new SequenceI[0]);
167  0 AlignmentOrder msaOrder = new AlignmentOrder(result);
168  0 AlignmentSorter.recoverOrder(result);
169  0 Map<String, SequenceInfo> names = new HashMap<>(job.getNames());
170  0 SeqsetUtils.deuniquify(names, result);
171   
172  0 alorders.add(msaOrder);
173  0 results[i] = result;
174  0 orders[i] = msaOrder;
175    }
176  0 Object[] newView = msa.getUpdatedView(results, orders, gapChar);
177    // free references to original data
178  0 for (int i = 0; i < jobs.size(); i++)
179    {
180  0 results[i] = null;
181  0 orders[i] = null;
182    }
183  0 SequenceI[] alignment = (SequenceI[]) newView[0];
184  0 HiddenColumns hidden = (HiddenColumns) newView[1];
185  0 Alignment aln = new Alignment(alignment);
186  0 aln.setProperty("Alignment Program", action.getName());
187  0 if (dataset != null)
188  0 aln.setDataset(dataset);
189   
190  0 propagateDatasetMappings(aln);
191  0 return new AlignmentResult(aln, alorders, hidden);
192    }
193   
194    /**
195    * Conserve dataset references to sequence objects returned from web services.
196    * Propagate AlignedCodonFrame data from {@code codonFrame} to {@code aln}.
197    * TODO: Refactor to datamodel
198    */
 
199  0 toggle private void propagateDatasetMappings(AlignmentI aln)
200    {
201  0 if (codonFrame != null)
202    {
203  0 SequenceI[] alignment = aln.getSequencesArray();
204  0 for (final SequenceI seq : alignment)
205    {
206  0 for (AlignedCodonFrame acf : codonFrame)
207    {
208  0 if (acf != null && acf.involvesSequence(seq))
209    {
210  0 aln.addCodonFrame(acf);
211  0 break;
212    }
213    }
214    }
215    }
216    }
217    }