Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.ws2.actions.alignment

File AlignmentTask.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
13% 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.826446382.6%
 

Contributing tests

This file is covered by 27 tests. .

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  26 toggle AlignmentTask(AlignmentWebServiceClientI client, AlignmentAction action,
59    List<ArgumentI> args, Credentials credentials,
60    AlignViewportI viewport, boolean submitGaps)
61    {
62  26 super(client, args, credentials);
63  26 this.client = client;
64  26 this.action = action;
65  26 this.msa = viewport.getAlignmentView(true);
66  26 this.submitGaps = submitGaps;
67  26 this.currentView = viewport.getAlignment();
68  26 this.dataset = viewport.getAlignment().getDataset();
69  26 this.gapChar = viewport.getGapCharacter();
70  26 List<AlignedCodonFrame> cf = viewport.getAlignment().getCodonFrames();
71  26 if (cf != null)
72  26 this.codonFrame.addAll(cf);
73    }
74   
 
75  26 toggle @Override
76    protected List<AlignmentJob> prepareJobs() throws ServiceInputInvalidException
77    {
78  26 Console.info(format("starting alignment service %s:%s",
79    client.getClientName(), action.getName()));
80  26 SequenceI[][] conmsa = msa.getVisibleContigs(gapChar);
81  26 if (conmsa == null)
82    {
83  0 throw new ServiceInputInvalidException("no visible contigs for alignment");
84    }
85  26 List<AlignmentJob> jobs = new ArrayList<>(conmsa.length);
86  26 boolean validInput = false;
87  52 for (int i = 0; i < conmsa.length; i++)
88    {
89  26 AlignmentJob job = AlignmentJob.create(conmsa[i], 2, submitGaps);
90  26 validInput |= job.isInputValid(); // at least one input is valid
91  26 job.setStatus(job.isInputValid() ? JobStatus.READY : JobStatus.INVALID);
92  26 jobs.add(job);
93    }
94  26 this.jobs = jobs;
95  26 if (!validInput)
96    {
97  0 throw new ServiceInputInvalidException("no valid sequences for alignment");
98    }
99  26 return jobs;
100    }
101   
 
102  26 toggle @Override
103    protected AlignmentResult collectResult(List<AlignmentJob> jobs) throws IOException
104    {
105  26 IOException lastIOE = null;
106  26 for (AlignmentJob job : jobs)
107    {
108  26 if (job.isInputValid() && job.getStatus() == JobStatus.COMPLETED &&
109    !job.hasResult())
110    {
111  20 try
112    {
113  20 job.setAlignmentResult(client.getAlignment(job.getServerJob()));
114    } catch (IOException e)
115    {
116  0 lastIOE = e;
117    }
118    }
119    }
120  26 if (lastIOE != null)
121  0 throw lastIOE; // do not proceed unless all results has been retrieved
122   
123  26 List<AlignmentOrder> alorders = new ArrayList<>();
124  26 SequenceI[][] results = new SequenceI[jobs.size()][];
125  26 AlignmentOrder[] orders = new AlignmentOrder[jobs.size()];
126  52 for (int i = 0; i < jobs.size(); i++)
127    {
128    /* alternative implementation of MsaWSJob#getAlignment */
129  26 AlignmentJob job = jobs.get(i);
130  26 if (!job.hasResult())
131  18 continue;
132  8 AlignmentI alignment = job.getAlignmentResult();
133  8 int alnSize = alignment.getSequences().size();
134  8 char gapChar = alnSize > 0 ? alignment.getGapCharacter() : '-';
135  8 List<SequenceI> emptySeqs = job.getEmptySequences();
136  8 List<SequenceI> alnSeqs = new ArrayList<>(alnSize);
137    // create copies of all sequences involved
138  8 for (SequenceI seq : alignment.getSequences())
139    {
140  24 alnSeqs.add(new Sequence(seq));
141    }
142  8 for (SequenceI seq : emptySeqs)
143    {
144  0 alnSeqs.add(new Sequence(seq));
145    }
146    // find the width of the longest sequence
147  8 int width = 0;
148  8 for (var seq: alnSeqs)
149  24 width = Integer.max(width, seq.getLength());
150    // make a sequence of gaps only to cut/paste
151  8 String gapSeq;
152    {
153  8 char[] gaps = new char[width];
154  8 Arrays.fill(gaps, gapChar);
155  8 gapSeq = new String(gaps);
156    }
157  8 for (var seq: alnSeqs)
158    {
159  24 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  8 SequenceI[] result = alnSeqs.toArray(new SequenceI[0]);
167  8 AlignmentOrder msaOrder = new AlignmentOrder(result);
168  8 AlignmentSorter.recoverOrder(result);
169  8 Map<String, SequenceInfo> names = new HashMap<>(job.getNames());
170  8 SeqsetUtils.deuniquify(names, result);
171   
172  8 alorders.add(msaOrder);
173  8 results[i] = result;
174  8 orders[i] = msaOrder;
175    }
176  26 Object[] newView = msa.getUpdatedView(results, orders, gapChar);
177    // free references to original data
178  52 for (int i = 0; i < jobs.size(); i++)
179    {
180  26 results[i] = null;
181  26 orders[i] = null;
182    }
183  26 SequenceI[] alignment = (SequenceI[]) newView[0];
184  26 HiddenColumns hidden = (HiddenColumns) newView[1];
185  26 Alignment aln = new Alignment(alignment);
186  26 aln.setProperty("Alignment Program", action.getName());
187  26 if (dataset != null)
188  0 aln.setDataset(dataset);
189   
190  26 propagateDatasetMappings(aln);
191  26 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  26 toggle private void propagateDatasetMappings(AlignmentI aln)
200    {
201  26 if (codonFrame != null)
202    {
203  26 SequenceI[] alignment = aln.getSequencesArray();
204  26 for (final SequenceI seq : alignment)
205    {
206  78 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    }