package dnanexus;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.dnanexus.ColumnSpecification;
import com.dnanexus.DXAPI;
import com.dnanexus.DXEnvironment;
import com.dnanexus.DXGTable;
import com.dnanexus.DXJSON;
import com.dnanexus.DXUtil;
public class DXTrimReads {
private static class GTableAddRowsRequest {
@JsonProperty
private int part;
@JsonProperty
private List<ArrayNode> data;
public GTableAddRowsRequest(int part, List<ArrayNode> data) {
this.part = part;
this.data = data;
}
}
private static class GTableGetRequest {
@JsonProperty
private int starting;
@JsonProperty
private int limit;
public GTableGetRequest(int starting, int limit) {
this.starting = starting;
this.limit = limit;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
private static class GTableGetResponse {
@JsonProperty
private List<ArrayNode> data;
}
@JsonIgnoreProperties(ignoreUnknown = true)
private static class GTableNewResponse {
@JsonProperty
public String id;
}
@JsonIgnoreProperties(ignoreUnknown = true)
private static class ReadTrimmerInput {
@JsonProperty
private DXGTable reads;
@JsonProperty
private int trimLength;
}
private static class ReadTrimmerOutput {
@JsonProperty
private DXGTable trimmedReads;
public ReadTrimmerOutput(DXGTable trimmedReads) {
this.trimmedReads = trimmedReads;
}
}
public static void main(String[] args) throws IOException {
System.out.println("This is the DNAnexus Java Read Trimmer Example App");
ReadTrimmerInput input = DXUtil.getJobInput(ReadTrimmerInput.class);
DXGTable readsTable = input.reads;
int trimLength = input.trimLength;
System.out.println("Trimming reads in " + readsTable.getId());
// Raw API call here because DXGTable.Builder doesn't support
// initializeFrom
ObjectNode gtableNewInput = DXJSON.getObjectBuilder()
.put("initializeFrom",
DXJSON.getObjectBuilder()
.put("project", DXEnvironment.create().getWorkspace().getId())
.put("id", readsTable.getId())
.build())
.build();
DXGTable trimmedReads = DXGTable.getInstance(DXAPI.gtableNew(gtableNewInput, GTableNewResponse.class).id);
DXGTable.Describe gtableDesc = readsTable.describe();
int sequenceColumnIndex = -1, qualColumnIndex = -1;
List<ColumnSpecification> columns = gtableDesc.getColumns();
for (int i = 0; i < columns.size(); i++) {
ColumnSpecification cs = columns.get(i);
if (cs.getName().equals("sequence")) {
sequenceColumnIndex = i;
} else if (cs.getName().equals("quality")) {
qualColumnIndex = i;
}
}
// Raw API calls here because there are no high-level bindings to "get"
// and "addRows" methods in DXGTable
int step = 10000, nextPartIndex = 1;
for (int i = 0; i < gtableDesc.getNumRows(); i += step) {
GTableGetRequest gtableGetInput = new GTableGetRequest(i, step);
List<ArrayNode> inputRows = DXAPI.gtableGet(readsTable.getId(), gtableGetInput, GTableGetResponse.class).data;
List<ArrayNode> outputRows = new ArrayList<ArrayNode>();
for (ArrayNode row : inputRows) {
// First row is the index - don't send it back. After removing
// it, the remaining columns should correspond to the GTable
// schema.
row.remove(0);
String sequence = row.get(sequenceColumnIndex).textValue();
String quality = row.get(qualColumnIndex).textValue();
String sequenceSubstr = sequence.substring(0, Math.max(sequence.length()-trimLength, 0));
String qualitySubstr = quality.substring(0, Math.max(quality.length()-trimLength, 0));
row.set(sequenceColumnIndex, TextNode.valueOf(sequenceSubstr));
row.set(qualColumnIndex, TextNode.valueOf(qualitySubstr));
outputRows.add(row);
}
DXAPI.gtableAddRows(trimmedReads.getId(), new GTableAddRowsRequest(nextPartIndex++, outputRows), JsonNode.class);
}
trimmedReads.close();
DXUtil.writeJobOutput(new ReadTrimmerOutput(trimmedReads));
System.out.println("Trimming complete!");
}
}