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 */ main(String[] args)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 */ TaxServer(String[] args)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 */ killOldInstance()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 */ initializeServer(int millis0, int iterations, boolean https)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 returnUsage(long startTime, HttpExchange t)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 returnUsageHtml(long startTime, HttpExchange t)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 returnStats(long startTime, HttpExchange t)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 handle(HttpExchange t)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 handle(HttpExchange t)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 handle(HttpExchange t)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 handle(HttpExchange t)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 */ testCode(HttpExchange t, String rparam)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 handle(HttpExchange t)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 loadSketchesFromBody(String body)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 loadSketchesFromFile(String fname, DisplayParams params)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 SketchInstance(HttpExchange t_)599 SketchInstance(HttpExchange t_){ 600 t=t_; 601 instanceStartTime=System.nanoTime(); 602 } 603 handleInner()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 parseRparamSketch(HttpExchange t)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 findRefSketch(String s)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(Integer.parseInt(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(Integer.parseInt(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(Integer.parseInt(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(Integer.parseInt(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(Integer.parseInt(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(int 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/projectb/sandbox/gaag/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 } 2374