13. EPMO Open Source Coordination Office Redaction File Detail Report

Produced by Araxis Merge on 10/4/2017 8:38:10 AM Central Daylight Time. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.

13.1 Files compared

# Location File Last Modified
1 solr-smart-client.zip\solr-smart-client solr-smart-client.js Mon Aug 28 19:30:59 2017 UTC
2 solr-smart-client.zip\solr-smart-client solr-smart-client.js Wed Oct 4 13:31:53 2017 UTC

13.2 Comparison summary

Description Between
Files 1 and 2
Text Blocks Lines
Unchanged 8 1272
Changed 7 22
Inserted 0 0
Removed 0 0

13.3 Comparison options

Whitespace
Character case Differences in character case are significant
Line endings Differences in line endings (CR and LF characters) are ignored
CR/LF characters Not shown in the comparison detail

13.4 Active regular expressions

No regular expressions were active.

13.5 Comparison detail

  1   'use stric t';
  2  
  3   /*
  4   This class  handles c onnecting  to ZooKeep er, lookin g up and c onnecting  to a Solr  server,
  5   and perfor ming opera tions agai nst that s erver. Thi s class au tomaticall y connects  to
  6   ZooKeeper,  and will  attempt to  reconnect  if ZooKee per goes d own. In th e event th at the
  7   SolrSmartC lient cann ot connect  to ZooKee per within  the timeo ut period,  it will r eturn
  8   an error i n the call back.
  9  
  10   Currently,  this impl ementation  does not  listen for  (ZooKeepe r) node ev ents, as i t does
  11   not appear  to be nec essary giv en the cur rent requi rements.
  12  
  13   Note that  it is not  necessary  to pass a  value for  the 'agent ' paramete r in the c onstructor
  14   function o r for eith er of the  factory fu nctions. I n this cas e, no Keep -alive Age nt will be
  15   used.
  16   */
  17  
  18  
  19   const _ =  require('u nderscore' );
  20   const solr ClientModu le = requi re('solr-c lient');
  21   const zook eeper = re quire('nod e-zookeepe r-client') ;
  22  
  23   const CHIL D_INSTANCE _ENABLED =  true;
  24   const DATA _TIMEOUT_M ILLIS = 30 000;
  25   const WAIT _LOOP_DELA Y_MILLIS =  100;
  26   const REQU ERY_LOOP_D ELAY_MILLI S = 1000;
  27   const CORE  = 'vpr';
  28   const PATH  = '/colle ctions/vpr /state.jso n';
  29   const NODE _EVENT_LOG _LEVEL = ' debug';
  30   const ZOOK EEPER_EVEN T_LOG_LEVE L = 'debug ';
  31  
  32   /*
  33   Variadic F unction:
  34   function S olrSmartCl ient(logge r, config,  agent, pa rentDataWr apper)
  35   function S olrSmartCl ient(logge r, config,  agent)
  36  
  37   IMPORTANT:  If you ma nually cre ate an ins tance of S olrSmartCl ient direc tly by usi ng this co nstructor,
  38   you MUST c all start( ) for the  SolrSmartC lient inst ance to co nnect to Z ookeeper.
  39  
  40   logger - a  bunyan ty pe logger
  41   config - t he connect ion and co nfiguratio n properti es
  42   agent - HT TP Agent w hich is us ed for poo ling socke ts used in  HTTP(s) c lient requ ests
  43           Th is paramet er is opti onal
  44   parentData Wrapper =  optional o bject. If  a value is  passed th en this is  a child i nstance an d
  45           it  will not  attempt an y connecti on managem ent (as th at is hand led by the  parent)
  46           an d will onl y return d ata. This  parameter  should onl y be passe d when the  construct or
  47           is  called by  the child Instance()  method.
  48  
  49   config sho uld be an  object as  follows:
  50  
  51   let config  = {
  52     childIns tanceEnabl ed, // if  false, chi ldInstance () returns  "this"
  53     dataTime outMillis,  // the am ount of ti me to wait  for ZooKe eper data
  54     waitLoop DelayMilli s, // the  amount of  time betwe en each lo op when wa iting for  valid data
  55     requeryL oopDelayMi llis, // t he amount  of time be tween each  attempt t o call get Data() aft er an erro r
  56     core. //  the solr  core, e.g.  'vpr'
  57     zooKeepe rConnectio n, // conn ection str ing for Zo oKeeper, e .g. 'local host:2183, localhost: 2182,local host:2181'
  58     path, //  ZooKeeper  path to n ode with c luster sta tus
  59     nodeEven tLogLevel,  // bunyan  log level  at which  ZooKeeper  Node Event s will be  logged
  60     zookeepe rEventLogL evel, // b unyan log  level at w hich ZooKe eper Event s will be  logged
  61     zooKeepe rOptions:  { // this  node and a ll of the  values it  contains a re optiona l
  62       spinDe lay: // a  millisecon d value -  zookeeper  client wil l default  to 1000
  63       sessio nTimeout:  // a milli second val ue - zooke eper clien t will def ault to 30 000
  64       retrie s: // zook eeper clie nt will de fault to 0  - SEE BEL OW BEFORE  SETTING TH IS
  65       sessio nId: // zo okeeper cl ient will  default to  undefined
  66       sessio nPassword:  // zookee per client  will defa ult to und efined
  67     }
  68   };
  69  
  70   RETRIES VA LUE
  71   The Zookee per client  uses an a lgorithm t hat geomet rically in creases th e delay be tween each
  72   retry as f ollows:
  73       Math.m in(1000 *  Math.pow(2 , attempts ), session Timeout)
  74   */
  75  
  76   class Solr SmartClien t {
  77     construc tor(logger , config,  agent, par entDataWra pper) {
  78       if (!n ew.target)  {
  79         retu rn new Sol rSmartClie nt(logger,  config, a gent, pare ntDataWrap per);
  80       }
  81  
  82       logger .debug('so lr-smart-c lient.Solr SmartClien t()');
  83  
  84       this.l ogger = lo gger;
  85       this.c onfig = co nfig;
  86       this.a gent = age nt;
  87       this.c hild = !!p arentDataW rapper;
  88       this.z kClient =  null;
  89  
  90       this.c onfig.chil dInstanceE nabled = _ .has(confi g, 'childI nstanceEna bled') ? c onfig.chil dInstanceE nabled : C HILD_INSTA NCE_ENABLE D;
  91       this.c onfig.data TimeoutMil lis = _.ha s(config,  'dataTimeo utMillis')  ? config. dataTimeou tMillis :  DATA_TIMEO UT_MILLIS;
  92       this.c onfig.wait LoopDelayM illis = _. has(config , 'waitLoo pDelayMill is') ? con fig.waitLo opDelayMil lis : WAIT _LOOP_DELA Y_MILLIS;
  93       this.c onfig.requ eryLoopDel ayMillis =  _.has(con fig, 'requ eryLoopDel ayMillis')  ? config. requeryLoo pDelayMill is : REQUE RY_LOOP_DE LAY_MILLIS ;
  94       this.c onfig.core  = config. core || CO RE;
  95       this.c onfig.path  = config. path || PA TH;
  96       this.c onfig.zooK eeperConne ction = co nfig.zooKe eperConnec tion;
  97       this.c onfig.node EventLogLe vel = conf ig.nodeEve ntLogLevel  || NODE_E VENT_LOG_L EVEL;
  98       this.c onfig.zook eeperEvent LogLevel =  config.zo okeeperEve ntLogLevel  || ZOOKEE PER_EVENT_ LOG_LEVEL;
  99       this.c onfig.zooK eeperOptio ns = confi g.zooKeepe rOptions;
  100  
  101  
  102       // Thi s wrapper  object all ows the Zo okeeper da ta to be p assed by r eference
  103       // fro m parent t o child an d child to  parent. T his way, t he parent  and child
  104       // ins tances all  share the  same zook eeper conn ection.
  105       // IMP ORTANT: Do  not set t hese value s manually ! Only set  them in r esponse
  106       // to  a Zookeepe r event or  a Zookeep er Node ev ent!
  107       this.d ataWrapper  = parentD ataWrapper  || {
  108         data : undefine d,
  109         vali d: false
  110       };
  111     }
  112  
  113  
  114     /*
  115     This met hod create s a child  instance o f the curr ent SolrSm artClient  instance.
  116     A child  instance o nly uses t he 'dataWr apper' obj ect and as sumes that  Zookeeper
  117     connecti on, event,  and error  handling  will be pe rformed by  the paren t instance .
  118  
  119     The purp ose of thi s method i s to allow  instance- specific l ogging wit hout addin g
  120     addition al Zookeep er connect ion overhe ad.
  121  
  122     IMPORTAN T: DO NOT  call start () on inst ances of S olrSmartCl ient creat ed with th is
  123     method.  The Zookee per connec tion manag ement will  be handle d exclusiv ely by the
  124     parent i nstance.
  125     */
  126     childIns tance(chil dLogger) {
  127       this.l ogger.debu g('solr-sm art-client .childInst ance() chi ldInstance Enabled? % s', this.c onfig.chil dInstanceE nabled);
  128  
  129       if (!t his.config .childInst anceEnable d) {
  130         this .logger.de bug('solr- smart-clie nt.childIn stance() c hildInstan ceEnabled  false, ret urning "th is"');
  131         retu rn this;
  132       }
  133  
  134       return  new SolrS martClient (childLogg er, this.c onfig, thi s.agent, t his.dataWr apper);
  135     }
  136  
  137  
  138     /*
  139     Add a do cument or  a list of  documents
  140  
  141     docs - d ocument or  list of d ocuments t o add into  the Solr  database
  142     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  143     */
  144     add(docs , callback ) {
  145       this.l ogger.debu g('solr-sm art-client .add(): %j ', docs);
  146       this._ executeSol rCommand(' add', docs , callback );
  147     }
  148  
  149  
  150     /*
  151     Delete a ll documen ts
  152  
  153     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  154     */
  155     deleteAl l(callback ) {
  156       this.l ogger.debu g('solr-sm art-client .deleteAll ()');
  157       this._ executeSol rCommand(' deleteByQu ery', '*:* ', callbac k);
  158     }
  159  
  160  
  161     /*
  162     Delete d ocuments m atching th e given `q uery`
  163  
  164     query -  solr query
  165     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  166     */
  167     deleteBy Query(quer y, callbac k) {
  168       this.l ogger.debu g('solr-sm art-client .deleteByQ uery(%j)',  query);
  169       this._ executeSol rCommand(' deleteByQu ery', quer y, callbac k);
  170     }
  171  
  172  
  173     /*
  174     Search d ocuments m atching th e `query`
  175  
  176     query -  solr query
  177     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  178     */
  179     search(q uery, call back) {
  180       this.l ogger.debu g('solr-sm art-client .search(%j )', query) ;
  181       this._ executeSol rCommand(' search', q uery, call back);
  182     }
  183  
  184  
  185     /*
  186     Send an  arbitrary  HTTP GET r equest to  Solr on th e specifie d `handler ` (as Solr  like to c all it i.e  path)
  187  
  188     handler  - a Solr p ath
  189     query -  Solr query
  190     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  191     */
  192     get(hand ler, query , callback ) {
  193       this.l ogger.debu g('solr-sm art-client .get(%j, % j)', handl er, query) ;
  194       this._ executeSol rCommand(' get', [han dler, quer y], callba ck);
  195     }
  196  
  197  
  198     /*
  199     Commit l ast added  and remove d document s, that me ans your d ocuments a re now ind exed.
  200     This isn 't strictl y necessar y for norm al operati ons, but c ommitting  updates wi ll
  201     cause th em to be a pplied mor e immediat ely (this  will likel y be neces sary for i ntegration
  202     tests wh ich involv e data bei ng updated  in Solr).
  203  
  204     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  205     */
  206     commit(c allback) {
  207       this.l ogger.debu g('solr-sm art-client .commit()' );
  208       this._ executeSol rCommand(' commit', c allback);
  209     }
  210  
  211  
  212     /*
  213     Ping the  server vi a a call t o solrClie nt.ping()
  214  
  215     callback  - a funct ion execut ed when th e Solr ser ver respon ds or an e rror occur s
  216     */
  217     ping(cal lback) {
  218       this.l ogger.debu g('solr-sm art-client .ping()');
  219       this._ executeSol rCommand(' ping', cal lback);
  220     }
  221  
  222  
  223     /*
  224     This met hod create s the Zook eeper clie nt instanc es and reg isters all  event
  225     handlers  for Zooke eper event s and Zook eeper Node  events. I f this met hod is
  226     called f rom and in stance cre ated with  childInsta nce(), it  will log a  warning
  227     message  and return  without d oing anyth ing.
  228     */
  229     start()  {
  230       this.l ogger.debu g('solr-sm art-client .start()') ;
  231  
  232       if (th is.child)  {
  233         // T his method  was calle d on a chi ld instanc e, so log  a warning  and return
  234         this .logger.wa rn('solr-s mart-clien t.start()  attempt to  call this  method fr om childIn stance ign ored');
  235         retu rn;
  236       }
  237  
  238       let lo gger = thi s.logger;
  239       let da taWrapper  = this.dat aWrapper;
  240       let zo oKeeperOpt ions = thi s.config.z ooKeeperOp tions;
  241       let zo oKeeperCon nection =  this.confi g.zooKeepe rConnectio n;
  242       let zo okeeperEve ntLogLevel  = this.co nfig.zooke eperEventL ogLevel;
  243  
  244       // Cle ar the dat a to start  fresh
  245       dataWr apper.vali d = false;
  246       dataWr apper.data  = undefin ed;
  247  
  248       // Unr egister al l Zookeepe r listener s, close t he current  connectio n
  249       if (th is.zkClien t) {
  250         this .zkClient. removeAllL isteners() ;
  251         this .zkClient. close();
  252       }
  253  
  254       logger .debug('so lr-smart-c lient.star t() zookee per.create Client()') ;
  255       this.z kClient =  zookeeper. createClie nt(zooKeep erConnecti on, zooKee perOptions );
  256       logger .debug('so lr-smart-c lient.star t() zookee per client  created') ;
  257       this.z kClient.co nnect();
  258       this.z kClient.on ('state',  state => {
  259         logg er.debug(' solr-smart -client.st art() -> s essionId:  %s, eventH andler():  %j', this. zkSessionI d, state);
  260  
  261         // Z ooKeeper e vents can  be one of  6 states:
  262         //    DISCONNEC TED
  263         //    SYNC_CONN ECTED
  264         //    AUTH_FAIL ED
  265         //    CONNECTED _READ_ONLY
  266         //    SASL_AUTH ENTICATED
  267         //    EXPIRED
  268  
  269         if ( !_.isEmpty (zookeeper EventLogLe vel) && _. isFunction (logger[zo okeeperEve ntLogLevel ])) {
  270           lo gger[zooke eperEventL ogLevel](' solr-smart -client.st art() -> e ventHandle r() sessio nId: %s, Z ookeeper E vent: %j',  this.zkSe ssionId, s tate);
  271         }
  272  
  273         if ( state ===  zookeeper. State.SYNC _CONNECTED  || state  === zookee per.State. CONNECTED_ READ_ONLY)  {
  274           re turn this. _fetchZook eeperData( );
  275         }
  276  
  277         if ( state ===  zookeeper. State.DISC ONNECTED)  {
  278           lo gger.debug ('solr-sma rt-client. start() ->  eventHand ler() sess ionId: %s,  DISCONNEC TED', this .zkSession Id);
  279           da taWrapper. valid = fa lse;
  280           da taWrapper. data = und efined;
  281           re turn;
  282         }
  283  
  284         if ( state ===  zookeeper. State.EXPI RED) {
  285           lo gger.warn( 'solr-smar t-client.s tart() ->  eventHandl er() sessi onId: %s,  EXPIRED',  this.zkSes sionId);
  286  
  287           //  EXPIRED e vents shou ld be unco mmon. Clea r out the  client and  reset eve rything.
  288           th is.start() ;
  289         }
  290       });
  291     }
  292  
  293  
  294     /*
  295     Returns  the Zookee per Sessio nId as a s tring. If  "this.zkCl ient"
  296     (the Zoo keeper cli ent instan ce) is nul l or undef ined, it r eturns
  297     'undefin ed'.
  298  
  299     The valu e returned  will be a  hex value  which wil l match up  with the
  300     sessionI d value in  the Zooke eper log f ile.
  301     */
  302     get zkSe ssionId()  {
  303       if (!t his.zkClie nt) {
  304         retu rn;
  305       }
  306  
  307       return  this.zkCl ient.getSe ssionId(). toString(' hex');
  308     }
  309  
  310  
  311     /*
  312     Call zkC lient.getC hildren()  and update  the data  from the r esults.
  313     Addition ally, regi ster a wat cher so th at in the  event of a  node
  314     being mo dified, ad ded, or de leted, the  data will  be reload ed.
  315     */
  316     _fetchZo okeeperDat a() {
  317       this.l ogger.debu g('solr-sm art-client ._fetchZoo keeperData ()');
  318  
  319       let da taWrapper  = this.dat aWrapper;
  320       let lo gger = thi s.logger;
  321       let no deEventLog Level = th is.nodeEve ntLogLevel ;
  322       let re queryLoopD elayMillis  = this.co nfig.reque ryLoopDela yMillis;
  323  
  324  
  325       // Thi s is calle d on any o f the Zook eeper Node  events:
  326       // NOD E_CREATED,  NODE_DELE TED, NODE_ DATA_CHANG ED, NODE_C HILDREN_CH ANGED
  327  
  328       // A w atch is a  one-time e vent liste ner (i.e.  it is call ed at most , one time )
  329       let wa tch = even t => {
  330         if ( !_.isEmpty (nodeEvent LogLevel)  && _.isFun ction(logg er[nodeEve ntLogLevel ])) {
  331           lo gger[nodeE ventLogLev el]('solr- smart-clie nt._fetchZ ookeeperDa ta() -> wa tch() sess ionId: %s,  Zookeeper  Node Even t: %j', th is.zkSessi onId, even t);
  332         }
  333  
  334         logg er.debug(' solr-smart -client._f etchZookee perData()  -> watch()  Zookeeper  Node Even t: %j', ev ent);
  335         this ._fetchZoo keeperData ();
  336       };
  337  
  338       // Sav e the data  or the va lid flag t o false if  an error  occured wh en
  339       // att empting to  call zkCl ient.getCh ildren()
  340       let se tData = (e rror, clus terState)  => {
  341         if ( error) {
  342           lo gger.error ('solr-sma rt-client. _fetchZook eeperData( ) -> setDa ta() Error  calling z ookeeper.g etData():  sessionId:  %s, error : %j', thi s.zkSessio nId, error );
  343           da taWrapper. valid = fa lse;
  344           da taWrapper. data = und efined;
  345           re turn setTi meout(this ._fetchZoo keeperData .bind(this ), requery LoopDelayM illis);
  346         }
  347  
  348         logg er.debug(' solr-smart -client._f etchZookee perData()  -> setData () session Id: %s, cl usterState : %s', thi s.zkSessio nId, clust erState);
  349         data Wrapper.va lid = true ;
  350         data Wrapper.da ta = clust erState;
  351       };
  352  
  353       this.z kClient.ge tData(this .config.pa th, watch,  setData);
  354     }
  355  
  356  
  357     /*
  358     This fun ction retr ieves the  SOLR clien t info fro m ZooKeepe r. In the  event
  359     that dat a has not  been retri eved yet,  or has bee n cleared  because Zo oKeeper
  360     is down  or because  the data  is being u pdated, th e method w ill wait f or the
  361     data unt il the con fig.dataTi meoutMilli s period i s exceeded , at which  point
  362     it will  return an  error.
  363     */
  364     _getSolr ClientInfo (callback)  {
  365       this.l ogger.debu g('solr-sm art-client ._getSolrC lientInfo( )');
  366  
  367       let st artTime =  Date.now() ;
  368       let lo gger = thi s.logger;
  369       let da taWrapper  = this.dat aWrapper;
  370       let da taTimeoutM illis = th is.config. dataTimeou tMillis;
  371       let wa itLoopDela yMillis =  this.confi g.waitLoop DelayMilli s;
  372  
  373       // inv oked immed iately via  IIFE
  374       // rec ursively l oop until  dataWrappe r.valid or  timeout e xpires
  375       (funct ion waitFo rValidData () {
  376         logg er.debug(' solr-smart -client._g etSolrClie ntInfo() - > waitForV alidData() : waiting  for dataWr apper.vali d: %s', da taWrapper. valid);
  377         if ( !dataWrapp er.valid)  {
  378           if  (Date.now () - start Time > dat aTimeoutMi llis) {
  379              logger.war n('solr-sm art-client ._getSolrC lientInfo( ) -> waitF orValidDat a(): timeo ut while w aiting for  valid dat a');
  380              return set Timeout(ca llback, 0,  'Timeout  waiting fo r valid zo okeeper da ta');
  381           }
  382  
  383           re turn setTi meout(wait ForValidDa ta, waitLo opDelayMil lis);
  384         }
  385  
  386         logg er.debug(' solr-smart -client._g etSolrClie ntInfo() - > waitForV alidData() : retrieve d valid da ta: %s', d ataWrapper .data);
  387         retu rn setTime out(callba ck, 0, nul l, dataWra pper.data) ;
  388       })();
  389     }
  390  
  391  
  392     /*
  393     Variadic  function:
  394     function  executeSo lrCommand( operation,  callback)
  395     function  executeSo lrCommand( operation,  param, ca llback)
  396     function  executeSo lrCommand( operation,  [param1,  param2...] , callback )
  397  
  398     operatio n - name o f the oper ation to c all on sol rClient (e .g. solrCl ient.add() , etc.)
  399     params -  a single  parameter  or an arra y of param eters to p ass to sol rClient
  400     callback  - the fun ction(erro r, result)  called on  success o r failure  of the sol r action
  401  
  402     This fun ction exec utes a sol r command,  first per forming al l of the n ecessary o perations
  403     to get a  reference  to a vali d solr cli ent instan ce. The fo llowing so lr command  methods
  404     in this  class dele gate to th is method:
  405  
  406       add()
  407       delete All()
  408       delete ByQuery()
  409       search ()
  410       get()
  411       commit ()
  412     */
  413     _execute SolrComman d(operatio n, params,  callback)  {
  414       this.l ogger.debu g('solr-sm art-client ._executeS olrCommand () -> solr Client.%s( %j)', oper ation, par ams);
  415  
  416       if (ar guments.le ngth < 3)  {
  417         call back = par ams;
  418         para ms = [];
  419       }
  420  
  421       if (!_ .isArray(p arams)) {
  422         para ms = [para ms];
  423       }
  424  
  425       // sli ce() makes  a shallow  copy of t he array
  426       params  = params. slice();
  427       params .push(call back);
  428  
  429       this.l ogger.debu g('solr-sm art-client ._executeS olrCommand () -> solr Client.%s( )', operat ion);
  430       this._ getValidSo lrClient(s olrClientM odule, (er ror, solrC lientInsta nce) => {
  431         if ( error) {
  432           re turn callb ack(error) ;
  433         }
  434  
  435         let  func = sol rClientIns tance[oper ation];
  436         if ( !_.isFunct ion(func))  {
  437           re turn callb ack('"' +  operation  + '" is no t a valid  function f or the Sol r Client') ;
  438         }
  439  
  440         retu rn func.ap ply(solrCl ientInstan ce, params );
  441       });
  442     }
  443  
  444  
  445     /*
  446     Returns  a valid So lrClient r eady to in voke vario us Solr op erations
  447  
  448     The solr Client par ameter is  to allow u nit tests  to pass in  a custom
  449     solrClie nt library .
  450     */
  451     _getVali dSolrClien t(solrClie ntLibrary,  callback)  {
  452       this.l ogger.debu g('solr-sm art-client ._getValid SolrClient ()');
  453  
  454       let co re = this. config.cor e;
  455       let ag ent = this .agent;
  456       this._ getSolrCli entInfo((e rror, solr ClientInfo ) => {
  457         if ( error) {
  458           th is.logger. warn('solr -smart-cli ent._getVa lidSolrCli ent() erro r retrievi ng solrCon fig: %j',  error);
  459           re turn callb ack(error) ;
  460         }
  461  
  462         let  solrConfig  = SolrSma rtClient._ createSolr ClientConf ig(this.lo gger, core , agent, s olrClientI nfo);
  463  
  464         this .logger.in fo('solr-s mart-clien t._getVali dSolrClien t() solrCo nfig: %j',  _.omit(so lrConfig,  'agent'));
  465         retu rn callbac k(null, so lrClientLi brary.crea teClient(s olrConfig) );
  466       });
  467     }
  468  
  469  
  470     /*
  471     Generate  a Solr cl ient confi g object o r return u ndefined i f no valid  liveNode  string exi sts.
  472     core - t he Solr 'c ore' (e.g.  'vpr');
  473     agent -  a referenc e to the a gent objec t (i.e. th e KeepAliv eAgent)
  474              This value  can be 'u ndefined'  in which c ase, no ag ent will b e used.
  475     clusterS tate - the  state of  the SOLR c luster sto red by Zoo Keeper. Th is should  be a JSON
  476     document  similar t o:
  477  
  478     {
  479       "vpr":  {
  480         "rep licationFa ctor": "1" ,
  481         "sha rds": {
  482           "s hard1": {
  483              "range": " 80000000-7 fffffff",
  484              "state": " active",
  485              "replicas" : {
  486                "core_no de1": {
  487                  "core" : "vpr_sha rd1_replic a1",
  488                    "base_url" : "http:// IP                /solr",
  489                    "node_name ": " IP                _solr",
  490                  "state ": "active ",
  491                  "leade r": "true"
  492                }
  493              }
  494           }
  495         },
  496         "rou ter": {
  497           "n ame": "com positeId"
  498         },
  499         "max ShardsPerN ode": "2",
  500         "aut oAddReplic as": "fals e"
  501       }
  502     }
  503  
  504     Note tha t "vpr" is  the name  of the col lection (i .e. the co re). Note  that a com plex syste m could
  505     have mul tiple shar ds with mu ltiple rep licas per  shard. Thi s function  will find  the data  from the
  506     first sh ard with a  replica w ith "state " === 'act ive' and " leader" == = 'true'.
  507     */
  508     static _ createSolr ClientConf ig(logger,  core, age nt, cluste rState) {
  509       logger .debug('so lr-smart-c lient._cre ateSolrCli entConfig( ) core: %s  clusterSt ate: %s',  core, clus terState);
  510  
  511       if (_. isEmpty(co re) || _.i sEmpty(clu sterState) ) {
  512         logg er.warn('s olr-smart- client._cr eateSolrCl ientConfig () no valu e for core  and/or cl usterState , unable t o create s olr client  config');
  513         retu rn;
  514       }
  515  
  516       try {
  517         clus terState =  JSON.pars e(clusterS tate);
  518       } catc h (error)  {
  519         logg er.warn('s olr-smart- client._cr eateSolrCl ientConfig () error p arsing clu sterState,  unable to  create so lr client  config: %j ', error);
  520         retu rn;
  521       }
  522  
  523       if (!c lusterStat e[core]) {
  524         logg er.warn('s olr-smart- client._cr eateSolrCl ientConfig () no entr y for "%s"  collectio n, unable  to create  solr clien t config',  core);
  525         retu rn;
  526       }
  527  
  528       let pa rsedUrl =  SolrSmartC lient._fin dFirstRead yNodeUrl(l ogger, clu sterState[ core].shar ds);
  529  
  530       if (!p arsedUrl)  {
  531         logg er.warn('s olr-smart- client._cr eateSolrCl ientConfig () unable  to find re ady replic a to creat e solr cli ent config ');
  532         retu rn;
  533       }
  534  
  535       return  {
  536         secu re: parsed Url[2] ===  'https',
  537         host : parsedUr l[3],
  538         port : parsedUr l[4],
  539         path : parsedUr l[5],
  540         core : core,
  541         agen t: agent
  542       };
  543     }
  544  
  545  
  546     /*
  547     This fun ction pars es the sha rd and rep lica infor mation (wh ich was re trieved fr om the
  548     collecti ons node)  and finds  the first  replica wh ich matche s the crit eria:
  549       state  === 'activ e'
  550       leader  === 'true '
  551       base_u rl that ma tches the  regex
  552  
  553     The retu rn value i s the arra y gotten f rom execut ing the re gex.
  554  
  555     Given th e followin g input:
  556  
  557     let shar ds =
  558       "shard 1": {
  559         "ran ge": "8000 0000-7ffff fff",
  560         "sta te": "acti ve",
  561         "rep licas": {
  562           "c ore_node1" : {
  563              "core": "v pr_shard1_ replica1",
  564               "base_url" : "http:// IP                /solr",
  565               "node_name ": " IP                _solr",
  566              "state": " active",
  567              "leader":  "true"
  568           }
  569         }
  570       },
  571       "shard 2": {
  572         "ran ge": "8000 0000-7ffff fff",
  573         "sta te": "acti ve",
  574         "rep licas": {
  575           "c ore_node1" : {
  576              "core": "v pr_shard2_ replica1",
  577               "base_url" : "http:// IP                /solr",
  578               "node_name ": " IP                _solr",
  579              "state": " active",
  580              "leader":  "true"
  581           }
  582         }
  583       }
  584     }
  585  
  586     The retu rn value w ould be:
  587  
  588       [ 'http:// IP                /solr',
  589       'http: //',
  590       'http' ,
  591       ' IP         ',
  592         ' PORT ',
  593       '/solr ',
  594       index:  0,
  595         input: 'ht tp:// IP                /solr' ]
  596  
  597     */
  598     static _ findFirstR eadyNodeUr l(logger,  shards) {
  599       logger .debug('so lr-smart-c lient._fin dFirstRead yNodeUrl()  %j', shar ds);
  600  
  601       // Go  to: https: //regex101 .com/#java script and  enter thi s regex to  explore.. .
  602       // Thi s regex ma tches urls  of the fo rms with o r without  the protoc ol:
  603         //      http://127 .0.0.1: PORT /solr
  604       let ur lRegex = n ew RegExp( /^((http[s ]?):\/\/)? (\S+):([0- 9]{1,5})(\ S+)/);
  605  
  606       // Cre ate an arr ay with al l of the s olr node e ntries in  all of the  shards th at
  607       // are  active, l eaders, an d with a b ase_url  t hat matche s the expe cted patte rn
  608       let no deList = _ .flatten(_ .map(shard s, shardIn fo => {
  609         retu rn _.filte r(shardInf o.replicas , node =>  {
  610           re turn node. state ===  'active' & & node.lea der === 't rue' && ur lRegex.tes t(node.bas e_url);
  611         });
  612       }));
  613  
  614       if (_. isEmpty(no deList)) {
  615         logg er.warn('s olr-smart- client._fi ndFirstRea dyNodeUrl( ) no nodes  were foun d in a val id state w ith valid  info');
  616         retu rn;
  617       }
  618  
  619       return  urlRegex. exec(_.fir st(nodeLis t).base_ur l);
  620     }
  621   }
  622  
  623   /* ******* ********** ********** ********** ********** ********** ********** ********** ********** ********** ********** *** */
  624   /*                                                     Factory Fu nctions                                                    */
  625   /* ******* ********** ********** ********** ********** ********** ********** ********** ********** ********** ********** *** */
  626  
  627   /*
  628   This funct ion create s a stand- alone (i.e . not a ch ild) insta nce of Sol rSmartClie nt.
  629  
  630   config - t he connect ion and co nfiguratio n properti es
  631   agent - HT TP Agent w hich is us ed for poo ling socke ts used in  HTTP(s) c lient requ ests
  632           Th is paramet er is opti onal
  633  
  634   For full d ocumentati on on the  properties  in 'confi g', see th e comments  in the So lrSmartCli ent constr uctor
  635   */
  636   function c reateClien t(logger,  config, ag ent) {
  637     logger.d ebug('solr -smart-cli ent.create Client() c onfig: %j' , config);
  638  
  639     let solr SmartClien t = new So lrSmartCli ent(logger , config,  agent);
  640     solrSmar tClient.st art();
  641  
  642     return s olrSmartCl ient;
  643   }
  644  
  645  
  646   exports.So lrSmartCli ent = Solr SmartClien t;
  647   exports.cr eateClient  = createC lient;