Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/tax/TaxServer.java @ 68:5028fdace37b
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 16:23:26 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 68:5028fdace37b |
---|---|
1 package tax; | |
2 | |
3 import java.io.File; | |
4 import java.io.IOException; | |
5 import java.io.InputStream; | |
6 import java.io.PrintStream; | |
7 import java.net.InetSocketAddress; | |
8 import java.util.ArrayList; | |
9 import java.util.Arrays; | |
10 import java.util.Collections; | |
11 import java.util.Date; | |
12 import java.util.HashMap; | |
13 import java.util.List; | |
14 import java.util.Locale; | |
15 import java.util.Map.Entry; | |
16 import java.util.concurrent.ConcurrentHashMap; | |
17 import java.util.concurrent.atomic.AtomicInteger; | |
18 import java.util.concurrent.atomic.AtomicLong; | |
19 import java.util.concurrent.atomic.AtomicLongArray; | |
20 | |
21 import com.sun.net.httpserver.HttpExchange; | |
22 import com.sun.net.httpserver.HttpHandler; | |
23 import com.sun.net.httpserver.HttpServer; | |
24 import com.sun.net.httpserver.HttpsServer; | |
25 | |
26 import dna.Data; | |
27 import fileIO.ReadWrite; | |
28 import json.JsonObject; | |
29 import server.PercentEncoding; | |
30 import server.ServerTools; | |
31 import shared.KillSwitch; | |
32 import shared.Parse; | |
33 import shared.Parser; | |
34 import shared.PreParser; | |
35 import shared.Shared; | |
36 import shared.Timer; | |
37 import shared.Tools; | |
38 import sketch.CompareBuffer; | |
39 import sketch.Comparison; | |
40 import sketch.DisplayParams; | |
41 import sketch.Sketch; | |
42 import sketch.SketchMakerMini; | |
43 import sketch.SketchObject; | |
44 import sketch.SketchResults; | |
45 import sketch.SketchSearcher; | |
46 import sketch.SketchTool; | |
47 import sketch.Whitelist; | |
48 import stream.Read; | |
49 import structures.ByteBuilder; | |
50 import structures.IntList; | |
51 import structures.StringNum; | |
52 | |
53 /** | |
54 * Server for taxonomy or Sketch queries. | |
55 * @author Shijie Yao, Brian Bushnell | |
56 * @date Dec 13, 2016 | |
57 * | |
58 */ | |
59 public class TaxServer { | |
60 | |
61 /*--------------------------------------------------------------*/ | |
62 /*---------------- Startup ----------------*/ | |
63 /*--------------------------------------------------------------*/ | |
64 | |
65 /** Command line entrance */ | |
66 public static void main(String[] args) throws Exception { | |
67 Timer t=new Timer(); | |
68 @SuppressWarnings("unused") | |
69 TaxServer ts=new TaxServer(args); | |
70 | |
71 t.stop("Time: "); | |
72 | |
73 System.err.println("Ready!"); | |
74 | |
75 //ts.begin(); | |
76 } | |
77 | |
78 /** Constructor */ | |
79 public TaxServer(String[] args) throws Exception { | |
80 | |
81 {//Preparse block for help, config files, and outstream | |
82 PreParser pp=new PreParser(args, getClass(), false); | |
83 args=pp.args; | |
84 outstream=pp.outstream; | |
85 } | |
86 | |
87 ReadWrite.USE_UNPIGZ=true; | |
88 TaxFilter.printNodesAdded=false; | |
89 TaxFilter.REQUIRE_PRESENT=false; //Due to missing entries in TaxDump. | |
90 Read.JUNK_MODE=Read.FIX_JUNK; | |
91 SketchObject.compareSelf=true; | |
92 | |
93 int port_=3068; //Taxonomy server | |
94 String killCode_=null; | |
95 boolean allowRemoteFileAccess_=false; | |
96 boolean allowLocalHost_=false; | |
97 String addressPrefix_="128."; //LBL | |
98 long defaultSketchReads=200000; | |
99 boolean https=false; | |
100 | |
101 int serverNum_=0; | |
102 int serverCount_=1; | |
103 | |
104 //Create a parser object | |
105 Parser parser=new Parser(); | |
106 | |
107 //Parse each argument | |
108 for(int i=0; i<args.length; i++){ | |
109 String arg=args[i]; | |
110 | |
111 //Break arguments into their constituent parts, in the form of "a=b" | |
112 String[] split=arg.split("="); | |
113 String a=split[0].toLowerCase(); | |
114 String b=split.length>1 ? split[1] : null; | |
115 | |
116 if(a.equals("verbose")){ | |
117 verbose=Parse.parseBoolean(b); | |
118 }else if(a.equals("verbose2")){ | |
119 verbose2=SketchObject.verbose2=Parse.parseBoolean(b); | |
120 }else if(a.equals("html")){ | |
121 useHtml=Parse.parseBoolean(b); | |
122 }else if(a.equals("https")){ | |
123 https=Parse.parseBoolean(b); | |
124 }else if(a.equals("http")){ | |
125 https=!Parse.parseBoolean(b); | |
126 }else if(a.equals("servers") || a.equals("numservers") || a.equals("servercount")){ | |
127 serverCount_=Integer.parseInt(b); | |
128 assert(serverCount_>0) : arg; | |
129 }else if(a.equals("servernum")){ | |
130 serverNum_=Integer.parseInt(b); | |
131 assert(serverNum_>=0) : arg; | |
132 }else if(a.startsWith("slave") && Tools.isDigit(a.charAt(a.length()-1))){ | |
133 int num=Integer.parseInt(a.substring(5)); | |
134 if(slaveAddress==null){slaveAddress=new ArrayList<String>(serverCount_);} | |
135 while(slaveAddress.size()<=num){slaveAddress.add(null);} | |
136 slaveAddress.set(num, b); | |
137 }else if(a.equals("table") || a.equals("gi") || a.equals("gitable")){ | |
138 giTableFile=b; | |
139 }else if(a.equals("tree") || a.equals("taxtree")){ | |
140 taxTreeFile=b; | |
141 }else if(a.equals("accession")){ | |
142 accessionFile=b; | |
143 }else if(a.equals("pattern")){ | |
144 patternFile=b; | |
145 }else if(a.equals("size") || a.equals("sizefile")){ | |
146 sizeFile=b; | |
147 }else if(a.equalsIgnoreCase("img")){ | |
148 imgFile=b; | |
149 }else if(a.equals("domain")){ | |
150 domain=b; | |
151 while(domain!=null && domain.endsWith("/")){domain=domain.substring(0, domain.length()-1);} | |
152 }else if(a.equals("port")){ | |
153 port_=Integer.parseInt(b); | |
154 }else if(a.equals("kill") || a.equals("killcode")){ | |
155 killCode_=b; | |
156 }else if(a.equals("oldcode")){ | |
157 oldKillCode=b; | |
158 }else if(a.equals("oldaddress")){ | |
159 oldAddress=b; | |
160 }else if(a.equals("sketchonly")){ | |
161 sketchOnly=Parse.parseBoolean(b); | |
162 }else if(a.equals("sketchreads")){ | |
163 defaultSketchReads=Parse.parseKMG(b); | |
164 }else if(a.equals("handlerthreads")){ | |
165 handlerThreads=Integer.parseInt(b); | |
166 }else if(a.equals("sketchthreads") || a.equals("sketchcomparethreads")){ | |
167 maxConcurrentSketchCompareThreads=Integer.parseInt(b); | |
168 }else if(a.equals("sketchloadthreads")){ | |
169 maxConcurrentSketchLoadThreads=Integer.parseInt(b); | |
170 }else if(a.equals("hashnames")){ | |
171 hashNames=Parse.parseBoolean(b); | |
172 }else if(a.equals("hashdotformat")){ | |
173 hashDotFormat=Parse.parseBoolean(b); | |
174 }else if(a.equals("printip")){ | |
175 printIP=Parse.parseBoolean(b); | |
176 }else if(a.equals("printheaders")){ | |
177 printHeaders=Parse.parseBoolean(b); | |
178 }else if(a.equals("countqueries")){ | |
179 countQueries=Parse.parseBoolean(b); | |
180 }else if(a.equals("clear") || a.equals("clearmem")){ | |
181 clearMem=Parse.parseBoolean(b); | |
182 }else if(a.equals("dbname")){ | |
183 SketchObject.defaultParams.dbName=b; | |
184 }else if(a.equals("allowremotefileaccess")){ | |
185 allowRemoteFileAccess_=Parse.parseBoolean(b); | |
186 }else if(a.equals("allowlocalhost")){ | |
187 allowLocalHost_=Parse.parseBoolean(b); | |
188 }else if(a.equals("addressprefix")){ | |
189 addressPrefix_=b; | |
190 }else if(a.equals("maxpigzprocesses")){ | |
191 AccessionToTaxid.maxPigzProcesses=Integer.parseInt(b); | |
192 }else if(a.equals("path") || a.equals("treepath") || a.equals("basepath")){ | |
193 basePath=b; | |
194 }else if(a.equalsIgnoreCase("prealloc")){ | |
195 if(b==null || Character.isLetter(b.charAt(0))){ | |
196 if(Parse.parseBoolean(b)){ | |
197 prealloc=0.78f; | |
198 }else{ | |
199 prealloc=0; | |
200 } | |
201 }else{ | |
202 prealloc=Float.parseFloat(b); | |
203 } | |
204 SketchObject.prealloc=prealloc; | |
205 }else if(searcher.parse(arg, a, b, true)){ | |
206 //do nothing | |
207 }else if(parser.parse(arg, a, b)){//Parse standard flags in the parser | |
208 //do nothing | |
209 }else{ | |
210 throw new RuntimeException(arg); | |
211 } | |
212 } | |
213 if("auto".equalsIgnoreCase(imgFile)){imgFile=TaxTree.defaultImgFile();} | |
214 if("auto".equalsIgnoreCase(taxTreeFile)){taxTreeFile=TaxTree.defaultTreeFile();} | |
215 if("auto".equalsIgnoreCase(giTableFile)){giTableFile=TaxTree.defaultTableFile();} | |
216 if("auto".equalsIgnoreCase(accessionFile)){accessionFile=TaxTree.defaultAccessionFile();} | |
217 if("auto".equalsIgnoreCase(patternFile)){patternFile=TaxTree.defaultPatternFile();} | |
218 if("auto".equalsIgnoreCase(sizeFile)){sizeFile=TaxTree.defaultSizeFile();} | |
219 | |
220 serverNum=AccessionToTaxid.serverNum=serverNum_; | |
221 serverCount=AccessionToTaxid.serverCount=serverCount_; | |
222 distributed=AccessionToTaxid.distributed=serverCount>1; | |
223 assert(serverNum<serverCount && serverNum>=0); | |
224 if(distributed && serverNum==0){ | |
225 assert(slaveAddress!=null); | |
226 assert(slaveAddress.size()==serverCount); | |
227 for(int i=1; i<slaveAddress.size(); i++){ | |
228 assert(slaveAddress.get(i)!=null); | |
229 } | |
230 } | |
231 | |
232 maxConcurrentSketchCompareThreads=Tools.mid(1, maxConcurrentSketchCompareThreads, Shared.threads()); | |
233 maxConcurrentSketchLoadThreads=Tools.mid(1, maxConcurrentSketchLoadThreads, Shared.threads()); | |
234 assert(maxConcurrentSketchCompareThreads>=1); | |
235 assert(maxConcurrentSketchLoadThreads>=1); | |
236 | |
237 if(basePath==null || basePath.trim().length()==0){basePath="";} | |
238 else{ | |
239 basePath=basePath.trim().replace('\\', '/').replaceAll("/+", "/"); | |
240 if(!basePath.endsWith("/")){basePath=basePath+"/";} | |
241 } | |
242 | |
243 //Adjust SketchSearch rcomp and amino flags | |
244 SketchObject.postParse(); | |
245 | |
246 if(sketchOnly){ | |
247 // hashNames=false; | |
248 giTableFile=null; | |
249 accessionFile=null; | |
250 imgFile=null; | |
251 patternFile=null; | |
252 } | |
253 | |
254 port=port_; | |
255 killCode=killCode_; | |
256 allowRemoteFileAccess=allowRemoteFileAccess_; | |
257 allowLocalHost=allowLocalHost_; | |
258 addressPrefix=addressPrefix_; | |
259 | |
260 //Fill some data objects | |
261 USAGE=makeUsagePrefix(); | |
262 rawHtml=(useHtml ? loadRawHtml() : null); | |
263 typeMap=makeTypeMap(); | |
264 commonMap=makeCommonMap(); | |
265 | |
266 //Load the GI table | |
267 if(giTableFile!=null){ | |
268 outstream.println("Loading gi table."); | |
269 GiToTaxid.initialize(giTableFile); | |
270 } | |
271 | |
272 //Load the taxTree | |
273 if(taxTreeFile!=null){ | |
274 tree=TaxTree.loadTaxTree(taxTreeFile, outstream, hashNames, hashDotFormat); | |
275 if(hashNames){tree.hashChildren();} | |
276 assert(tree.nameMap!=null || sketchOnly); | |
277 }else{//The tree is required | |
278 tree=null; | |
279 throw new RuntimeException("No tree specified."); | |
280 } | |
281 //Set a default taxtree for sketch-related usage | |
282 SketchObject.taxtree=tree; | |
283 | |
284 if(sizeFile!=null){ | |
285 Timer t=new Timer(); | |
286 outstream.println("Loading size file."); | |
287 tree.loadSizeFile(sizeFile); | |
288 t.stopAndPrint(); | |
289 } | |
290 | |
291 if(imgFile!=null){ | |
292 TaxTree.loadIMG(imgFile, false, outstream); | |
293 } | |
294 | |
295 if(patternFile!=null){ | |
296 Timer t=new Timer(); | |
297 AnalyzeAccession.loadCodeMap(patternFile); | |
298 outstream.println("Loading pattern table."); | |
299 t.stopAndPrint(); | |
300 } | |
301 | |
302 //Load accession files | |
303 if(accessionFile!=null){ | |
304 Timer t=new Timer(); | |
305 AccessionToTaxid.tree=tree; | |
306 AccessionToTaxid.prealloc=prealloc; | |
307 outstream.println("Loading accession table."); | |
308 AccessionToTaxid.load(accessionFile); | |
309 t.stopAndPrint(); | |
310 // if(searcher.refFiles.isEmpty()){System.gc();} | |
311 } | |
312 | |
313 // assert(false) : searcher.refFileCount(); | |
314 | |
315 //Load reference sketches | |
316 hasSketches=searcher.refFileCount()>0; | |
317 if(hasSketches){ | |
318 outstream.println("Loading sketches."); | |
319 Timer t=new Timer(); | |
320 searcher.loadReferences(SketchObject.PER_TAXA, SketchObject.defaultParams); | |
321 t.stopAndPrint(); | |
322 // System.gc(); | |
323 } | |
324 | |
325 SketchObject.allowMultithreadedFastq=(maxConcurrentSketchLoadThreads>1); | |
326 SketchObject.defaultParams.maxReads=defaultSketchReads; | |
327 ReadWrite.USE_UNPIGZ=false; | |
328 // ReadWrite.USE_UNBGZIP=false; | |
329 | |
330 if(clearMem){ | |
331 System.err.println("Clearing memory."); | |
332 System.gc(); | |
333 Shared.printMemory(); | |
334 } | |
335 | |
336 //If there is a kill code, kill the old instance | |
337 if(oldKillCode!=null && oldAddress!=null){ | |
338 outstream.println("Killing old instance."); | |
339 killOldInstance(); | |
340 } | |
341 | |
342 //Wait for server initialization | |
343 httpServer=initializeServer(1000, 8, https); | |
344 assert(httpServer!=null); | |
345 | |
346 //Initialize handlers | |
347 if(!sketchOnly){ | |
348 httpServer.createContext("/", new TaxHandler(false)); | |
349 httpServer.createContext("/tax", new TaxHandler(false)); | |
350 httpServer.createContext("/stax", new TaxHandler(true)); | |
351 httpServer.createContext("/simpletax", new TaxHandler(true)); | |
352 }else{ | |
353 httpServer.createContext("/", new SketchHandler()); | |
354 } | |
355 httpServer.createContext("/sketch", new SketchHandler()); | |
356 if(killCode!=null){ | |
357 httpServer.createContext("/kill", new KillHandler()); | |
358 } | |
359 | |
360 httpServer.createContext("/help", new HelpHandler()); | |
361 httpServer.createContext("/usage", new HelpHandler()); | |
362 httpServer.createContext("/stats", new StatsHandler()); | |
363 httpServer.createContext("/favicon.ico", new IconHandler()); | |
364 | |
365 handlerThreads=handlerThreads>0 ? handlerThreads : Tools.max(2, Shared.threads()); | |
366 httpServer.setExecutor(java.util.concurrent.Executors.newFixedThreadPool(handlerThreads)); // Creates a multithreaded executor | |
367 // httpServer.setExecutor(java.util.concurrent.Executors.newCachedThreadPool()); // Creates a multithreaded executor | |
368 // httpServer.setExecutor(null); // Creates a singlethreaded executor | |
369 | |
370 //Start the server | |
371 httpServer.start(); | |
372 } | |
373 | |
374 /** Kill a prior server instance */ | |
375 private void killOldInstance(){ | |
376 StringNum result=null; | |
377 try { | |
378 result=ServerTools.sendAndReceive(oldKillCode.getBytes(), oldAddress); | |
379 } catch (Exception e) { | |
380 // TODO Auto-generated catch block | |
381 if(e!=null){e.printStackTrace();} | |
382 System.err.println("\nException suppressed; continuing.\n"); | |
383 return; | |
384 } | |
385 if(result==null || result.s==null || !"Success.".equals(result.s)){ | |
386 // KillSwitch.kill("Bad kill result: "+result+"\nQuitting.\n"); | |
387 System.err.println("Bad kill result: "+result+"\nContinuing.\n"); | |
388 } | |
389 ServerTools.pause(1000); | |
390 } | |
391 | |
392 /** Iterative wait for server initialization */ | |
393 private HttpServer initializeServer(int millis0, int iterations, boolean https){ | |
394 HttpServer server=null; | |
395 InetSocketAddress isa=new InetSocketAddress(port); | |
396 Exception ee=null; | |
397 for(int i=0, millis=millis0; i<iterations && server==null; i++){ | |
398 try { | |
399 if(https){ | |
400 server=HttpsServer.create(isa, 0); | |
401 }else{ | |
402 server=HttpServer.create(isa, 0); | |
403 } | |
404 } catch (java.net.BindException e) {//Expected | |
405 System.err.println(e); | |
406 System.err.println("\nWaiting "+millis+" ms"); | |
407 ee=e; | |
408 ServerTools.pause(millis); | |
409 millis=millis*2; | |
410 } catch (IOException e) {//Not sure when this would occur... it would be unexpected | |
411 System.err.println(e); | |
412 System.err.println("\nWaiting "+millis+" ms"); | |
413 ee=e; | |
414 ServerTools.pause(millis); | |
415 millis=millis*2; | |
416 } | |
417 } | |
418 if(server==null){throw new RuntimeException(ee);} | |
419 return server; | |
420 } | |
421 | |
422 public void returnUsage(long startTime, HttpExchange t){ | |
423 if(useHtml){ | |
424 returnUsageHtml(startTime, t); | |
425 return; | |
426 } | |
427 if(logUsage){System.err.println("usage");} | |
428 // String usage=USAGE(USAGE); | |
429 bytesOut.addAndGet(USAGE.length()); | |
430 ServerTools.reply(USAGE, "text/plain", t, verbose2, 200, true); | |
431 final long stopTime=System.nanoTime(); | |
432 final long elapsed=stopTime-startTime; | |
433 timeMeasurementsUsage.incrementAndGet(); | |
434 elapsedTimeUsage.addAndGet(elapsed); | |
435 lastTimeUsage.set(elapsed); | |
436 } | |
437 | |
438 public void returnUsageHtml(long startTime, HttpExchange t){ | |
439 if(logUsage){System.err.println("usage");} | |
440 String s=makeUsageHtml(); | |
441 bytesOut.addAndGet(s.length()); | |
442 ServerTools.reply(s, "html", t, verbose2, 200, true); | |
443 final long stopTime=System.nanoTime(); | |
444 final long elapsed=stopTime-startTime; | |
445 timeMeasurementsUsage.incrementAndGet(); | |
446 elapsedTimeUsage.addAndGet(elapsed); | |
447 lastTimeUsage.set(elapsed); | |
448 } | |
449 | |
450 public void returnStats(long startTime, HttpExchange t){ | |
451 if(logUsage){System.err.println("stats");} | |
452 String stats=makeStats(); | |
453 bytesOut.addAndGet(stats.length()); | |
454 ServerTools.reply(stats, "text/plain", t, verbose2, 200, true); | |
455 final long stopTime=System.nanoTime(); | |
456 final long elapsed=stopTime-startTime; | |
457 timeMeasurementsUsage.incrementAndGet(); | |
458 elapsedTimeUsage.addAndGet(elapsed); | |
459 lastTimeUsage.set(elapsed); | |
460 } | |
461 | |
462 /*--------------------------------------------------------------*/ | |
463 /*---------------- Handlers ----------------*/ | |
464 /*--------------------------------------------------------------*/ | |
465 | |
466 /** Handles queries for favicon.ico */ | |
467 class IconHandler implements HttpHandler { | |
468 | |
469 @Override | |
470 public void handle(HttpExchange t) throws IOException { | |
471 if(verbose2){System.err.println("Icon handler");} | |
472 iconQueries.incrementAndGet(); | |
473 ServerTools.reply(favIcon, "image/x-icon", t, verbose2, 200, true); | |
474 } | |
475 | |
476 } | |
477 | |
478 /*--------------------------------------------------------------*/ | |
479 | |
480 /** Handles queries that fall through other handlers */ | |
481 class HelpHandler implements HttpHandler { | |
482 | |
483 @Override | |
484 public void handle(HttpExchange t) throws IOException { | |
485 if(verbose2){System.err.println("Help handler");} | |
486 final long startTime=System.nanoTime(); | |
487 returnUsage(startTime, t); | |
488 } | |
489 | |
490 } | |
491 | |
492 /*--------------------------------------------------------------*/ | |
493 | |
494 /** Handles queries that fall through other handlers */ | |
495 class StatsHandler implements HttpHandler { | |
496 | |
497 @Override | |
498 public void handle(HttpExchange t) throws IOException { | |
499 if(verbose2){System.err.println("Http handler");} | |
500 final long startTime=System.nanoTime(); | |
501 returnStats(startTime, t); | |
502 } | |
503 | |
504 } | |
505 | |
506 /*--------------------------------------------------------------*/ | |
507 | |
508 /** Handles requests to kill the server */ | |
509 class KillHandler implements HttpHandler { | |
510 | |
511 @Override | |
512 public void handle(HttpExchange t) throws IOException { | |
513 if(verbose2){System.err.println("Kill handler");} | |
514 | |
515 //Parse the query from the URL | |
516 String rparam=getRParam(t, false); | |
517 InetSocketAddress remote=t.getRemoteAddress(); | |
518 | |
519 if(testCode(t, rparam)){ | |
520 ServerTools.reply("Success.", "text/plain", t, verbose2, 200, true); | |
521 System.err.println("Killed by remote address "+remote); | |
522 //TODO: Perhaps try to close open resources such as the server | |
523 KillSwitch.killSilent(); | |
524 } | |
525 | |
526 if(verbose){System.err.println("Bad kill from address "+remote);} | |
527 ServerTools.reply(BAD_CODE, "text/plain", t, verbose2, 403, true); | |
528 } | |
529 | |
530 /** Determines whether kill code was correct */ | |
531 private boolean testCode(HttpExchange t, String rparam){ | |
532 String[] params = rparam.split("/"); | |
533 if(verbose2){System.err.println(Arrays.toString(params));} | |
534 | |
535 if(killCode!=null){ | |
536 if(params.length>1){//URL mode | |
537 return (params[1].equals(killCode)); | |
538 }else{//Body mode | |
539 try { | |
540 String code=ServerTools.receive(t); | |
541 return (code!=null && code.equals(killCode)); | |
542 } catch (Exception e) { | |
543 // TODO Auto-generated catch block | |
544 e.printStackTrace(); | |
545 } | |
546 } | |
547 } | |
548 return false; | |
549 } | |
550 } | |
551 | |
552 /*--------------------------------------------------------------*/ | |
553 | |
554 /** Listens for sketch comparison requests */ | |
555 class SketchHandler implements HttpHandler { | |
556 | |
557 @Override | |
558 public void handle(HttpExchange t) throws IOException { | |
559 if(verbose2){outstream.println("Got a request.");} | |
560 SketchInstance si=new SketchInstance(t); | |
561 if(verbose2){outstream.println("Made si.");} | |
562 si.handleInner(); | |
563 if(verbose2){outstream.println("Done.");} | |
564 } | |
565 | |
566 private ArrayList<Sketch> loadSketchesFromBody(String body){ | |
567 //List of query sketches | |
568 ArrayList<Sketch> sketches=null; | |
569 | |
570 if(body!=null && body.length()>0){ | |
571 sketches=searcher.loadSketchesFromString(body); | |
572 if(Whitelist.exists()){ | |
573 for(Sketch sk : sketches){ | |
574 Whitelist.apply(sk); | |
575 } | |
576 } | |
577 } | |
578 return sketches; | |
579 } | |
580 | |
581 private ArrayList<Sketch> loadSketchesFromFile(String fname, DisplayParams params){ | |
582 //List of query sketches | |
583 ArrayList<Sketch> sketches=null; | |
584 | |
585 SketchTool tool=searcher.tool; | |
586 if(tool.minKeyOccuranceCount!=params.minKeyOccuranceCount || params.trackCounts()){ | |
587 tool=new SketchTool(SketchObject.targetSketchSize, params); | |
588 } | |
589 | |
590 if(verbose2){System.err.println("Loading sketches from file "+fname);} | |
591 sketches=tool.loadSketchesFromFile(fname, (SketchMakerMini)null, maxConcurrentSketchLoadThreads, params.maxReads, params.mode, params, true); | |
592 if(verbose2){System.err.println("Loaded "+(sketches==null ? "null" : sketches.size())+" sketches from file "+fname);} | |
593 return sketches; | |
594 } | |
595 | |
596 //Created in handle() | |
597 private class SketchInstance { | |
598 | |
599 SketchInstance(HttpExchange t_){ | |
600 t=t_; | |
601 instanceStartTime=System.nanoTime(); | |
602 } | |
603 | |
604 void handleInner(){ | |
605 | |
606 if(!hasSketches){ | |
607 if(verbose2){System.err.println("No sketches.");} | |
608 ServerTools.reply("\nERROR: This server has no sketches loaded.\n" | |
609 + "Please download the latest BBTools version to use SendSketch.\n", "text/plain", t, verbose2, 400, true); | |
610 return; | |
611 } | |
612 | |
613 String rparam=parseRparamSketch(t); | |
614 if(verbose2){System.err.println("Parsed rparam.");} | |
615 if(rparam==null){ | |
616 returnUsage(instanceStartTime, t); | |
617 return; | |
618 } | |
619 final boolean internal=incrementQueries(t, fileMode, refMode, false, false, false, false, false, false, false, false, -1); | |
620 if(verbose2){System.err.println("Incremented queries rparam.");} | |
621 | |
622 if(verbose2){System.err.println(rparam);} | |
623 if(verbose2){System.err.println("fileMode="+fileMode+", refMode="+refMode);} | |
624 | |
625 if(fileMode && !internal && !allowRemoteFileAccess){ | |
626 if(verbose){System.err.println("Illegal file query from "+ServerTools.getClientAddress(t));} | |
627 malformedQueries.incrementAndGet(); | |
628 // if(verbose){System.err.println("test1");} | |
629 // String body=getBody(t);//123 | |
630 ServerTools.reply("\nERROR: This server does not allow remote file access. " | |
631 + "You may only use the 'local' flag from with the local intranet.\n", "text/plain", t, verbose2, 400, true); | |
632 // if(verbose){System.err.println("test2");} | |
633 return; | |
634 } | |
635 | |
636 String body=getBody(t); | |
637 if(verbose2){System.err.println("Got body.");} | |
638 | |
639 if(body!=null){bytesIn.addAndGet(body.length());} | |
640 | |
641 if(verbose2){System.err.println("Found body: "+body);} | |
642 if(body!=null && body.length()>0){ | |
643 if((fileMode || refMode) && !body.startsWith("##")){ | |
644 body="##"+body; | |
645 } | |
646 try { | |
647 params=params.parseDoubleHeader(body); | |
648 if(verbose2){System.err.println("Passed parse params.");} | |
649 | |
650 } catch (Throwable e) { | |
651 String s=Tools.toString(e); | |
652 ServerTools.reply("\nERROR: \n"+ s, | |
653 "text/plain", t, verbose2, 400, true); | |
654 return; | |
655 } | |
656 if(!params.compatible()){ | |
657 ServerTools.reply("\nERROR: The sketch is not compatible with this server.\n" | |
658 + "Server settings: k="+SketchObject.k+(SketchObject.k2>0 ? ","+SketchObject.k2 : "") | |
659 +" amino="+SketchObject.amino+" hash_version="+SketchObject.HASH_VERSION+"\n" | |
660 + "You may need to download a newer version of BBTools; this server is running version "+Shared.BBMAP_VERSION_STRING, | |
661 "text/plain", t, verbose2, 400, true); | |
662 return; | |
663 } | |
664 } | |
665 if(params.trackCounts()){ | |
666 depthQueries.incrementAndGet(); | |
667 } | |
668 | |
669 if(verbose2){System.err.println("Parsed params: "+params.toString());} | |
670 | |
671 //List of query sketches | |
672 ArrayList<Sketch> sketches; | |
673 | |
674 if(fileMode){ | |
675 File f=new File(rparam); | |
676 if(!f.exists() && !rparam.startsWith("/")){ | |
677 String temp="/"+rparam; | |
678 f=new File(temp); | |
679 if(f.exists()){rparam=temp;} | |
680 } | |
681 // if(f.exists()){ | |
682 // if(f.length()>100000000L){ | |
683 // if(params.reads<0){ | |
684 // params.reads=200000;//Cap default number of reads at 200000 | |
685 // } | |
686 // } | |
687 // } | |
688 sketches=loadSketchesFromFile(rparam, params); | |
689 }else if(refMode){ | |
690 String[] split=rparam.split(","); | |
691 sketches=new ArrayList<Sketch>(split.length); | |
692 for(String s : split){ | |
693 Sketch sk=findRefSketch(s); | |
694 if(sk!=null){sketches.add(sk);} | |
695 } | |
696 }else{ | |
697 sketches=loadSketchesFromBody(body); | |
698 } | |
699 if(verbose2){System.err.println("Loaded "+sketches.size()+" sketches.");} | |
700 | |
701 final int numSketches=sketches==null ? 0 : sketches.size(); | |
702 if(params.chunkNum<0){ | |
703 if(numSketches<2){ | |
704 unknownChunkSingle.incrementAndGet(); | |
705 }else{ | |
706 unknownChunkMulti.incrementAndGet(); | |
707 } | |
708 }else if(params.chunkNum==0){ | |
709 if(numSketches<2){ | |
710 firstChunkSingle.incrementAndGet(); | |
711 }else{ | |
712 firstChunkMulti.incrementAndGet(); | |
713 } | |
714 }else{ | |
715 if(numSketches<2){ | |
716 nthChunkSingle.incrementAndGet(); | |
717 }else{ | |
718 nthChunkMulti.incrementAndGet(); | |
719 } | |
720 } | |
721 bulkCount.addAndGet(numSketches); | |
722 | |
723 if(params.inputVersion==null){params.inputVersion="unknown";} | |
724 synchronized(versionMap){ | |
725 StringNum sn=versionMap.get(params.inputVersion); | |
726 if(sn==null){versionMap.put(params.inputVersion, new StringNum(params.inputVersion, 1));} | |
727 else{sn.increment();} | |
728 } | |
729 | |
730 String response=null; | |
731 if(sketches==null || sketches.isEmpty()){ | |
732 malformedQueries.incrementAndGet(); | |
733 response="Error."; | |
734 if(verbose){ | |
735 StringBuilder sb=new StringBuilder(); | |
736 sb.append("Malformed query from ").append(ServerTools.getClientAddress(t)).append(". body:"); | |
737 if(body==null){ | |
738 sb.append(" null"); | |
739 }else{ | |
740 String[] split = body.split("\n"); | |
741 sb.append(" ").append(split.length).append(" lines total, displaying ").append(Tools.min(3, split.length)).append('.'); | |
742 for(int i=0; i<3 && i<split.length; i++){ | |
743 String s=split[i]; | |
744 int len=s.length(); | |
745 if(s.length()>1000){s=s.substring(0, 1000)+" [truncated, "+len+" total]";} | |
746 sb.append('\n'); | |
747 sb.append(s); | |
748 } | |
749 } | |
750 System.err.println(sb); | |
751 } | |
752 }else{ | |
753 if(verbose2){ | |
754 System.err.println("Received "+sketches.get(0).name()+", size "+sketches.get(0).keys.length); | |
755 System.err.println("params: "+params); | |
756 System.err.println("postparsed: "+params.postParsed()); | |
757 System.err.println("taxwhitelist: "+params.taxFilterWhite); | |
758 } | |
759 response=compare(sketches, params); | |
760 // searcher.compare(sketches, response, params, maxConcurrentSketchCompareThreads); //This is where it gets stuck if comparing takes too long | |
761 if(verbose2){System.err.println("Result: '"+response+"'");} | |
762 } | |
763 | |
764 bytesOut.addAndGet(response.length()); | |
765 ServerTools.reply(response, "text/plain", t, verbose2, 200, true); | |
766 | |
767 final long stopTime=System.nanoTime(); | |
768 final long elapsed=stopTime-instanceStartTime; | |
769 if(fileMode){ | |
770 timeMeasurementsLocal.incrementAndGet(); | |
771 elapsedTimeLocal.addAndGet(elapsed); | |
772 lastTimeLocal.set(elapsed); | |
773 }else if(refMode){ | |
774 timeMeasurementsReference.incrementAndGet(); | |
775 elapsedTimeReference.addAndGet(elapsed); | |
776 lastTimeReference.set(elapsed); | |
777 }else{ | |
778 timeMeasurementsRemote.incrementAndGet(); | |
779 elapsedTimeRemote.addAndGet(elapsed); | |
780 lastTimeRemote.set(elapsed); | |
781 | |
782 queryCounts.incrementAndGet(Tools.min(numSketches, queryCounts.length()-1)); | |
783 timesByCount.addAndGet(Tools.min(numSketches, queryCounts.length()-1), elapsed); | |
784 } | |
785 } | |
786 | |
787 private String parseRparamSketch(HttpExchange t){ | |
788 //Parse the query from the URL | |
789 String rparam=getRParam(t, false); | |
790 if(rparam!=null){bytesIn.addAndGet(rparam.length());} | |
791 | |
792 if(rparam.length()<1 || rparam.equalsIgnoreCase("help") || rparam.equalsIgnoreCase("usage") || rparam.equalsIgnoreCase("help/") || rparam.equalsIgnoreCase("usage/")){ | |
793 return null; | |
794 } | |
795 | |
796 if(rparam.startsWith("sketch/")){rparam=rparam.substring(7);} | |
797 else if(rparam.equals("sketch")){rparam="";} | |
798 while(rparam.startsWith("/")){rparam=rparam.substring(1);} | |
799 | |
800 //Toggle between local files and sketch transmission | |
801 | |
802 if(rparam.length()<2){ | |
803 params=SketchObject.defaultParams; | |
804 }else{ | |
805 params=SketchObject.defaultParams.clone(); | |
806 String[] args=rparam.split("/"); | |
807 int trimmed=0; | |
808 for(int i=0; i<args.length; i++){//parse rparam | |
809 String arg=args[i]; | |
810 if(arg.length()>0){ | |
811 String[] split=arg.split("="); | |
812 String a=split[0].toLowerCase(); | |
813 String b=split.length>1 ? split[1] : null; | |
814 | |
815 if(a.equals("file")){ | |
816 fileMode=true; | |
817 trimmed+=5; | |
818 break; | |
819 }else if(a.equals("ref") || a.equals("taxid") || a.equals("tid")){ | |
820 refMode=true; | |
821 trimmed+=4; | |
822 break; | |
823 }else if(params.parse(arg, a, b)){ | |
824 trimmed+=arg.length()+1; | |
825 }else{ | |
826 assert(false) : "Bad argument:'"+arg+"'"+"\n"+Arrays.toString(args)+"\n"+rparam; | |
827 } | |
828 } | |
829 } | |
830 params.postParse(true, true); | |
831 // System.err.println("Trimmed="+trimmed+", rparam="+rparam); | |
832 if(trimmed>0){ | |
833 rparam=rparam.substring(Tools.min(trimmed, rparam.length())); | |
834 } | |
835 // System.err.println("rparam="+rparam); | |
836 } | |
837 | |
838 if(verbose2){ | |
839 System.err.println(rparam); | |
840 System.err.println("rparam.startsWith(\"file/\"):"+rparam.startsWith("file/")); | |
841 } | |
842 | |
843 return rparam; | |
844 } | |
845 | |
846 private final HttpExchange t; | |
847 private DisplayParams params; | |
848 private final long instanceStartTime; | |
849 private boolean fileMode=false; | |
850 private boolean refMode=false; | |
851 } | |
852 | |
853 } | |
854 | |
855 private Sketch findRefSketch(String s){ | |
856 assert(s!=null); | |
857 if(s==null || s.length()<1){return null;} | |
858 int tid=-1; | |
859 if(Tools.isDigit(s.charAt(0))){tid=Integer.parseInt(s);} | |
860 else{ | |
861 TaxNode tn=getTaxNodeByName(s); | |
862 tid=tn==null ? -1 : tn.id; | |
863 } | |
864 Sketch sk=tid<0 ? null : searcher.findReferenceSketch(tid); | |
865 if(sk!=null){sk=(Sketch)sk.clone();} | |
866 return sk; | |
867 } | |
868 | |
869 /*--------------------------------------------------------------*/ | |
870 | |
871 /** Handles taxonomy lookups */ | |
872 class TaxHandler implements HttpHandler { | |
873 | |
874 public TaxHandler(boolean skipNonCanonical_){ | |
875 skipNonCanonical=skipNonCanonical_; | |
876 } | |
877 | |
878 @Override | |
879 public void handle(HttpExchange t) throws IOException { | |
880 if(verbose2){System.err.println("Tax handler");} | |
881 final long startTime=System.nanoTime(); | |
882 | |
883 if(sketchOnly){ | |
884 ServerTools.reply("\nERROR: This server is tunning in sketch mode and should not be used for taxonomic lookups.\n" | |
885 + "The taxonomy server is at "+Shared.taxServer()+"\n", "text/plain", t, verbose2, 400, true); | |
886 return; | |
887 } | |
888 | |
889 //Parse the query from the URL | |
890 String rparam=getRParam(t, true); | |
891 | |
892 | |
893 boolean simple=skipNonCanonical; | |
894 | |
895 {//Legacy support for old style of invoking simple | |
896 if(rparam.startsWith("simpletax/")){rparam=rparam.substring(7); simple=true;} | |
897 else if(rparam.startsWith("stax/")){rparam=rparam.substring(5); simple=true;} | |
898 else if(rparam.startsWith("tax/")){rparam=rparam.substring(4);} | |
899 else if(rparam.equals("simpletax") || rparam.equals("stax")){rparam=""; simple=true;} | |
900 else if(rparam.equals("tax")){rparam="";} | |
901 } | |
902 while(rparam.startsWith("/")){rparam=rparam.substring(1);} | |
903 if(rparam.length()<1 || rparam.equalsIgnoreCase("help") || rparam.equalsIgnoreCase("usage")){ | |
904 returnUsage(startTime, t); | |
905 return; | |
906 } | |
907 | |
908 String[] params = rparam.split("/"); | |
909 if(verbose2){System.err.println(Arrays.toString(params));} | |
910 | |
911 final String response=toResponse(simple, params, t); | |
912 final String type=response.startsWith("{") ? "application/json" : "text/plain"; | |
913 | |
914 ServerTools.reply(response, type, t, verbose2, 200, true); | |
915 | |
916 final long stopTime=System.nanoTime(); | |
917 final long elapsed=stopTime-startTime; | |
918 if(response.startsWith("Welcome to ")){ | |
919 timeMeasurementsUsage.incrementAndGet(); | |
920 elapsedTimeUsage.addAndGet(elapsed); | |
921 lastTimeUsage.set(elapsed); | |
922 }else{ | |
923 timeMeasurementsRemote.incrementAndGet(); | |
924 elapsedTimeRemote.addAndGet(elapsed); | |
925 lastTimeRemote.set(elapsed); | |
926 } | |
927 } | |
928 | |
929 //TODO: Integrate something like this to improve parsing | |
930 // String parse(String rparam){ | |
931 // | |
932 // if(rparam.length()<2){return rparam;} | |
933 // | |
934 // String[] args=rparam.split("/"); | |
935 // int trimmed=0; | |
936 // for(int i=0; i<args.length; i++){//parse rparam | |
937 // String arg=args[i]; | |
938 // if(arg.length()>0){ | |
939 // String[] split=arg.split("="); | |
940 // String a=split[0].toLowerCase(); | |
941 // String b=split.length>1 ? split[1] : null; | |
942 // | |
943 // if(a.equals("file")){ | |
944 // fileMode=true; | |
945 // trimmed+=5; | |
946 // break; | |
947 // }else if(params.parse(arg, a, b)){ | |
948 // trimmed+=arg.length()+1; | |
949 // }else{ | |
950 // assert(false) : "Bad argument:'"+arg+"'"+"\n"+Arrays.toString(args)+"\n"+rparam; | |
951 // } | |
952 // } | |
953 // } | |
954 // params.postParse(true); | |
955 // // System.err.println("Trimmed="+trimmed+", rparam="+rparam); | |
956 // if(trimmed>0){ | |
957 // rparam=rparam.substring(Tools.min(trimmed, rparam.length())); | |
958 // } | |
959 // } | |
960 | |
961 /** Only print nodes at canonical tax levels */ | |
962 public final boolean skipNonCanonical; | |
963 } | |
964 | |
965 /*--------------------------------------------------------------*/ | |
966 /*---------------- Helpers ----------------*/ | |
967 /*--------------------------------------------------------------*/ | |
968 | |
969 static String getBody(HttpExchange t){ | |
970 if(verbose2){System.err.println("getBody");} | |
971 InputStream is=t.getRequestBody(); | |
972 String s=ServerTools.readStream(is); | |
973 return s; | |
974 } | |
975 | |
976 /** Parse the query from the URL */ | |
977 static String getRParam(HttpExchange t, boolean allowPost){ | |
978 if(verbose2){System.err.println("getRParam");} | |
979 String rparam = t.getRequestURI().toString(); | |
980 | |
981 //Trim leading slashes | |
982 while(rparam.startsWith("/")){ | |
983 rparam = rparam.substring(1); | |
984 } | |
985 | |
986 //Trim trailing slashes | |
987 while(rparam.endsWith("/")){ | |
988 rparam = rparam.substring(0, rparam.length()-1); | |
989 } | |
990 | |
991 if(allowPost && ("$POST".equalsIgnoreCase(rparam) || "POST".equalsIgnoreCase(rparam))){ | |
992 String body=getBody(t); | |
993 rparam=body; | |
994 } | |
995 | |
996 if(verbose){System.err.println(rparam==null || rparam.trim().length()<1 ? "usage" : rparam+"\t"+System.currentTimeMillis());} | |
997 return rparam; | |
998 } | |
999 | |
1000 /*--------------------------------------------------------------*/ | |
1001 /*---------------- Taxonomy Formatting ----------------*/ | |
1002 /*--------------------------------------------------------------*/ | |
1003 | |
1004 /** All tax queries enter here from the handler */ | |
1005 String toResponse(boolean simple, String[] params, HttpExchange t){ | |
1006 if(verbose2){System.err.println("toResponse");} | |
1007 | |
1008 boolean printNumChildren=false; | |
1009 boolean printChildren=false; | |
1010 boolean printPath=false; | |
1011 boolean printSize=false; | |
1012 boolean printRange=false; | |
1013 boolean silvaHeader=false; | |
1014 boolean plaintext=false, semicolon=false, path=false; | |
1015 boolean mononomial=false; | |
1016 boolean ancestor=false; | |
1017 int source=SOURCE_REFSEQ; | |
1018 | |
1019 ArrayList<String> newParams=new ArrayList<String>(params.length); | |
1020 for(int i=0; i<params.length-1; i++){ | |
1021 String s=params[i]; | |
1022 if(s.length()==0 || s.equals("tax")){ | |
1023 //Do nothing | |
1024 }else if(s.equals("printnumchildren") || s.equals("numchildren")){ | |
1025 printNumChildren=true; | |
1026 }else if(s.equals("printchildren") || s.equals("children")){ | |
1027 printChildren=true; | |
1028 }else if(s.equals("mononomial") || s.equals("cn") | |
1029 || s.equals("fixname") || s.equals("fn") || s.equals("mono") || s.equals("mononomial")){ | |
1030 mononomial=true; | |
1031 }else if(s.equals("printpath") || s.equals("pp")){ | |
1032 printPath=true; | |
1033 }else if(s.equals("printsize") || s.equals("size") || s.equals("ps")){ | |
1034 printSize=true; | |
1035 }else if(s.equals("printrange") || s.equals("range")){ | |
1036 printRange=true; | |
1037 }else if(s.equals("plaintext") || s.equals("pt")){ | |
1038 plaintext=true; semicolon=false; path=false; | |
1039 }else if(s.equals("semicolon") || s.equals("sc")){ | |
1040 semicolon=true; plaintext=false; path=false; | |
1041 }else if(s.equals("path") || s.equals("pa")){ | |
1042 path=true; semicolon=false; plaintext=false; | |
1043 }else if(s.equals("silva")){ | |
1044 silvaHeader=true; | |
1045 source=SOURCE_SILVA; | |
1046 }else if(s.equals("refseq")){ | |
1047 source=SOURCE_REFSEQ; | |
1048 }else if(s.equals("ancestor")){ | |
1049 ancestor=true; | |
1050 }else if(s.equals("simple")){ | |
1051 simple=true; | |
1052 }else{ | |
1053 newParams.add(s); | |
1054 } | |
1055 } | |
1056 newParams.add(params[params.length-1]); | |
1057 params=newParams.toArray(new String[newParams.size()]); | |
1058 | |
1059 // System.err.println("mononomial="+mononomial); | |
1060 | |
1061 if(params.length<2){ | |
1062 if(params.length==1 && "advice".equalsIgnoreCase(params[0])){return TAX_ADVICE;} | |
1063 if(logUsage){System.err.println("usage");} | |
1064 return USAGE(USAGE); | |
1065 } | |
1066 if(params.length>3){ | |
1067 if(logUsage){System.err.println("usage");} | |
1068 return USAGE(USAGE); | |
1069 } | |
1070 | |
1071 final String query=params[params.length-1]; | |
1072 final String[] names=query.split(","); | |
1073 if(names==null){return USAGE(USAGE);} | |
1074 | |
1075 if(names==null || names.length<2){ | |
1076 firstChunkSingle.incrementAndGet(); | |
1077 }else{ | |
1078 firstChunkMulti.incrementAndGet(); | |
1079 } | |
1080 bulkCount.addAndGet(names.length); | |
1081 // System.err.println(params[2]+", "+ancestor); | |
1082 | |
1083 //Raw query type code | |
1084 final int type; | |
1085 //Type code excluding formatting | |
1086 final int type2; | |
1087 { | |
1088 String typeS=params[0]; | |
1089 Integer value=typeMap.get(typeS); | |
1090 if(value==null){ | |
1091 if(typeS.equalsIgnoreCase("advice")){ | |
1092 return TAX_ADVICE; | |
1093 }else{ | |
1094 return "{\"error\": \"Bad type ("+typeS+"); should be gi, taxid, or name.\"}"; | |
1095 } | |
1096 } | |
1097 int x=value.intValue(); | |
1098 if((x&15)==HEADER && silvaHeader){x=SILVAHEADER;} | |
1099 type=x; | |
1100 type2=x&15; | |
1101 if(type2==IMG){source=SOURCE_IMG;} | |
1102 } | |
1103 | |
1104 plaintext=(type>=PT_BIT || plaintext); | |
1105 semicolon=(type>=SC_BIT || semicolon); | |
1106 path=(type>=PA_BIT || path); | |
1107 if(semicolon || path){plaintext=false;} | |
1108 if(path){semicolon=false;} | |
1109 | |
1110 final boolean internal=incrementQueries(t, false, false, simple, ancestor, | |
1111 plaintext, semicolon, path, printChildren, printPath, printSize, type); //Ignores usage information. | |
1112 | |
1113 // if(type2==GI){//123 | |
1114 // return "{\"error\": \"GI number support is temporarily suspended due to conflicts in NCBI databases. " | |
1115 // + "It may come back split into nucleotide and protein GI numbers, which currently are not exclusive.\"}"; | |
1116 // } | |
1117 | |
1118 if(!internal && !allowRemoteFileAccess){ | |
1119 path=printPath=false; | |
1120 } | |
1121 | |
1122 if(verbose2){System.err.println("Type: "+type);} | |
1123 if(type2==NAME || type2==HEADER || type2==SILVAHEADER){ | |
1124 for(int i=0; i<names.length; i++){ | |
1125 names[i]=PercentEncoding.codeToSymbol(names[i]); | |
1126 if(type2==HEADER || type2==SILVAHEADER){ | |
1127 if(names[i].startsWith("@") || names[i].startsWith(">")){names[i]=names[i].substring(1);} | |
1128 } | |
1129 } | |
1130 if(verbose2){System.err.println("Revised: "+Arrays.toString(names));} | |
1131 } | |
1132 | |
1133 if(ancestor){ | |
1134 if(verbose2){System.err.println("toAncestor: "+Arrays.toString(names));} | |
1135 return toAncestor(type, names, plaintext, semicolon, path, query, simple, !simple, printNumChildren, printChildren, printPath, printSize, printRange, mononomial, source); | |
1136 } | |
1137 | |
1138 if(semicolon){ | |
1139 return toSemicolon(type, names, simple, mononomial); | |
1140 }else if(plaintext){ | |
1141 return toText(type, names); | |
1142 }else if(path){ | |
1143 return toPath(type, names, source); | |
1144 } | |
1145 | |
1146 JsonObject j=new JsonObject(); | |
1147 for(String name : names){ | |
1148 j.add(name, toJson(type, name, simple, !simple, printNumChildren, printChildren, | |
1149 printPath, printSize, printRange, mononomial, source)); | |
1150 } | |
1151 return j.toString(); | |
1152 } | |
1153 | |
1154 /** Look up common ancestor of terms */ | |
1155 String toAncestor(final int type, final String[] names, boolean plaintext, boolean semicolon, boolean path, | |
1156 String query, final boolean skipNonCanonical, boolean originalLevel, boolean printNumChildren, | |
1157 boolean printChildren, boolean printPath, boolean printSize, boolean printRange, boolean mononomial, | |
1158 int source){ | |
1159 IntList ilist=toIntList(type, names); | |
1160 int id=FindAncestor.findAncestor(tree, ilist); | |
1161 TaxNode tn=(id>-1 ? tree.getNode(id) : null); | |
1162 if(tn==null){ | |
1163 return new JsonObject("error","Not found.").toString(query); | |
1164 } | |
1165 if(semicolon){ | |
1166 return tree.toSemicolon(tn, skipNonCanonical, mononomial); | |
1167 }else if(plaintext){ | |
1168 return ""+id; | |
1169 }else if(path){ | |
1170 return toPath(tn, source); | |
1171 } | |
1172 | |
1173 JsonObject j=new JsonObject(); | |
1174 // j.add("name", mononomial ? tree.mononomial(tn) : tn.name); | |
1175 j.add("name", tn.name); | |
1176 if(mononomial || true){ | |
1177 String mono=tree.mononomial(tn); | |
1178 if(tn.name!=mono){j.add("mononomial", mono);} | |
1179 } | |
1180 j.add("tax_id", tn.id); | |
1181 if(printNumChildren){j.add("num_children", tn.numChildren);} | |
1182 if(printPath){j.add("path", toPath(tn, source));} | |
1183 if(printSize){ | |
1184 j.add("size", tree.toSize(tn)); | |
1185 j.add("cumulative_size", tree.toSizeC(tn)); | |
1186 j.add("seqs", tree.toSeqs(tn)); | |
1187 j.add("cumulative_seqs", tree.toSeqsC(tn)); | |
1188 j.add("cumulative_nodes", tree.toNodes(tn)); | |
1189 } | |
1190 j.add("level", tn.levelStringExtended(originalLevel)); | |
1191 if(tn.levelExtended<1 && printRange){ | |
1192 j.add("maxDescendent", TaxTree.levelToStringExtended(tn.maxChildLevelExtended)); | |
1193 j.add("minAncestor", TaxTree.levelToStringExtended(tn.minParentLevelExtended)); | |
1194 } | |
1195 // if(printChildren){j.add(getChildren(id, originalLevel, printRange));} | |
1196 while(tn!=null && tn.levelExtended!=TaxTree.LIFE_E && tn.id!=TaxTree.CELLULAR_ORGANISMS_ID){ | |
1197 if(!skipNonCanonical || tn.isSimple()){ | |
1198 j.addAndRename(tn.levelStringExtended(originalLevel), toJson(tn, originalLevel, printNumChildren, printChildren, printPath, printSize, printRange, mononomial, source, -1)); | |
1199 } | |
1200 if(tn.pid==tn.id){break;} | |
1201 tn=tree.getNode(tn.pid); | |
1202 } | |
1203 return j.toString(); | |
1204 } | |
1205 | |
1206 JsonObject getChildren(final int id, boolean originalLevel, boolean printRange, boolean mononomial){ | |
1207 TaxNode x=tree.getNode(id); | |
1208 if(x==null || x.numChildren==0){return null;} | |
1209 ArrayList<TaxNode> list=tree.getChildren(x); | |
1210 return makeChildrenObject(list, originalLevel, printRange, mononomial); | |
1211 } | |
1212 | |
1213 JsonObject makeChildrenObject(ArrayList<TaxNode> list, boolean originalLevel, boolean printRange, boolean mononomial){ | |
1214 if(list==null || list.isEmpty()){return null;} | |
1215 JsonObject j=new JsonObject(); | |
1216 for(TaxNode tn : list){ | |
1217 JsonObject child=new JsonObject(); | |
1218 // child.add("name", mononomial ? tree.mononomial(tn) : tn.name); | |
1219 child.add("name", tn.name); | |
1220 if(mononomial || true){ | |
1221 String mono=tree.mononomial(tn); | |
1222 if(tn.name!=mono){child.add("mononomial", mono);} | |
1223 } | |
1224 child.add("tax_id", tn.id); | |
1225 child.add("num_children", tn.numChildren); | |
1226 child.add("level", tn.levelStringExtended(originalLevel)); | |
1227 if(tn.levelExtended<1 && printRange){ | |
1228 child.add("maxDescendent", TaxTree.levelToStringExtended(tn.maxChildLevelExtended)); | |
1229 child.add("minAncestor", TaxTree.levelToStringExtended(tn.minParentLevelExtended)); | |
1230 } | |
1231 j.add(tn.id+"", child); | |
1232 } | |
1233 return j; | |
1234 } | |
1235 | |
1236 /** Format a reply as plaintext, comma-delimited, TaxID only */ | |
1237 String toText(final int type, final String[] names){ | |
1238 | |
1239 StringBuilder sb=new StringBuilder(); | |
1240 String comma=""; | |
1241 | |
1242 int type2=type&15; | |
1243 if(type2==GI){ | |
1244 for(String name : names){ | |
1245 sb.append(comma); | |
1246 TaxNode tn=getTaxNodeGi(Long.parseLong(name)); | |
1247 if(tn==null){sb.append("-1");} | |
1248 else{sb.append(tn.id);} | |
1249 comma=","; | |
1250 } | |
1251 }else if(type2==NAME){ | |
1252 for(String name : names){ | |
1253 sb.append(comma); | |
1254 TaxNode tn=getTaxNodeByName(name); | |
1255 if(tn==null){sb.append("-1");} | |
1256 else{sb.append(tn.id);} | |
1257 comma=","; | |
1258 } | |
1259 }else if(type2==TAXID){ | |
1260 for(String name : names){ | |
1261 sb.append(comma); | |
1262 TaxNode tn=getTaxNodeTaxid(Integer.parseInt(name)); | |
1263 if(tn==null){sb.append("-1");} | |
1264 else{sb.append(tn.id);} | |
1265 comma=","; | |
1266 } | |
1267 }else if(type2==ACCESSION){ | |
1268 for(String name : names){ | |
1269 sb.append(comma); | |
1270 int ncbi=accessionToTaxid(name); | |
1271 sb.append(ncbi); | |
1272 comma=","; | |
1273 } | |
1274 }else if(type2==HEADER || type2==SILVAHEADER){ | |
1275 for(String name : names){ | |
1276 sb.append(comma); | |
1277 TaxNode tn=getTaxNodeHeader(name, type2==SILVAHEADER); | |
1278 if(tn==null){sb.append("-1");} | |
1279 else{sb.append(tn.id);} | |
1280 comma=","; | |
1281 } | |
1282 }else if(type2==IMG){ | |
1283 for(String name : names){ | |
1284 sb.append(comma); | |
1285 int ncbi=TaxTree.imgToTaxid(Long.parseLong(name)); | |
1286 sb.append(ncbi); | |
1287 comma=","; | |
1288 } | |
1289 }else{ | |
1290 return "Bad type; should be pt_gi or pt_name; e.g. /pt_gi/1234"; | |
1291 } | |
1292 | |
1293 return sb.toString(); | |
1294 } | |
1295 | |
1296 private TaxNode toNode(final int type, final String name){ | |
1297 int type2=type&15; | |
1298 final TaxNode tn; | |
1299 if(type2==GI){ | |
1300 tn=getTaxNodeGi(Long.parseLong(name)); | |
1301 }else if(type2==NAME){ | |
1302 tn=getTaxNodeByName(name); | |
1303 }else if(type2==TAXID){ | |
1304 tn=getTaxNodeTaxid(Integer.parseInt(name)); | |
1305 }else if(type2==ACCESSION){ | |
1306 int ncbi=accessionToTaxid(name); | |
1307 tn=(ncbi<0 ? null : tree.getNode(ncbi)); | |
1308 }else if(type2==HEADER || type2==SILVAHEADER){ | |
1309 tn=getTaxNodeHeader(name, type2==SILVAHEADER); | |
1310 }else if(type2==IMG){ | |
1311 int ncbi=TaxTree.imgToTaxid(Long.parseLong(name)); | |
1312 tn=(ncbi<0 ? null : tree.getNode(ncbi)); | |
1313 }else{ | |
1314 tn=null; | |
1315 } | |
1316 return tn; | |
1317 } | |
1318 | |
1319 /** Format a reply as paths, comma-delimited*/ | |
1320 String toPath(final int type, final String[] names, final int source){ | |
1321 | |
1322 StringBuilder sb=new StringBuilder(); | |
1323 String comma=""; | |
1324 | |
1325 int type2=type&15; | |
1326 | |
1327 for(String name : names){ | |
1328 sb.append(comma); | |
1329 if(type2==IMG){ | |
1330 sb.append(toPathIMG(Long.parseLong(name))); | |
1331 }else{ | |
1332 TaxNode tn=toNode(type2, name); | |
1333 sb.append(toPath(tn, source)); | |
1334 } | |
1335 comma=","; | |
1336 } | |
1337 | |
1338 return sb.toString(); | |
1339 } | |
1340 | |
1341 /** Format a reply as plaintext, semicolon-delimited, full lineage */ | |
1342 String toSemicolon(final int type, final String[] names, boolean skipNonCanonical, boolean mononomial){ | |
1343 | |
1344 StringBuilder sb=new StringBuilder(); | |
1345 String comma=""; | |
1346 | |
1347 int type2=type&15; | |
1348 if(type2==GI){ | |
1349 for(String name : names){ | |
1350 sb.append(comma); | |
1351 TaxNode tn=getTaxNodeGi(Long.parseLong(name)); | |
1352 if(tn==null){sb.append("Not found");} | |
1353 else{sb.append(tree.toSemicolon(tn, skipNonCanonical, mononomial));} | |
1354 comma=","; | |
1355 } | |
1356 }else if(type2==NAME){ | |
1357 for(String name : names){ | |
1358 sb.append(comma); | |
1359 TaxNode tn=getTaxNodeByName(name); | |
1360 if(tn==null){sb.append("Not found");} | |
1361 else{sb.append(tree.toSemicolon(tn, skipNonCanonical, mononomial));} | |
1362 comma=","; | |
1363 } | |
1364 }else if(type2==TAXID){ | |
1365 for(String name : names){ | |
1366 sb.append(comma); | |
1367 TaxNode tn=getTaxNodeTaxid(Integer.parseInt(name)); | |
1368 // if(verbose2){outstream.println("name="+name+", tn="+tn);} | |
1369 if(tn==null){sb.append("Not found");} | |
1370 else{sb.append(tree.toSemicolon(tn, skipNonCanonical, mononomial));} | |
1371 comma=","; | |
1372 } | |
1373 }else if(type2==ACCESSION){ | |
1374 for(String name : names){ | |
1375 sb.append(comma); | |
1376 final int tid=accessionToTaxid(name); | |
1377 TaxNode tn=tree.getNode(tid, true); | |
1378 if(tn==null){sb.append("Not found");} | |
1379 else{sb.append(tree.toSemicolon(tn, skipNonCanonical, mononomial));} | |
1380 comma=","; | |
1381 } | |
1382 }else if(type2==HEADER || type2==SILVAHEADER){ | |
1383 for(String name : names){ | |
1384 sb.append(comma); | |
1385 TaxNode tn=getTaxNodeHeader(name, type2==SILVAHEADER); | |
1386 if(tn==null){sb.append("Not found");} | |
1387 else{sb.append(tree.toSemicolon(tn, skipNonCanonical, mononomial));} | |
1388 comma=","; | |
1389 } | |
1390 }else if(type2==IMG){ | |
1391 for(String name : names){ | |
1392 sb.append(comma); | |
1393 final int tid=TaxTree.imgToTaxid(Long.parseLong(name)); | |
1394 TaxNode tn=tree.getNode(tid, true); | |
1395 if(tn==null){sb.append("Not found");} | |
1396 else{sb.append(tree.toSemicolon(tn, skipNonCanonical, mononomial));} | |
1397 comma=","; | |
1398 } | |
1399 }else{ | |
1400 return "Bad type; should be sc_gi or sc_name; e.g. /sc_gi/1234"; | |
1401 } | |
1402 | |
1403 // if(verbose2){outstream.println("In toSemicolon; type="+type+", type2="+type2+", made "+sb);} | |
1404 | |
1405 return sb.toString(); | |
1406 } | |
1407 | |
1408 /** Create a JsonObject from a String, including full lineage */ | |
1409 JsonObject toJson(final int type, final String name, boolean skipNonCanonical, boolean originalLevel, | |
1410 boolean printNumChildren, boolean printChildren, boolean printPath, boolean printSize, | |
1411 boolean printRange, boolean mononomial, int source){ | |
1412 final TaxNode tn0; | |
1413 TaxNode tn; | |
1414 | |
1415 long img=-1; | |
1416 if(type==GI){ | |
1417 tn0=getTaxNodeGi(Long.parseLong(name)); | |
1418 }else if(type==NAME){ | |
1419 tn0=getTaxNodeByName(name); | |
1420 }else if(type==TAXID){ | |
1421 tn0=getTaxNodeTaxid(Integer.parseInt(name)); | |
1422 }else if(type==ACCESSION){ | |
1423 int ncbi=accessionToTaxid(name); | |
1424 tn0=(ncbi>=0 ? tree.getNode(ncbi) : null); | |
1425 }else if(type==HEADER || type==SILVAHEADER){ | |
1426 tn0=getTaxNodeHeader(name, type==SILVAHEADER); | |
1427 }else if(type==IMG){ | |
1428 img=Long.parseLong(name); | |
1429 final int tid=TaxTree.imgToTaxid(img); | |
1430 tn0=tree.getNode(tid, true); | |
1431 }else{ | |
1432 JsonObject j=new JsonObject("error","Bad type; should be gi, taxid, or name; e.g. /name/homo_sapiens"); | |
1433 j.add("name", name); | |
1434 j.add("type", type); | |
1435 return j; | |
1436 } | |
1437 tn=tn0; | |
1438 if(verbose2){System.err.println("Got node: "+tn);} | |
1439 | |
1440 if(tn!=null){ | |
1441 JsonObject j=new JsonObject(); | |
1442 // j.add("name", mononomial ? tree.mononomial(tn) : tn.name); | |
1443 j.add("name", tn.name); | |
1444 if(mononomial || true){ | |
1445 String mono=tree.mononomial(tn); | |
1446 if(tn.name!=mono){j.add("mononomial", mono);} | |
1447 } | |
1448 j.add("tax_id", tn.id); | |
1449 if(printNumChildren){j.add("num_children", tn.numChildren);} | |
1450 if(printPath){j.add("path", type==IMG ? toPathIMG(img) : toPath(tn, source));} | |
1451 if(printSize){ | |
1452 j.add("size", tree.toSize(tn)); | |
1453 j.add("cumulative_size", tree.toSizeC(tn)); | |
1454 j.add("seqs", tree.toSeqs(tn)); | |
1455 j.add("cumulative_seqs", tree.toSeqsC(tn)); | |
1456 j.add("cumulative_nodes", tree.toNodes(tn)); | |
1457 } | |
1458 j.add("level", tn.levelStringExtended(originalLevel)); | |
1459 if(tn.levelExtended<1 && printRange){ | |
1460 j.add("maxDescendent", TaxTree.levelToStringExtended(tn.maxChildLevelExtended)); | |
1461 j.add("minAncestor", TaxTree.levelToStringExtended(tn.minParentLevelExtended)); | |
1462 } | |
1463 if(printChildren && (tn.id==tn.pid || tn.id==TaxTree.CELLULAR_ORGANISMS_ID)){j.add("children", getChildren(tn.id, originalLevel, printRange, mononomial));} | |
1464 while(tn!=null && tn.levelExtended!=TaxTree.LIFE_E && tn.id!=TaxTree.CELLULAR_ORGANISMS_ID){ | |
1465 // System.err.println(tn+", "+(!skipNonCanonical)+", "+tn.isSimple()); | |
1466 if(!skipNonCanonical || tn.isSimple()){ | |
1467 j.addAndRename(tn.levelStringExtended(originalLevel), toJson(tn, originalLevel, printNumChildren, printChildren, printPath && tn==tn0, printSize, printRange, mononomial, source, img)); | |
1468 // System.err.println(j); | |
1469 } | |
1470 if(tn.pid==tn.id){break;} | |
1471 tn=tree.getNode(tn.pid); | |
1472 } | |
1473 return j; | |
1474 } | |
1475 { | |
1476 JsonObject j=new JsonObject("error","Not found."); | |
1477 j.add("name", name); | |
1478 j.add("type", type); | |
1479 return j; | |
1480 } | |
1481 } | |
1482 | |
1483 /** Create a JsonObject from a TaxNode, at that level only */ | |
1484 JsonObject toJson(TaxNode tn, boolean originalLevel, boolean printNumChildren, | |
1485 boolean printChildren, boolean printPath, boolean printSize, boolean printRange, | |
1486 boolean mononomial, int source, long img){ | |
1487 JsonObject j=new JsonObject(); | |
1488 // j.add("name", mononomial ? tree.mononomial(tn) : tn.name); | |
1489 j.add("name", tn.name); | |
1490 if(mononomial || true){ | |
1491 String mono=tree.mononomial(tn); | |
1492 if(tn.name!=mono){j.add("mononomial", mono);} | |
1493 } | |
1494 j.add("tax_id", tn.id); | |
1495 if(printNumChildren){j.add("num_children", tn.numChildren);} | |
1496 if(printPath){j.add("path", source==SOURCE_IMG ? toPathIMG(img) : toPath(tn, source));} | |
1497 if(printSize){ | |
1498 j.add("size", tree.toSize(tn)); | |
1499 j.add("cumulative_size", tree.toSizeC(tn)); | |
1500 j.add("seqs", tree.toSeqs(tn)); | |
1501 j.add("cumulative_seqs", tree.toSeqsC(tn)); | |
1502 j.add("cumulative_nodes", tree.toNodes(tn)); | |
1503 } | |
1504 if(tn.levelExtended<1 && printRange){ | |
1505 j.add("maxDescendent", TaxTree.levelToStringExtended(tn.maxChildLevelExtended)); | |
1506 j.add("minAncestor", TaxTree.levelToStringExtended(tn.minParentLevelExtended)); | |
1507 } | |
1508 if(printChildren){ | |
1509 JsonObject children=getChildren(tn.id, originalLevel, printRange, mononomial); | |
1510 if(children!=null){j.add("children", children);} | |
1511 } | |
1512 return j; | |
1513 } | |
1514 | |
1515 String toPath(TaxNode tn, int source){ | |
1516 if(tn==null){return "null";} | |
1517 String path; | |
1518 if(source==SOURCE_REFSEQ){ | |
1519 path=tree.toDir(tn, basePath)+"refseq_"+tn.id+".fa.gz"; | |
1520 }else if(source==SOURCE_SILVA){ | |
1521 path=tree.toDir(tn, basePath)+"silva_"+tn.id+".fa.gz"; | |
1522 }else if(source==SOURCE_IMG){ | |
1523 assert(false); | |
1524 path="null"; | |
1525 }else{ | |
1526 assert(false); | |
1527 path="null"; | |
1528 } | |
1529 if(!path.equals("null") && !new File(path).exists()){path="null";} | |
1530 return path; | |
1531 } | |
1532 | |
1533 String toPathIMG(long imgID){ | |
1534 String path="/global/dna/projectdirs/microbial/img_web_data/taxon.fna/"+imgID+".fna"; | |
1535 if(!new File(path).exists()){path="null";} | |
1536 return path; | |
1537 } | |
1538 | |
1539 /*--------------------------------------------------------------*/ | |
1540 /*---------------- Taxonomy Lookup ----------------*/ | |
1541 /*--------------------------------------------------------------*/ | |
1542 | |
1543 /** Convert a list of terms to a list of TaxIDs */ | |
1544 IntList toIntList(final int type, final String[] names){ | |
1545 IntList list=new IntList(names.length); | |
1546 int type2=type&15; | |
1547 if(type2==GI){ | |
1548 for(String name : names){ | |
1549 TaxNode tn=getTaxNodeGi(Long.parseLong(name)); | |
1550 if(tn!=null){list.add(tn.id);} | |
1551 else{notFound.incrementAndGet();} | |
1552 } | |
1553 }else if(type2==NAME){ | |
1554 for(String name : names){ | |
1555 TaxNode tn=getTaxNodeByName(name); | |
1556 if(tn!=null){list.add(tn.id);} | |
1557 else{notFound.incrementAndGet();} | |
1558 } | |
1559 }else if(type2==TAXID){ | |
1560 for(String name : names){ | |
1561 TaxNode tn=getTaxNodeTaxid(Integer.parseInt(name)); | |
1562 if(tn!=null){list.add(tn.id);} | |
1563 else{notFound.incrementAndGet();} | |
1564 } | |
1565 }else if(type2==ACCESSION){ | |
1566 for(String name : names){ | |
1567 int ncbi=accessionToTaxid(name); | |
1568 if(ncbi>=0){list.add(ncbi);} | |
1569 else{notFound.incrementAndGet();} | |
1570 } | |
1571 }else if(type2==IMG){ | |
1572 for(String name : names){ | |
1573 final int tid=TaxTree.imgToTaxid(Long.parseLong(name)); | |
1574 if(tid>=0){list.add(tid);} | |
1575 else{notFound.incrementAndGet();} | |
1576 } | |
1577 }else{ | |
1578 throw new RuntimeException("{\"error\": \"Bad type\"}"); | |
1579 } | |
1580 return list; | |
1581 } | |
1582 | |
1583 public static final String stripAccession(String s){ | |
1584 if(s==null){return null;} | |
1585 s=s.toUpperCase(); | |
1586 for(int i=0; i<s.length(); i++){ | |
1587 char c=s.charAt(i); | |
1588 if(c=='.' || c==':'){return s.substring(0, i);} | |
1589 } | |
1590 return s; | |
1591 } | |
1592 | |
1593 private int accessionToTaxid(String accession){ | |
1594 if(accession==null){return -1;} | |
1595 int tid=AccessionToTaxid.get(accession); | |
1596 if(tid<0 && distributed && serverNum==0){ | |
1597 accession=stripAccession(accession); | |
1598 int slaveNum=accession.hashCode()%serverCount; | |
1599 if(slaveNum!=serverNum){ | |
1600 String path=slaveAddress.get(slaveNum); | |
1601 tid=TaxClient.accessionToTaxidSpecificServer(path, accession); | |
1602 } | |
1603 } | |
1604 return tid; | |
1605 } | |
1606 | |
1607 /** Look up a TaxNode by parsing the organism name */ | |
1608 TaxNode getTaxNodeByName(String name){ | |
1609 if(verbose2){System.err.println("Fetching node for "+name);} | |
1610 List<TaxNode> list=tree.getNodesByNameExtended(name); | |
1611 if(verbose2){System.err.println("Fetched "+list);} | |
1612 if(list==null){ | |
1613 if(verbose2){System.err.println("Fetched in common map "+name);} | |
1614 String name2=commonMap.get(name); | |
1615 if(verbose2){System.err.println("Fetched "+name2);} | |
1616 if(name2!=null){list=tree.getNodesByName(name2);} | |
1617 } | |
1618 if(list==null){notFound.incrementAndGet();} | |
1619 return list==null ? null : list.get(0); | |
1620 } | |
1621 | |
1622 /** Look up a TaxNode from the gi number */ | |
1623 TaxNode getTaxNodeGi(long gi){ | |
1624 int ncbi=-1; | |
1625 try { | |
1626 ncbi=GiToTaxid.getID(gi); | |
1627 } catch (Throwable e) { | |
1628 if(verbose){e.printStackTrace();} | |
1629 } | |
1630 if(ncbi<0){notFound.incrementAndGet();} | |
1631 return ncbi<0 ? null : getTaxNodeTaxid(ncbi); | |
1632 } | |
1633 | |
1634 /** Look up a TaxNode by parsing the full header */ | |
1635 TaxNode getTaxNodeHeader(String header, boolean silvaMode){ | |
1636 TaxNode tn=silvaMode ? tree.getNodeSilva(header, true) : tree.parseNodeFromHeader(header, true); | |
1637 if(tn==null){notFound.incrementAndGet();} | |
1638 return tn; | |
1639 } | |
1640 | |
1641 /** Look up a TaxNode from the ncbi TaxID */ | |
1642 TaxNode getTaxNodeTaxid(int ncbi){ | |
1643 TaxNode tn=null; | |
1644 try { | |
1645 tn=tree.getNode(ncbi); | |
1646 } catch (Throwable e) { | |
1647 if(verbose){e.printStackTrace();} | |
1648 } | |
1649 if(tn==null){notFound.incrementAndGet();} | |
1650 return tn; | |
1651 } | |
1652 | |
1653 /*--------------------------------------------------------------*/ | |
1654 /*---------------- Data Initialization ----------------*/ | |
1655 /*--------------------------------------------------------------*/ | |
1656 | |
1657 private static HashMap<String, Integer> makeTypeMap() { | |
1658 HashMap<String, Integer> map=new HashMap<String, Integer>(63); | |
1659 map.put("gi", GI); | |
1660 // map.put("ngi", NGI); | |
1661 // map.put("pgi", PGI); | |
1662 map.put("name", NAME); | |
1663 map.put("tax_id", TAXID); | |
1664 map.put("ncbi", TAXID); | |
1665 map.put("taxid", TAXID); | |
1666 map.put("id", TAXID); | |
1667 map.put("tid", TAXID); | |
1668 map.put("header", HEADER); | |
1669 map.put("accession", ACCESSION); | |
1670 map.put("img", IMG); | |
1671 map.put("silvaheader", SILVAHEADER); | |
1672 | |
1673 map.put("pt_gi", PT_GI); | |
1674 // map.put("pt_ngi", PT_NGI); | |
1675 // map.put("pt_pgi", PT_PGI); | |
1676 map.put("pt_name", PT_NAME); | |
1677 map.put("pt_tax_id", PT_TAXID); | |
1678 map.put("pt_id", PT_TAXID); | |
1679 map.put("pt_tid", PT_TAXID); | |
1680 map.put("pt_ncbi", PT_TAXID); | |
1681 map.put("pt_taxid", PT_TAXID); | |
1682 map.put("pt_header", PT_HEADER); | |
1683 map.put("pt_header", PT_HEADER); | |
1684 map.put("pt_accession", PT_ACCESSION); | |
1685 map.put("pt_img", PT_IMG); | |
1686 map.put("pt_silvaheader", PT_SILVAHEADER); | |
1687 | |
1688 map.put("sc_gi", SC_GI); | |
1689 // map.put("sc_ngi", SC_NGI); | |
1690 // map.put("sc_pgi", SC_PGI); | |
1691 map.put("sc_name", SC_NAME); | |
1692 map.put("sc_tax_id", SC_TAXID); | |
1693 map.put("sc_id", SC_TAXID); | |
1694 map.put("sc_tid", SC_TAXID); | |
1695 map.put("sc_ncbi", SC_TAXID); | |
1696 map.put("sc_taxid", SC_TAXID); | |
1697 map.put("sc_header", SC_HEADER); | |
1698 map.put("sc_header", SC_HEADER); | |
1699 map.put("sc_accession", SC_ACCESSION); | |
1700 map.put("sc_silvaheader", SC_SILVAHEADER); | |
1701 | |
1702 return map; | |
1703 } | |
1704 | |
1705 public static HashMap<String, String> makeCommonMap(){ | |
1706 HashMap<String, String> map=new HashMap<String, String>(); | |
1707 map.put("human", "homo sapiens"); | |
1708 map.put("cat", "felis catus"); | |
1709 map.put("dog", "canis lupus familiaris"); | |
1710 map.put("mouse", "mus musculus"); | |
1711 map.put("cow", "bos taurus"); | |
1712 map.put("bull", "bos taurus"); | |
1713 map.put("horse", "Equus ferus"); | |
1714 map.put("pig", "Sus scrofa domesticus"); | |
1715 map.put("sheep", "Ovis aries"); | |
1716 map.put("goat", "Capra aegagrus"); | |
1717 map.put("turkey", "Meleagris gallopavo"); | |
1718 map.put("fox", "Vulpes vulpes"); | |
1719 map.put("chicken", "Gallus gallus domesticus"); | |
1720 map.put("wolf", "canis lupus"); | |
1721 map.put("fruitfly", "drosophila melanogaster"); | |
1722 map.put("zebrafish", "Danio rerio"); | |
1723 map.put("catfish", "Ictalurus punctatus"); | |
1724 map.put("trout", "Oncorhynchus mykiss"); | |
1725 map.put("salmon", "Salmo salar"); | |
1726 map.put("tilapia", "Oreochromis niloticus"); | |
1727 map.put("e coli", "Escherichia coli"); | |
1728 map.put("e.coli", "Escherichia coli"); | |
1729 | |
1730 map.put("lion", "Panthera leo"); | |
1731 map.put("tiger", "Panthera tigris"); | |
1732 map.put("bear", "Ursus arctos"); | |
1733 map.put("deer", "Odocoileus virginianus"); | |
1734 map.put("coyote", "Canis latrans"); | |
1735 | |
1736 map.put("corn", "Zea mays subsp. mays"); | |
1737 map.put("maize", "Zea mays subsp. mays"); | |
1738 map.put("oat", "Avena sativa"); | |
1739 map.put("wheat", "Triticum aestivum"); | |
1740 map.put("rice", "Oryza sativa"); | |
1741 map.put("potato", "Solanum tuberosum"); | |
1742 map.put("barley", "Hordeum vulgare"); | |
1743 map.put("poplar", "Populus alba"); | |
1744 map.put("lettuce", "Lactuca sativa"); | |
1745 map.put("beet", "Beta vulgaris"); | |
1746 map.put("strawberry", "Fragaria x ananassa"); | |
1747 map.put("orange", "Citrus sinensis"); | |
1748 map.put("lemon", "Citrus limon"); | |
1749 map.put("soy", "Glycine max"); | |
1750 map.put("soybean", "Glycine max"); | |
1751 map.put("grape", "Vitis vinifera"); | |
1752 map.put("olive", "Olea europaea"); | |
1753 map.put("cotton", "Gossypium hirsutum"); | |
1754 map.put("apple", "Malus pumila"); | |
1755 map.put("bannana", "Musa acuminata"); | |
1756 map.put("tomato", "Solanum lycopersicum"); | |
1757 map.put("sugarcane", "Saccharum officinarum"); | |
1758 map.put("bean", "Phaseolus vulgaris"); | |
1759 map.put("onion", "Allium cepa"); | |
1760 map.put("garlic", "Allium sativum"); | |
1761 | |
1762 map.put("pichu", "mus musculus"); | |
1763 map.put("pikachu", "mus musculus"); | |
1764 map.put("vulpix", "Vulpes vulpes"); | |
1765 map.put("ninetails", "Vulpes vulpes"); | |
1766 map.put("mareep", "Ovis aries"); | |
1767 | |
1768 return map; | |
1769 } | |
1770 | |
1771 //Customize usage message to include domain | |
1772 private String makeUsagePrefix(){ | |
1773 if(!sketchOnly){ | |
1774 return "Welcome to the JGI taxonomy server!\n" | |
1775 + "This service provides taxonomy information from NCBI taxID numbers, gi numbers, organism names, and accessions.\n" | |
1776 + "The output is formatted as a Json object.\n\n" | |
1777 + "Usage:\n\n" | |
1778 + "All addresses below are assumed to be prefixed by "+domain+", e.g. /name/homo_sapiens implies a full URL of:\n" | |
1779 + domain+"/name/homo_sapiens\n" | |
1780 + "\n" | |
1781 + "/name/homo_sapiens will give taxonomy information for an organism name.\n" | |
1782 + "Names are case-insensitive and underscores are equivalent to spaces.\n" | |
1783 + "/id/9606 will give taxonomy information for an NCBI taxID.\n" | |
1784 + "/gi/1234 will give taxonomy information from an NCBI gi number.\n" | |
1785 | |
1786 // + "\n****NOTICE**** gi number support is temporarily suspended due to conflicts in NCBI data.\n" | |
1787 // + "Support may be restored, altered, or discontinued pending a response from NCBI.\n" | |
1788 // + "Currently, it is not possible to ensure correct results when looking up a GI number, because some map to multiple organisms.\n\n" | |
1789 | |
1790 + "/accession/NZ_AAAA01000057.1 will give taxonomy information from an accession.\n" | |
1791 + "/header/ will accept an NCBI sequence header such as gi|7|emb|X51700.1| Bos taurus\n" | |
1792 + "/silvaheader/ will accept a Silva sequence header such as KC415233.1.1497 Bacteria;Spirochaetae;Spirochaetes\n" | |
1793 + "/img/ will accept an IMG id such as 2724679250\n" | |
1794 + "Vertical bars (|) may cause problems on the command line and can be replaced by tilde (~).\n" | |
1795 + "\nComma-delimited lists are accepted for bulk queries, such as tax/gi/1234,7000,42\n" | |
1796 + "For plaintext (non-Json) results, add the term /pt/ or /sc/.\n" | |
1797 + "pt will give just the taxID, while sc will give the whole lineage, semicolon-delimited. For example:\n" | |
1798 + "/pt/name/homo_sapiens\n" | |
1799 + "/sc/gi/1234\n\n" | |
1800 + "Additional supported display options are children, numchildren, range, simple, path, size, and ancestor.\n" | |
1801 + "The order is not important but they need to come before the query term. For example:\n" | |
1802 + "/children/numchildren/range/gi/1234\n" | |
1803 + "\nTo find the common ancestor of multiple organisms, add /ancestor/. For example:\n" | |
1804 + "/id/ancestor/1234,5678,42\n" | |
1805 + "/name/ancestor/homo_sapiens,canis_lupus,bos_taurus\n" | |
1806 + "\nFor a simplified taxonomic tree, add simple.\n" | |
1807 + "This will ignore unranked or uncommon levels like tribe and parvorder, and only display the following levels:\n" | |
1808 + "SUBSPECIES, SPECIES, GENUS, FAMILY, ORDER, CLASS, PHYLUM, KINGDOM, SUPERKINGDOM, DOMAIN\n" | |
1809 + "For example:\n" | |
1810 + "/simple/id/1234\n" | |
1811 + "\nTo print taxonomy from the command line in Linux, use curl:\n" | |
1812 + "curl https://taxonomy.jgi.doe.gov/id/9606\n" | |
1813 + "\nQueries longer than around 8kB can be sent via POST: curl https://taxonomy..doe.gov/POST" | |
1814 + "\n...where the data sent is, for example: name/e.coli,h.sapiens,c.lupus\n" | |
1815 + "\nLast restarted "+startTime+"\n" | |
1816 + "Running BBMap version "+Shared.BBMAP_VERSION_STRING+"\n"; | |
1817 }else{ | |
1818 StringBuilder sb=new StringBuilder(); | |
1819 sb.append("Welcome to the JGI"+(SketchObject.defaultParams.dbName==null ? "" : " "+SketchObject.defaultParams.dbName)+" sketch server!\n"); | |
1820 // if(dbName!=null){ | |
1821 // sb.append("This server has the "+dbName+ " database loaded.\n"); | |
1822 // } | |
1823 sb.append("\nUsage:\n\n"); | |
1824 sb.append("sendsketch.sh in=file.fasta"+(SketchObject.defaultParams.dbName==null ? "" : " "+SketchObject.defaultParams.dbName.toLowerCase())+"\n\n"); | |
1825 sb.append("SendSketch creates a sketch from a local sequence file, and sends the sketch to this server.\n"); | |
1826 sb.append("The server receives the sketch, compares it to all sketches in memory, and returns the results.\n"); | |
1827 sb.append("For files on the same system as the server, the 'local' flag may be used to offload sketch creation to the server.\n"); | |
1828 sb.append("For more details and parameters please run sendsketch.sh with no arguments.\n"); | |
1829 sb.append("\n"); | |
1830 if(SketchObject.useWhitelist()){ | |
1831 sb.append("This server is running in whitelist mode; for best results, use local queries.\n"); | |
1832 sb.append("Remote queries should specify a larger-than-normal sketch size.\n\n"); | |
1833 }else if(SketchObject.blacklist()!=null){ | |
1834 sb.append("This server is running in blacklist mode, using "+new File(SketchObject.blacklist()).getName()+".\n\n"); | |
1835 } | |
1836 sb.append("Last restarted "+startTime+"\n"); | |
1837 sb.append("Running BBMap version "+Shared.BBMAP_VERSION_STRING+"\n"); | |
1838 sb.append("Settings:\tk="+SketchObject.k+(SketchObject.k2>0 ? ","+SketchObject.k2 : "")); | |
1839 if(SketchObject.amino){sb.append(" amino");} | |
1840 if(SketchObject.makeIndex){sb.append(" index");} | |
1841 if(SketchObject.useWhitelist()){sb.append(" whitelist");} | |
1842 if(SketchObject.blacklist()!=null){sb.append(" blacklist="+new File(SketchObject.blacklist()).getName());} | |
1843 sb.append('\n'); | |
1844 return sb.toString(); | |
1845 } | |
1846 } | |
1847 | |
1848 private String makeUsageHtml(){ | |
1849 String html=rawHtml; | |
1850 html=html.replace("STATISTICSSTRING", makeStats()); | |
1851 // html=html.replace("TIMESTAMPSTRING", startTime); | |
1852 // html=html.replace("VERSIONSTRING", "Running BBMap version "+Shared.BBMAP_VERSION_STRING); | |
1853 return html; | |
1854 } | |
1855 | |
1856 private String loadRawHtml(){ | |
1857 String path=Data.findPath("?tax_server.html"); | |
1858 String html=ReadWrite.readString(path); | |
1859 return html; | |
1860 } | |
1861 | |
1862 private String makeStats(){ | |
1863 ByteBuilder sb=new ByteBuilder(); | |
1864 | |
1865 if(!sketchOnly){ | |
1866 sb.append("JGI taxonomy server stats:\n" | |
1867 + "\nLast restarted "+startTime+"\n" | |
1868 + "Running BBMap version "+Shared.BBMAP_VERSION_STRING+"\n"); | |
1869 }else{ | |
1870 sb.append("JGI"+(SketchObject.defaultParams.dbName==null ? "" : " "+SketchObject.defaultParams.dbName)+" sketch server stats:\n\n"); | |
1871 | |
1872 if(domain!=null) {sb.append("Domain: "+domain+"\n");} | |
1873 if(SketchObject.useWhitelist()){ | |
1874 sb.append("This server is running in whitelist mode; for best results, use local queries.\n"); | |
1875 sb.append("Remote queries should specify a larger-than-normal sketch size.\n\n"); | |
1876 }else if(SketchObject.blacklist()!=null){ | |
1877 sb.append("This server is running in blacklist mode, using "+new File(SketchObject.blacklist()).getName()+".\n\n"); | |
1878 } | |
1879 sb.append("Last restarted "+startTime+"\n"); | |
1880 sb.append("Running BBMap version "+Shared.BBMAP_VERSION_STRING+"\n"); | |
1881 sb.append("Settings: k="+SketchObject.k+(SketchObject.k2>0 ? ","+SketchObject.k2 : "")); | |
1882 if(SketchObject.amino){sb.append(" amino");} | |
1883 if(SketchObject.makeIndex){sb.append(" index");} | |
1884 if(SketchObject.useWhitelist()){sb.append(" whitelist");} | |
1885 if(SketchObject.blacklist()!=null){sb.append(" blacklist="+new File(SketchObject.blacklist()).getName());} | |
1886 } | |
1887 sb.nl().nl(); | |
1888 sb.append(basicStats()); | |
1889 if(sketchOnly){sb.append(makeExtendedStats());} | |
1890 | |
1891 return sb.toString(); | |
1892 } | |
1893 | |
1894 public String makeExtendedStats(){ | |
1895 ByteBuilder sb=new ByteBuilder(); | |
1896 sb.append('\n'); | |
1897 | |
1898 { | |
1899 sb.append("\nVersion\tCount\n"); | |
1900 ArrayList<String> list=new ArrayList<String>(); | |
1901 for(Entry<String, StringNum> e : versionMap.entrySet()){ | |
1902 list.add(e.getValue().toString()); | |
1903 } | |
1904 Collections.sort(list); | |
1905 for(String s : list){ | |
1906 sb.append(s).append('\n'); | |
1907 } | |
1908 } | |
1909 | |
1910 { | |
1911 sb.append("\nSketchs\tCount\tAvgTime\n"); | |
1912 for(int i=0; i<timesByCount.length(); i++){ | |
1913 double a=timesByCount.get(i)/1000000.0; | |
1914 long b=queryCounts.get(i); | |
1915 if(b>0){ | |
1916 sb.append(i).append('\t').append(b).append('\t').append(a/b, 3).append('\n'); | |
1917 } | |
1918 } | |
1919 sb.append('\n'); | |
1920 } | |
1921 return sb.toString(); | |
1922 } | |
1923 | |
1924 public String USAGE(String prefix){ | |
1925 if(!countQueries){return prefix;} | |
1926 String basicStats=basicStats(); | |
1927 return (prefix==null ? basicStats : prefix+"\n"+basicStats); | |
1928 } | |
1929 | |
1930 public String basicStats(){ | |
1931 if(!countQueries){return "";} | |
1932 StringBuilder sb=new StringBuilder(500); | |
1933 | |
1934 final long uq=usageQueries.getAndIncrement(); | |
1935 final long mq=malformedQueries.get(); | |
1936 final long pt=plaintextQueries.get(), sc=semicolonQueries.get(), pa=pathQueries.get(), pp=printPathQueries.get(), ps=printSizeQueries.get(); | |
1937 final long iq=internalQueries.get(); | |
1938 final long lq=localQueries.get(); | |
1939 final long rfq=refQueries.get(); | |
1940 final long q=queries.get(); | |
1941 final long nf=notFound.get(); | |
1942 final double avgTimeDL=.000001*(elapsedTimeLocal.get()/(Tools.max(1.0, timeMeasurementsLocal.get())));//in milliseconds | |
1943 final double lastTimeDL=.000001*lastTimeLocal.get(); | |
1944 final double avgTimeDR=.000001*(elapsedTimeRemote.get()/(Tools.max(1.0, timeMeasurementsRemote.get())));//in milliseconds | |
1945 final double lastTimeDR=.000001*lastTimeRemote.get(); | |
1946 final double avgTimeDRF=.000001*(elapsedTimeReference.get()/(Tools.max(1.0, timeMeasurementsReference.get())));//in milliseconds | |
1947 final double lastTimeDRF=.000001*lastTimeReference.get(); | |
1948 final double avgTimeDU=.000001*(elapsedTimeUsage.get()/(Tools.max(1.0, timeMeasurementsUsage.get())));//in milliseconds | |
1949 final double lastTimeDU=.000001*lastTimeUsage.get(); | |
1950 final long exq=q-iq; | |
1951 final long rmq=q-lq; | |
1952 | |
1953 sb.append('\n').append("Queries: ").append(q); | |
1954 sb.append('\n').append("Usage: ").append(uq); | |
1955 if(sketchOnly){ | |
1956 sb.append('\n').append("Invalid: ").append(mq); | |
1957 sb.append('\n').append("Avg time: ").append(String.format(Locale.ROOT, "%.3f ms (local queries)", avgTimeDL)); | |
1958 sb.append('\n').append("Last time: ").append(String.format(Locale.ROOT, "%.3f ms (local queries)", lastTimeDL)); | |
1959 sb.append('\n').append("Avg time: ").append(String.format(Locale.ROOT, "%.3f ms (remote queries)", avgTimeDR)); | |
1960 sb.append('\n').append("Last time: ").append(String.format(Locale.ROOT, "%.3f ms (remote queries)", lastTimeDR)); | |
1961 sb.append('\n').append("Avg time: ").append(String.format(Locale.ROOT, "%.3f ms (ref queries)", avgTimeDRF)); | |
1962 sb.append('\n').append("Last time: ").append(String.format(Locale.ROOT, "%.3f ms (ref queries)", lastTimeDRF)); | |
1963 }else{ | |
1964 sb.append('\n').append("Avg time: ").append(String.format(Locale.ROOT, "%.3f ms", avgTimeDR)); | |
1965 sb.append('\n').append("Last time: ").append(String.format(Locale.ROOT, "%.3f ms", lastTimeDR)); | |
1966 sb.append('\n').append("Avg time: ").append(String.format(Locale.ROOT, "%.3f ms (usage queries)", avgTimeDU)); | |
1967 sb.append('\n').append("Last time: ").append(String.format(Locale.ROOT, "%.3f ms (usage queries)", lastTimeDU)); | |
1968 } | |
1969 sb.append('\n'); | |
1970 sb.append('\n').append("Internal: ").append(iq); | |
1971 sb.append('\n').append("External: ").append(exq); | |
1972 if(!sketchOnly){sb.append('\n').append("NotFound: ").append(nf);} | |
1973 sb.append('\n'); | |
1974 | |
1975 if(sketchOnly){ | |
1976 sb.append('\n').append("Local: ").append(lq); | |
1977 sb.append('\n').append("Remote: ").append(rmq); | |
1978 sb.append('\n').append("Reference: ").append(rfq); | |
1979 sb.append('\n'); | |
1980 sb.append('\n').append("Depth: ").append(depthQueries.get()); | |
1981 sb.append('\n'); | |
1982 sb.append('\n').append("Sketches: ").append(querySketches.get()); | |
1983 sb.append('\n').append("BytesIn: ").append(bytesIn.get()); | |
1984 sb.append('\n').append("BytesOut: ").append(bytesOut.get()); | |
1985 sb.append('\n'); | |
1986 sb.append('\n').append("Single: ").append(firstChunkSingle.get()); | |
1987 sb.append('\n').append("Bulk: ").append(firstChunkMulti.get()); | |
1988 sb.append('\n').append("UnknownS: ").append(unknownChunkSingle.get()); | |
1989 sb.append('\n').append("UnknownB: ").append(unknownChunkMulti.get()); | |
1990 sb.append('\n').append("Total: ").append(bulkCount.get()); | |
1991 }else{ | |
1992 sb.append('\n').append("gi: ").append(giQueries.get()); | |
1993 sb.append('\n').append("Name: ").append(nameQueries.get()); | |
1994 sb.append('\n').append("TaxID: ").append(taxidQueries.get()); | |
1995 sb.append('\n').append("Header: ").append(headerQueries.get()); | |
1996 sb.append('\n').append("Accession: ").append(accessionQueries.get()); | |
1997 sb.append('\n').append("IMG: ").append(imgQueries.get()); | |
1998 sb.append('\n').append("Silva: ").append(silvaHeaderQueries.get()); | |
1999 sb.append('\n'); | |
2000 sb.append('\n').append("Simple: ").append(simpleQueries.get()); | |
2001 sb.append('\n').append("Ancestor: ").append(ancestorQueries.get()); | |
2002 sb.append('\n').append("Children: ").append(childrenQueries.get()); | |
2003 sb.append('\n'); | |
2004 sb.append('\n').append("Json: ").append(q-pt-sc-pa); | |
2005 sb.append('\n').append("Plaintext: ").append(pt); | |
2006 sb.append('\n').append("Semicolon: ").append(sc); | |
2007 sb.append('\n').append("Path: ").append(pa+pp); | |
2008 sb.append('\n').append("Size: ").append(ps); | |
2009 sb.append('\n').append("Single: ").append(firstChunkSingle.get()); | |
2010 sb.append('\n').append("Bulk: ").append(firstChunkMulti.get()); | |
2011 sb.append('\n').append("Total: ").append(bulkCount.get()); | |
2012 } | |
2013 sb.append('\n'); | |
2014 return sb.toString(); | |
2015 } | |
2016 | |
2017 public boolean incrementQueries(HttpExchange t, boolean local, boolean refMode, boolean simple, boolean ancestor, | |
2018 boolean plaintext, boolean semicolon, boolean path, boolean printChildren, boolean printPath, boolean printSize, int type){ | |
2019 final boolean internal=ServerTools.isInternalQuery(t, addressPrefix, allowLocalHost, printIP, printHeaders); | |
2020 | |
2021 if(!countQueries){return internal;} | |
2022 queries.incrementAndGet(); | |
2023 if(local){localQueries.incrementAndGet();} | |
2024 else if(refMode){localQueries.incrementAndGet();} | |
2025 | |
2026 if(type>=0){ | |
2027 int type2=type&15; | |
2028 if(type2==GI){ | |
2029 giQueries.incrementAndGet(); | |
2030 }else if(type2==NAME){ | |
2031 nameQueries.incrementAndGet(); | |
2032 }else if(type2==TAXID){ | |
2033 taxidQueries.incrementAndGet(); | |
2034 }else if(type2==ACCESSION){ | |
2035 accessionQueries.incrementAndGet(); | |
2036 }else if(type2==IMG){ | |
2037 imgQueries.incrementAndGet(); | |
2038 }else if(type2==HEADER){ | |
2039 headerQueries.incrementAndGet(); | |
2040 }else if(type2==UNKNOWN){ | |
2041 unknownQueries.incrementAndGet(); | |
2042 }else if(type2==SILVAHEADER){ | |
2043 silvaHeaderQueries.incrementAndGet(); | |
2044 } | |
2045 | |
2046 if(simple){simpleQueries.incrementAndGet();} | |
2047 if(ancestor){ancestorQueries.incrementAndGet();} | |
2048 | |
2049 if(plaintext){plaintextQueries.incrementAndGet();} | |
2050 else if(semicolon){semicolonQueries.incrementAndGet();} | |
2051 else if(path){pathQueries.incrementAndGet();} | |
2052 | |
2053 if(printChildren){childrenQueries.incrementAndGet();} | |
2054 if(printPath){printPathQueries.incrementAndGet();} | |
2055 if(printSize){printSizeQueries.incrementAndGet();} | |
2056 } | |
2057 | |
2058 if(internal){internalQueries.incrementAndGet();} | |
2059 | |
2060 return internal; | |
2061 } | |
2062 | |
2063 /*--------------------------------------------------------------*/ | |
2064 | |
2065 String compare(ArrayList<Sketch> inSketches, DisplayParams params){ | |
2066 boolean success=true; | |
2067 final int inSize=inSketches.size(); | |
2068 querySketches.addAndGet(inSize); | |
2069 if(Shared.threads()<2 || maxConcurrentSketchCompareThreads<2 || inSize<4){ | |
2070 ByteBuilder sb=new ByteBuilder(); | |
2071 success=searcher.compare(inSketches, sb, params, maxConcurrentSketchCompareThreads); | |
2072 return sb.toString(); | |
2073 }else{//More sketches than threads, and more than one thread | |
2074 final int threads=Tools.min(maxConcurrentSketchCompareThreads, (inSize+4)/4); | |
2075 | |
2076 ByteBuilder[] out=new ByteBuilder[inSize]; | |
2077 ArrayList<CompareThread> alct=new ArrayList<CompareThread>(threads); | |
2078 AtomicInteger next=new AtomicInteger(0); | |
2079 for(int i=0; i<threads; i++){ | |
2080 alct.add(new CompareThread(inSketches, i, next, out, params)); | |
2081 } | |
2082 for(CompareThread ct : alct){ct.start();} | |
2083 for(CompareThread ct : alct){ | |
2084 | |
2085 //Wait until this thread has terminated | |
2086 while(ct.getState()!=Thread.State.TERMINATED){ | |
2087 try { | |
2088 //Attempt a join operation | |
2089 ct.join(); | |
2090 } catch (InterruptedException e) { | |
2091 e.printStackTrace(); | |
2092 } | |
2093 } | |
2094 | |
2095 synchronized(ct){ | |
2096 success&=ct.success; | |
2097 } | |
2098 } | |
2099 alct=null; | |
2100 | |
2101 int len=0; | |
2102 for(ByteBuilder bb : out){len=len+bb.length;} | |
2103 ByteBuilder bb2=new ByteBuilder(len); | |
2104 for(int i=0; i<out.length; i++){ | |
2105 ByteBuilder bb=out[i]; | |
2106 bb2.append(bb); | |
2107 out[i]=null; | |
2108 } | |
2109 return bb2.toString(); | |
2110 } | |
2111 } | |
2112 | |
2113 private class CompareThread extends Thread { | |
2114 | |
2115 CompareThread(final ArrayList<Sketch> inSketches_, final int tid_, final AtomicInteger nextSketch_, ByteBuilder[] out_, DisplayParams params_){ | |
2116 inSketches=inSketches_; | |
2117 tid=tid_; | |
2118 nextSketch=nextSketch_; | |
2119 out=out_; | |
2120 params=params_; | |
2121 } | |
2122 | |
2123 @Override | |
2124 public void run(){ | |
2125 success=false; | |
2126 final int inLim=inSketches.size(); | |
2127 final boolean json=params.json(); | |
2128 | |
2129 for(int inNum=nextSketch.getAndIncrement(); inNum<inLim; inNum=nextSketch.getAndIncrement()){ | |
2130 Sketch a=inSketches.get(inNum); | |
2131 assert(buffer.cbs==null); //Because this sketch will only be used by one thread at a time, so per-buffer bitsets are not needed. | |
2132 SketchResults sr=searcher.processSketch(a, buffer, fakeID, map, params, 1); | |
2133 a.clearRefHitCounts(); | |
2134 | |
2135 ByteBuilder bb=sr.toText(params); | |
2136 if(out!=null){ | |
2137 if(json && inLim>1){ | |
2138 if(inNum==0){ | |
2139 bb.insert(0, (byte)'['); | |
2140 } | |
2141 if(inNum<inLim-1){ | |
2142 bb.append(','); | |
2143 }else{ | |
2144 bb.append(']'); | |
2145 } | |
2146 } | |
2147 synchronized(out){ | |
2148 out[inNum]=bb; | |
2149 } | |
2150 } | |
2151 } | |
2152 synchronized(this){success=true;} | |
2153 } | |
2154 | |
2155 private final ArrayList<Sketch> inSketches; | |
2156 private final int tid; | |
2157 private final CompareBuffer buffer=new CompareBuffer(false); | |
2158 private final DisplayParams params; | |
2159 private final ByteBuilder[] out; | |
2160 | |
2161 private final AtomicInteger nextSketch; | |
2162 private final AtomicInteger fakeID=new AtomicInteger(SketchObject.minFakeID); | |
2163 private ConcurrentHashMap<Integer, Comparison> map=new ConcurrentHashMap<Integer, Comparison>(101); | |
2164 | |
2165 boolean success=false; | |
2166 | |
2167 } | |
2168 | |
2169 | |
2170 /*--------------------------------------------------------------*/ | |
2171 /*---------------- Fields ----------------*/ | |
2172 /*--------------------------------------------------------------*/ | |
2173 | |
2174 public boolean sketchOnly=false; | |
2175 | |
2176 /*--------------------------------------------------------------*/ | |
2177 /*---------------- Counters ----------------*/ | |
2178 /*--------------------------------------------------------------*/ | |
2179 | |
2180 private HashMap<String, StringNum> versionMap=new HashMap<String, StringNum>(); | |
2181 private AtomicLongArray timesByCount=new AtomicLongArray(10000); | |
2182 private AtomicLongArray queryCounts=new AtomicLongArray(10000); | |
2183 | |
2184 private AtomicLong notFound=new AtomicLong(0); | |
2185 private AtomicLong queries=new AtomicLong(0); | |
2186 /** Same IP address mask */ | |
2187 private AtomicLong internalQueries=new AtomicLong(0); | |
2188 /** Local filesystem sketch */ | |
2189 private AtomicLong localQueries=new AtomicLong(0); | |
2190 private AtomicLong refQueries=new AtomicLong(0); | |
2191 | |
2192 private AtomicLong depthQueries=new AtomicLong(0); | |
2193 | |
2194 private AtomicLong iconQueries=new AtomicLong(0); | |
2195 | |
2196 private AtomicLong querySketches=new AtomicLong(0); | |
2197 | |
2198 private AtomicLong unknownChunkSingle=new AtomicLong(0); | |
2199 private AtomicLong unknownChunkMulti=new AtomicLong(0); | |
2200 private AtomicLong firstChunkSingle=new AtomicLong(0); | |
2201 private AtomicLong firstChunkMulti=new AtomicLong(0); | |
2202 private AtomicLong nthChunkSingle=new AtomicLong(0); | |
2203 private AtomicLong nthChunkMulti=new AtomicLong(0); | |
2204 | |
2205 private AtomicLong singleQueries=new AtomicLong(0); | |
2206 private AtomicLong bulkQueries=new AtomicLong(0); | |
2207 private AtomicLong bulkCount=new AtomicLong(0); | |
2208 | |
2209 private AtomicLong giQueries=new AtomicLong(0); | |
2210 private AtomicLong nameQueries=new AtomicLong(0); | |
2211 private AtomicLong taxidQueries=new AtomicLong(0); | |
2212 private AtomicLong headerQueries=new AtomicLong(0); | |
2213 private AtomicLong accessionQueries=new AtomicLong(0); | |
2214 private AtomicLong imgQueries=new AtomicLong(0); | |
2215 private AtomicLong unknownQueries=new AtomicLong(0); | |
2216 private AtomicLong silvaHeaderQueries=new AtomicLong(0); | |
2217 | |
2218 private AtomicLong plaintextQueries=new AtomicLong(0); | |
2219 private AtomicLong semicolonQueries=new AtomicLong(0); | |
2220 private AtomicLong pathQueries=new AtomicLong(0); | |
2221 private AtomicLong printPathQueries=new AtomicLong(0); | |
2222 private AtomicLong printSizeQueries=new AtomicLong(0); | |
2223 private AtomicLong childrenQueries=new AtomicLong(0); | |
2224 | |
2225 private AtomicLong simpleQueries=new AtomicLong(0); | |
2226 private AtomicLong ancestorQueries=new AtomicLong(0); | |
2227 | |
2228 private AtomicLong usageQueries=new AtomicLong(0); | |
2229 private AtomicLong bytesIn=new AtomicLong(0); | |
2230 private AtomicLong bytesOut=new AtomicLong(0); | |
2231 | |
2232 // private AtomicLong elapsedTime=new AtomicLong(0); | |
2233 // private AtomicLong timeMeasurements=new AtomicLong(0); | |
2234 // private AtomicLong lastTime=new AtomicLong(0); | |
2235 | |
2236 private AtomicLong elapsedTimeUsage=new AtomicLong(0); | |
2237 private AtomicLong timeMeasurementsUsage=new AtomicLong(0); | |
2238 private AtomicLong lastTimeUsage=new AtomicLong(0); | |
2239 | |
2240 private AtomicLong elapsedTimeRemote=new AtomicLong(0); | |
2241 private AtomicLong timeMeasurementsRemote=new AtomicLong(0); | |
2242 private AtomicLong lastTimeRemote=new AtomicLong(0); | |
2243 | |
2244 private AtomicLong elapsedTimeLocal=new AtomicLong(0); | |
2245 private AtomicLong timeMeasurementsLocal=new AtomicLong(0); | |
2246 private AtomicLong lastTimeLocal=new AtomicLong(0); | |
2247 | |
2248 private AtomicLong elapsedTimeReference=new AtomicLong(0); | |
2249 private AtomicLong timeMeasurementsReference=new AtomicLong(0); | |
2250 private AtomicLong lastTimeReference=new AtomicLong(0); | |
2251 | |
2252 private AtomicLong malformedQueries=new AtomicLong(0); | |
2253 | |
2254 /*--------------------------------------------------------------*/ | |
2255 /*---------------- Params ----------------*/ | |
2256 /*--------------------------------------------------------------*/ | |
2257 | |
2258 public boolean printIP=false; | |
2259 public boolean printHeaders=false; | |
2260 public boolean countQueries=true; | |
2261 public float prealloc=0; | |
2262 public boolean useHtml=false; | |
2263 | |
2264 /** Location of GiTable file */ | |
2265 private String giTableFile=null; | |
2266 /** Location of TaxTree file */ | |
2267 private String taxTreeFile="auto"; | |
2268 /** Comma-delimited locations of Accession files */ | |
2269 private String accessionFile=null; | |
2270 /** Location of IMG dump file */ | |
2271 private String imgFile=null; | |
2272 /** Location of accession pattern file */ | |
2273 private String patternFile=null; | |
2274 | |
2275 private String sizeFile=null; | |
2276 | |
2277 /** Location of sequence directory tree */ | |
2278 private String basePath="/global/cfs/cdirs/bbtools/tree/"; | |
2279 | |
2280 /** Used for taxonomic tree traversal */ | |
2281 private final TaxTree tree; | |
2282 | |
2283 /** Maps URL Strings to numeric query types */ | |
2284 private final HashMap<String, Integer> typeMap; | |
2285 /** Maps common organism names to scientific names */ | |
2286 private final HashMap<String, String> commonMap; | |
2287 | |
2288 /** Hash taxonomic names for lookup */ | |
2289 private boolean hashNames=true; | |
2290 private boolean hashDotFormat=true; | |
2291 | |
2292 /** Kill code of prior server instance (optional) */ | |
2293 private String oldKillCode=null; | |
2294 /** Address of prior server instance (optional) */ | |
2295 private String oldAddress=null; | |
2296 | |
2297 /** Address of current server instance (optional) */ | |
2298 public String domain=null; | |
2299 | |
2300 public int maxConcurrentSketchCompareThreads=8;//TODO: This might be too high when lots of concurrent sessions are active | |
2301 public int maxConcurrentSketchLoadThreads=4;//TODO: This might be too high when lots of concurrent sessions are active | |
2302 public int handlerThreads=-1; | |
2303 | |
2304 /*--------------------------------------------------------------*/ | |
2305 /*---------------- Final Fields ----------------*/ | |
2306 /*--------------------------------------------------------------*/ | |
2307 | |
2308 private final boolean distributed; | |
2309 private final int serverNum; | |
2310 private final int serverCount; | |
2311 private ArrayList<String> slaveAddress; | |
2312 | |
2313 public final String favIconPath=Data.findPath("?favicon.ico"); | |
2314 public final byte[] favIcon=ReadWrite.readRaw(favIconPath); | |
2315 | |
2316 private final String startTime=new Date().toString(); | |
2317 | |
2318 /** Listen on this port */ | |
2319 public final int port; | |
2320 /** Code to validate kill requests */ | |
2321 public final String killCode; | |
2322 | |
2323 public final HttpServer httpServer; | |
2324 | |
2325 /** Bit to set for plaintext query types */ | |
2326 public static final int PT_BIT=16; | |
2327 /** Bit to set for semicolon-delimited query types */ | |
2328 public static final int SC_BIT=32; | |
2329 /** Bit to set for path query types */ | |
2330 public static final int PA_BIT=64; | |
2331 /** Request query types */ | |
2332 public static final int UNKNOWN=0, GI=1, NAME=2, TAXID=3, HEADER=4, ACCESSION=5, IMG=6, SILVAHEADER=7; | |
2333 /** Plaintext-response query types */ | |
2334 public static final int PT_GI=GI+PT_BIT, PT_NAME=NAME+PT_BIT, PT_TAXID=TAXID+PT_BIT, | |
2335 PT_HEADER=HEADER+PT_BIT, PT_ACCESSION=ACCESSION+PT_BIT, PT_IMG=IMG+PT_BIT, PT_SILVAHEADER=SILVAHEADER+PT_BIT; | |
2336 /** Semicolon-response query types */ | |
2337 public static final int SC_GI=GI+SC_BIT, SC_NAME=NAME+SC_BIT, SC_TAXID=TAXID+SC_BIT, | |
2338 SC_HEADER=HEADER+SC_BIT, SC_ACCESSION=ACCESSION+SC_BIT, SC_IMG=IMG+SC_BIT, SC_SILVAHEADER=SILVAHEADER+PT_BIT; | |
2339 | |
2340 public static final int SOURCE_REFSEQ=1, SOURCE_SILVA=2, SOURCE_IMG=3; | |
2341 | |
2342 /** Generic response when asking for tax advice */ | |
2343 public static final String TAX_ADVICE="This site does not give tax advice."; | |
2344 /** Generic response for incorrect kill code */ | |
2345 public static final String BAD_CODE="Incorrect code."; | |
2346 /** Generic response for badly-formatted queries */ | |
2347 public final String USAGE; | |
2348 /** HTML version */ | |
2349 // public final String USAGE_HTML; | |
2350 public final String rawHtml; | |
2351 | |
2352 /** Tool for comparing query sketches to reference sketches */ | |
2353 public final SketchSearcher searcher=new SketchSearcher(); | |
2354 | |
2355 public final boolean hasSketches; | |
2356 | |
2357 final boolean allowRemoteFileAccess; | |
2358 final boolean allowLocalHost; | |
2359 final String addressPrefix; | |
2360 private boolean clearMem=true; | |
2361 | |
2362 /*--------------------------------------------------------------*/ | |
2363 /*---------------- Common Fields ----------------*/ | |
2364 /*--------------------------------------------------------------*/ | |
2365 | |
2366 /** Print status messages to this output stream */ | |
2367 private PrintStream outstream=System.err; | |
2368 /** Print verbose messages */ | |
2369 public static boolean verbose=false, verbose2=false, logUsage=false; | |
2370 /** True if an error was encountered */ | |
2371 public boolean errorState=false; | |
2372 | |
2373 } |