1
2
3
4
5
6
7 package org.utgenome.gwt.utgb.server.app;
8
9 import java.io.BufferedReader;
10 import java.io.File;
11 import java.io.IOException;
12 import java.io.InputStreamReader;
13 import java.net.URL;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import javax.servlet.ServletContext;
18 import javax.servlet.ServletException;
19 import javax.servlet.http.HttpServletRequest;
20 import javax.servlet.http.HttpServletResponse;
21
22 import org.utgenome.UTGBErrorCode;
23 import org.utgenome.UTGBException;
24 import org.utgenome.format.bed.BEDDatabase;
25 import org.utgenome.format.sam.SAMReader;
26 import org.utgenome.graphics.GenomeWindow;
27 import org.utgenome.graphics.ReadCanvas;
28 import org.utgenome.gwt.utgb.client.bio.ChrLoc;
29 import org.utgenome.gwt.utgb.client.bio.DASLocation;
30 import org.utgenome.gwt.utgb.client.bio.DASResult;
31 import org.utgenome.gwt.utgb.client.bio.DASResult.DASFeature;
32 import org.utgenome.gwt.utgb.client.bio.GenomeDB;
33 import org.utgenome.gwt.utgb.client.bio.GenomeDB.DBType;
34 import org.utgenome.gwt.utgb.client.bio.OnGenome;
35 import org.utgenome.gwt.utgb.client.bio.ReadCoverage;
36 import org.utgenome.gwt.utgb.client.bio.ReadQueryConfig;
37 import org.utgenome.gwt.utgb.client.bio.ReadQueryConfig.Layout;
38 import org.utgenome.gwt.utgb.server.WebTrackBase;
39 import org.utgenome.gwt.utgb.server.util.WebApplicationResource;
40 import org.xerial.silk.SilkWriter;
41 import org.xerial.util.ObjectHandlerBase;
42 import org.xerial.util.StopWatch;
43 import org.xerial.util.log.Logger;
44
45
46
47
48
49 public class ReadView extends WebTrackBase {
50 private static final long serialVersionUID = 1L;
51 private static Logger _logger = Logger.getLogger(ReadView.class);
52
53 public ReadView() {
54 }
55
56 public int start = -1;
57 public int end = -1;
58 public String species;
59 public String ref;
60 public String chr;
61 public int width = 700;
62 public boolean useCanvas = true;
63 public Layout layout = Layout.PILEUP;
64
65
66 public String path;
67
68 public static boolean isDescendant(String targetPath) {
69
70 String[] pathComponent = targetPath.split("(\\\\|/)");
71 if (pathComponent == null)
72 return false;
73
74 int level = 0;
75 for (String each : pathComponent) {
76 if ("..".equals(each)) {
77 level--;
78 }
79 else if (!".".equals(each)) {
80 level++;
81 }
82 if (level < 0)
83 return false;
84 }
85
86 return level > 0;
87 }
88
89 @Override
90 public void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
91
92
93 if (start == -1 || end == -1 || chr == null)
94 return;
95
96 String suffix = getActionSuffix(request);
97 _logger.info("suffix: " + suffix);
98 if ("png".equals(suffix)) {
99 response.setContentType("image/png");
100 ReadQueryConfig config = new ReadQueryConfig(width, useCanvas, layout);
101 config.maxmumNumberOfReadsToDisplay = Integer.MAX_VALUE;
102 List<OnGenome> result = overlapQuery(new GenomeDB(path, ref), new ChrLoc(chr, start, end), config);
103
104 ReadCanvas canvas = new ReadCanvas(width, 100, new GenomeWindow(start, end));
105 canvas.draw(result);
106 canvas.toPNG(response.getOutputStream());
107 }
108 else {
109 List<OnGenome> result = overlapQuery(new GenomeDB(path, ref), new ChrLoc(chr, start, end), new ReadQueryConfig(width, useCanvas, layout));
110
111 response.setContentType("text/html");
112
113
114 SilkWriter w = new SilkWriter(response.getWriter());
115 w.preamble();
116 for (OnGenome each : result) {
117 w.leafObject("entry", each);
118 }
119 w.endDocument();
120 }
121 }
122
123 public static List<OnGenome> overlapQuery(GenomeDB db, ChrLoc loc, ReadQueryConfig config) {
124
125 if (!isDescendant(db.path)) {
126 _logger.error("relative path must be used in the path parameter: " + db.path);
127 return new ArrayList<OnGenome>(0);
128 }
129 return overlapQuery(new File(WebTrackBase.getProjectRootPath()), db, loc, config);
130 }
131
132 public static List<OnGenome> overlapQuery(File baseDir, GenomeDB db, ChrLoc loc, ReadQueryConfig config) {
133
134 StopWatch sw = new StopWatch();
135 loc = loc.getLocForPositiveStrand();
136 List<OnGenome> result = new ArrayList<OnGenome>();
137 try {
138
139 DBType dbType = GenomeDB.resolveDBType(db.path);
140 if (dbType == null)
141 throw new UTGBException(UTGBErrorCode.UnknownDBType, "auto detection of DBType failed : " + db.path);
142
143 switch (dbType) {
144 case BAM: {
145 File bamFile = new File(db.path);
146 if (config.wigPath != null) {
147 config.wigPath = new File(baseDir, config.wigPath).getAbsolutePath();
148 File wigDB = new File(config.wigPath.trim());
149 if (!(wigDB.exists() && wigDB.isFile())) {
150 _logger.warn(String.format("wig database file %s is not found", config.wigPath));
151 config.wigPath = null;
152 }
153 }
154
155 if (config.layout == Layout.COVERAGE)
156 return SAMReader.depthCoverage(bamFile, loc, config.pixelWidth, config);
157 else
158 return SAMReader.overlapQuery(bamFile, loc, config.pixelWidth, config);
159 }
160 case BED: {
161 result = BEDDatabase.overlapQuery(new File(db.path), loc);
162 break;
163 }
164 case DAS: {
165 String dasType = null;
166 if (db instanceof DASLocation) {
167 dasType = ((DASLocation) db).dasType;
168 }
169 DASResult queryDAS = DASViewer.queryDAS(db.path, dasType, loc);
170 if (queryDAS != null) {
171 for (DASFeature each : queryDAS.segment.feature) {
172 result.add(each);
173 }
174 }
175 break;
176 }
177 default:
178 throw new UTGBException(UTGBErrorCode.INVALID_INPUT, "unknown db type: " + dbType);
179 }
180 }
181 catch (Exception e) {
182 e.printStackTrace();
183 }
184
185 _logger.debug("query done. " + sw.getElapsedTime() + " sec.");
186
187 if (config.layout == Layout.COVERAGE || result.size() > config.maxmumNumberOfReadsToDisplay) {
188
189 ReadCoverage coverage = computeCoverage(result, loc.start, loc.end, config.pixelWidth);
190 result.clear();
191 result.add(coverage);
192 }
193
194 return result;
195 }
196
197 public static ReadCoverage computeCoverage(List<OnGenome> readList, int start, int end, int pixelWidth) {
198
199 int[] coverage = new int[pixelWidth];
200 for (int i = 0; i < coverage.length; ++i)
201 coverage[i] = 0;
202
203 GenomeWindow w = new GenomeWindow(start, end);
204
205
206
207
208
209 for (OnGenome eachRead : readList) {
210 int bucketStart = w.getXPosOnWindow(eachRead.getStart(), pixelWidth);
211 int bucketEnd = w.getXPosOnWindow(eachRead.getEnd(), pixelWidth);
212 if (bucketStart < 0)
213 bucketStart = 0;
214
215 if (bucketEnd - bucketStart <= 0)
216 bucketEnd = bucketStart + 1;
217
218 if (bucketEnd >= pixelWidth)
219 bucketEnd = pixelWidth - 1;
220
221 for (int i = bucketStart; i < bucketEnd; ++i)
222 coverage[i]++;
223 }
224
225 return new ReadCoverage(start, end, pixelWidth, coverage);
226 }
227
228 private static class OnGenomeDataRetriever<T extends OnGenome> extends ObjectHandlerBase<T> {
229 private ArrayList<OnGenome> geneList = new ArrayList<OnGenome>();
230
231 public OnGenomeDataRetriever() {
232 }
233
234 public ArrayList<OnGenome> getResult() {
235 return geneList;
236 }
237
238 public void handle(T bean) throws Exception {
239 geneList.add(bean);
240 }
241
242 public void handleException(Exception e) throws Exception {
243 _logger.error(e);
244 }
245 }
246
247 private static BufferedReader openURL(String url, ServletContext context) throws IOException {
248 BufferedReader in;
249 if (!url.startsWith("http://")) {
250 if (!url.startsWith("/"))
251 url = "/" + url;
252 _logger.debug("proxy request: " + url);
253 in = WebApplicationResource.openResource(context, url);
254 }
255 else {
256 URL address = new URL(url);
257 _logger.debug("proxy request: " + url);
258 in = new BufferedReader(new InputStreamReader(address.openStream()));
259 }
260 return in;
261 }
262
263 }