/// <summary> /// Reloads the internal SPI list. /// Changes to the service list are visible after the method ends, all /// iterators (e.g, from <see cref="AvailableServices"/>,...) stay consistent. /// /// <para/><b>NOTE:</b> Only new service providers are added, existing ones are /// never removed or replaced. /// /// <para/><em>this method is expensive and should only be called for discovery /// of new service providers on the given classpath/classloader!</em> /// </summary> public void Reload() { UninterruptableMonitor.Enter(this); try { IDictionary <string, Type> services = new JCG.LinkedDictionary <string, Type>(this.services); SPIClassIterator <S> loader = SPIClassIterator <S> .Get(); foreach (var service in loader) { string clazzName = service.Name; string name = null; foreach (string suffix in suffixes) { if (clazzName.EndsWith(suffix, StringComparison.Ordinal)) { name = clazzName.Substring(0, clazzName.Length - suffix.Length).ToLowerInvariant(); break; } } if (name is null) { throw ServiceConfigurationError.Create("The class name " + service.Name + " has wrong suffix, allowed are: " + Arrays.ToString(suffixes)); } // only add the first one for each name, later services will be ignored // this allows to place services before others in classpath to make // them used instead of others // // TODO: Should we disallow duplicate names here? // Allowing it may get confusing on collisions, as different packages // could contain same factory class, which is a naming bug! // When changing this be careful to allow reload()! if (!services.ContainsKey(name)) { services.Add(name, service); } } this.services = services.AsReadOnly(); } finally { UninterruptableMonitor.Exit(this); } }
/// <summary> /// Detect repetition groups. Done once - for first doc. </summary> private IList <IList <PhrasePositions> > GatherRptGroups(JCG.LinkedDictionary <Term, int?> rptTerms) { PhrasePositions[] rpp = RepeatingPPs(rptTerms); IList <IList <PhrasePositions> > res = new JCG.List <IList <PhrasePositions> >(); if (!hasMultiTermRpts) { // simpler - no multi-terms - can base on positions in first doc for (int i = 0; i < rpp.Length; i++) { PhrasePositions pp = rpp[i]; if (pp.rptGroup >= 0) // already marked as a repetition { continue; } int tpPos = TpPos(pp); for (int j = i + 1; j < rpp.Length; j++) { PhrasePositions pp2 = rpp[j]; if (pp2.rptGroup >= 0 || pp2.offset == pp.offset || TpPos(pp2) != tpPos) // not a repetition - not a repetition: two PPs are originally in same offset in the query! - already marked as a repetition { continue; } // a repetition int g = pp.rptGroup; if (g < 0) { g = res.Count; pp.rptGroup = g; IList <PhrasePositions> rl = new JCG.List <PhrasePositions>(2) { pp }; res.Add(rl); } pp2.rptGroup = g; res[g].Add(pp2); } } } else { // more involved - has multi-terms IList <JCG.HashSet <PhrasePositions> > tmp = new JCG.List <JCG.HashSet <PhrasePositions> >(); IList <FixedBitSet> bb = PpTermsBitSets(rpp, rptTerms); UnionTermGroups(bb); IDictionary <Term, int> tg = TermGroups(rptTerms, bb); JCG.HashSet <int> distinctGroupIDs = new JCG.HashSet <int>(tg.Values); for (int i = 0; i < distinctGroupIDs.Count; i++) { tmp.Add(new JCG.HashSet <PhrasePositions>()); } foreach (PhrasePositions pp in rpp) { foreach (Term t in pp.terms) { if (rptTerms.ContainsKey(t)) { int g = tg[t]; tmp[g].Add(pp); if (Debugging.AssertsEnabled) { Debugging.Assert(pp.rptGroup == -1 || pp.rptGroup == g); } pp.rptGroup = g; } } } foreach (JCG.HashSet <PhrasePositions> hs in tmp) { res.Add(new JCG.List <PhrasePositions>(hs)); } } return(res); }