package Ġc rawler Ċ Ċ import Ġcom . google . common . base . Stop watch Ċ import Ġcom . google . common . collect . Maps Ċ import Ġcom . google . common . collect . Sets Ċ import Ġorg . slf 4 j . LoggerFactory Ċ import Ġjava . util .* Ċ import Ġjava . util . concurrent . Fork Join Pool Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ /** Ċ Ġ* ĠMulti - threaded Ġlink Ġc rawler . ĠUses Ġa Ġfork Ġjoin Ġpool Ġto Ġde compose Ġthe Ġjob Ġof Ġc raw ling Ġa Ġwebsite Ġinto Ġsmaller Ġtasks Ċ Ġ* Ġthat Ġare Ġfar med Ġout Ġto Ġmultiple Ġworker Ġthreads . ĠId le Ġworkers Ġcan Ġste al Ġwork Ġfrom Ġbus ier Ġworkers Ġin Ġorder Ġto Ġachieve Ċ Ġ* Ġhigher Ġthroughput . ĠThis Ġclass Ġis Ġresponsible Ġfor Ġstoring Ġthe Ġstate Ġ( visited Ġlinks , Ġwhich Ġlinks Ġare Ġchild Ġof Ċ Ġ* Ġwhich ĠURLs ) Ġin Ġa Ġthread - safe Ġmanner . Ċ Ġ*/ Ċ class ĠC rawler ( private Ġval Ġlink Loader : ĠLink Loader , Ġprivate Ġval Ġmax Threads : ĠInt ) Ġ{ ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġval ĠLOGGER Ġ= ĠLoggerFactory . getLogger ( Crawler :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġvisited Ġ= ĠCollections . synchronized Map ( Maps . new Linked HashMap < String , ĠInt >()) ĊĠĠĠ Ġprivate Ġval Ġmy Site Map Ġ= ĠCollections . synchronized Map ( Maps . new Linked HashMap < String , ĠMutable Collection < String >> ()) ĊĠĠĠ Ġprivate Ġval Ġpool Ġ= ĠFork Join Pool ( max Threads ) ĊĊĠĠĠ Ġval Ġsize ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġvisited . size ĊĊĠĠĠ Ġval Ġsite Map : ĠMap < String , ĠCollection < String >> ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġmy Site Map ĊĊĠĠĠ Ġfun Ġadd Vis ited ( url : ĠString , Ġdepth : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġvisited [ url ] Ġ= Ġdepth ĊĠĠĠĠĠĠĠ ĠLOGGER . debug (" visited : Ġ{} Ġat Ġdepth : Ġ{}", Ġurl , Ġdepth ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġvisited ( url : ĠString ) Ġ= Ġvisited . containsKey ( url ) ĊĊĠĠĠ Ġfun ĠaddTo Site Map ( url : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġmy Site Map [ url ] Ġ= ĠCollections . synchronized Set ( Sets . new HashSet < String >()) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġadd Child ( parent : ĠString , Ġchild : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġmy Site Map . get ( parent )?. add ( child ) ĊĠĠĠĠĠĠĠ ĠLOGGER . debug (" added Ġ{} Ġto Ġ{}, Ġwhich Ġnow Ġhas Ġ{} Ġchild : Ġ{}", Ġchild , Ġparent , Ġmy Site Map . get ( parent )?. size , Ġmy Site Map . get ( parent )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcrawl ( url : ĠString , Ġmax Depth : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġprintln (" c raw ling : Ġ${ url } Ġusing Ġ${ max Threads } Ġthreads Ġto Ġa Ġmaximum Ġlink Ġdepth Ġof Ġ${ max Depth }") ĊĠĠĠĠĠĠĠ Ġval Ġstop Watch Ġ= ĠStop watch . create Started () ĊĊĠĠĠĠĠĠĠ Ġ// Ġnext Ġline Ġcreates Ġa Ġtop - level Ġtask Ġto Ġcrawl Ġa Ġwebsite Ġfrom Ġthe Ġgiven ĠURL ĊĠĠĠĠĠĠĠ Ġpool . invoke ( Indexer ( this , Ġlink Loader , Ġurl , Ġ 0 , Ġmax Depth )) ĊĠĠĠĠĠĠĠ Ġstop Watch . stop () ĊĠĠĠĠĠĠĠ Ġprintln (" sitemap Ġcrawl Ġtook Ġ${ stop Watch . elapsed ( TimeUnit . SECONDS )} s ") ĊĠĠĠĠĠĠĠ Ġsite Map . keys . sorted (). forEach Ġ{ ĠLOGGER . debug ("{} Ġ-> Ġ{} : Ġ{}", Ġit , Ġsite Map [ it ]?. size , Ġsite Map [ it ]) } ĊĠĠĠ Ġ} Ċ }