package net.sourceforge.seqware.webservice.resources.tables;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.seqware.common.factory.DBAccess;
import static net.sourceforge.seqware.webservice.resources.BasicResource.parseClientInt;
import net.sourceforge.seqware.webservice.resources.BasicRestlet;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.OutputRepresentation;
public class ProcessingStructureResource extends BasicRestlet {
public ProcessingStructureResource(Context context) {
super(context);
}
@Override
public void handle(Request request, Response response) {
authenticate(request.getChallengeResponse().getIdentifier());
init(request);
Form form = request.getResourceRef().getQueryAsForm();
String swAccession = form.getFirstValue("swAccession");
// handle multi accession
if (swAccession == null) {
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "null swAccession");
return;
}
String[] accessions = swAccession.trim().split(",");
List<Integer> accessionList = new ArrayList<>();
for (String a : accessions) {
try {
Integer i = parseClientInt(a);
accessionList.add(i);
} catch (NumberFormatException e) {
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid swAccession");
return;
}
}
final StringBuffer sb = new StringBuffer();
sb.append("digraph dag {\n");
for (int i : accessionList) {
DotNode root = null;
try {
root = this.buildDotTree(i);
} catch (SQLException e) {
e.printStackTrace();
}
if (root == null) {
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid swAccession");
return;
}
Set<String> cache = new HashSet<>();
this.visitNode(root, sb, cache);
}
sb.append("}\n");
OutputRepresentation output = new OutputRepresentation(MediaType.TEXT_ALL) {
@Override
public void write(OutputStream out) throws IOException {
try (Writer writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))) {
writer.write(sb.toString());
writer.flush();
}
}
};
response.setEntity(output);
}
private DotNode buildDotTree(int parentAccession) throws SQLException {
String sql0 = "select processing_id, algorithm, sw_accession from processing where sw_accession = " + parentAccession;
DotNode root = null;
try {
root = DBAccess.get().executeQuery(sql0, new ResultSetHandler<DotNode>() {
@Override
public DotNode handle(ResultSet rs) throws SQLException {
if (rs.next()) {
DotNode root = new DotNode(rs.getInt("processing_id"));
root.setAlgo(rs.getString("algorithm"));
root.setSWAccessionId(rs.getInt("sw_accession"));
return root;
} else {
return null;
}
}
});
if (root == null) return null;
} finally {
DBAccess.close();
}
String sql = "select a.child_id, b.algorithm, b.sw_accession from processing_relationship a, processing b "
+ "where a.child_id = b.processing_id and a.parent_id = " + root.getProcessingId();
List<DotNode> children;
try {
children = DBAccess.get().executeQuery(sql, new ResultSetHandler<List<DotNode>>() {
@Override
public List<DotNode> handle(ResultSet rs) throws SQLException {
List<DotNode> children = new ArrayList<>();
while (rs.next()) {
DotNode c = new DotNode(rs.getInt("child_id"));
c.setAlgo(rs.getString("algorithm"));
c.setSWAccessionId(rs.getInt("sw_accession"));
children.add(c);
}
return children;
}
});
} finally {
DBAccess.close();
}
for (DotNode c : children) {
root.addChild(c);
this.addSubNodes(c);
}
return root;
}
private void addSubNodes(DotNode parent) throws SQLException {
String sql = "select a.child_id, b.algorithm, b.sw_accession from processing_relationship a, processing b "
+ "where a.child_id = b.processing_id and a.parent_id = " + parent.getProcessingId();
List<DotNode> children;
try {
children = DBAccess.get().executeQuery(sql, new ResultSetHandler<List<DotNode>>() {
@Override
public List<DotNode> handle(ResultSet rs) throws SQLException {
List<DotNode> children = new ArrayList<>();
while (rs.next()) {
DotNode c = new DotNode(rs.getInt("child_id"));
c.setAlgo(rs.getString("algorithm"));
c.setSWAccessionId(rs.getInt("sw_accession"));
children.add(c);
}
return children;
}
});
} finally {
DBAccess.close();
}
for (DotNode c : children) {
parent.addChild(c);
this.addSubNodes(c);
}
}
private void visitNode(DotNode node, StringBuffer fw, Collection<String> all) {
for (DotNode child : node.getChildren()) {
String w = node.toString() + " -> " + child.toString();
if (all.contains(w)) continue;
all.add(w);
fw.append(w).append("\n");
this.visitNode(child, fw, all);
}
}
class DotNode {
private List<DotNode> children;
private int processingId;
private String algo;
private int swAccessionId;
public DotNode(int pid) {
this.children = new ArrayList<>();
this.processingId = pid;
}
public void addChild(DotNode node) {
if (!this.children.contains(node)) this.children.add(node);
}
@Override
public String toString() {
return this.algo + "__" + this.swAccessionId;
}
public List<DotNode> getChildren() {
return this.children;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DotNode == false) return false;
if (obj == this) return true;
DotNode rhs = (DotNode) obj;
return new EqualsBuilder().appendSuper(super.equals(obj)).append(this.processingId, rhs.processingId).isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37).append(this.processingId).toHashCode();
}
public int getProcessingId() {
return this.processingId;
}
public String getAlgo() {
return this.algo;
}
public void setAlgo(String algo) {
this.algo = algo;
}
public int getSWAccessionId() {
return this.swAccessionId;
}
public void setSWAccessionId(int id) {
this.swAccessionId = id;
}
}
}