View Javadoc

1   //--------------------------------------
2   //
3   // ReadView.java
4   // Since: 2009/04/27
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   * Web action for querying data in a specified window in a genome
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  	// resource ID
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  		// validating input
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 			// output the result in Silk format
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 			// compute coverage
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 		// 0112233332200332111000 (coverage)
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 }