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 }