/** * Search against all repositories using provided parameters. Note there are a few different types * of searches you can perform. If you provide the 'q' query parameter, a keyword search will be * performed. If you provide the 'g, a, v, p or c' query parameters, a maven coordinate search * will be performed. If you provide the 'cn' query parameter, a classname search will be * performed. If you provide the 'sha1' query parameter, a checksum search will be performed. * * @param q provide this param for a keyword search (g, a, v, p, c, cn, sha1 params will be * ignored). * @param sha1 provide this param for a checksum search (g, a, v, p, c, cn params will be * ignored). * @param cn provide this param for a classname search (g, a, v, p, c params will be ignored). * @param g group id to perform a maven search against (can be combined with a, v, p & c params as * well). * @param a artifact id to perform a maven search against (can be combined with g, v, p & c params * as well). * @param v version to perform a maven search against (can be combined with g, a, p & c params as * well). * @param p packaging type to perform a maven search against (can be combined with g, a, v & c * params as well). * @param c classifier to perform a maven search against (can be combined with g, a, v & p params * as well). * @param from result index to start retrieving results from. * @param count number of results to have returned to you. * @param repositoryId The repositoryId to which repository search should be narrowed. Omit if * search should be global. */ @Override @GET @ResourceMethodSignature( queryParams = { @QueryParam("q"), @QueryParam("g"), @QueryParam("a"), @QueryParam("v"), @QueryParam("p"), @QueryParam("c"), @QueryParam("cn"), @QueryParam("sha1"), @QueryParam("from"), @QueryParam("count"), @QueryParam("repositoryId") }, output = SearchResponse.class) public Object get(Context context, Request request, Response response, Variant variant) throws ResourceException { Form form = request.getResourceRef().getQueryAsForm(); final Map<String, String> terms = new HashMap<String, String>(); for (Parameter parameter : form) { terms.put(parameter.getName(), parameter.getValue()); } Integer from = null; Boolean exact = null; String repositoryId = null; Boolean expandVersion = Boolean.FALSE; Boolean collapseResults = Boolean.FALSE; if (form.getFirstValue("from") != null) { try { from = Integer.valueOf(form.getFirstValue("from")); } catch (NumberFormatException e) { from = null; } } int count = LUCENE_HIT_LIMIT; if (form.getFirstValue("count") != null) { try { // capping the possible count count = Math.min(LUCENE_HIT_LIMIT, Integer.valueOf(form.getFirstValue("count"))); } catch (NumberFormatException e) { count = LUCENE_HIT_LIMIT; } } if (form.getFirstValue("repositoryId") != null) { repositoryId = form.getFirstValue("repositoryId"); } if (form.getFirstValue("exact") != null) { exact = Boolean.valueOf(form.getFirstValue("exact")); } if (form.getFirstValue("versionexpand") != null) { expandVersion = Boolean.valueOf(form.getFirstValue("versionexpand")); } if (form.getFirstValue("collapseresults") != null) { collapseResults = Boolean.valueOf(form.getFirstValue("collapseresults")); } // A little explanation about collapseResults, that might seems little bit awkward, since // currently we have only // one column "collapsable" (the version), but before and maybe in the future that's not the // case. So, here is // it: // the "collapseResults" is just a flag "do we allow collapse at all". It is just a shorthand to // turn on or off // collapse generally // Let's assume we have columns colA, colB and colC collapsable. So, instead saying // expandColA=true,expandColB=true,expandColC=true, // it is just easy to say collapseresults=false // BUT, if collapseresults=true is sent by client, even then an "override" will happen if there // is actually NO // ROW to collapse! // So: collapseresults=false EQUALS-TO expandColA=true & expandColB=true & expandColC=true if (collapseResults) { // here we would like to have ANDed all the collapsable column flags and negated the result // currently we collapseResults = !(true && expandVersion); // && expandColA && expandColB; } IteratorSearchResponse searchResult = null; SearchNGResponse result = new SearchNGResponse(); int runCount = 0; while (runCount < RETRIES) { try { List<ArtifactInfoFilter> filters = new ArrayList<ArtifactInfoFilter>(); // we need to save this reference to later SystemWideLatestVersionCollector systemWideCollector = new SystemWideLatestVersionCollector(); filters.add(systemWideCollector); RepositoryWideLatestVersionCollector repositoryWideCollector = null; if (collapseResults) { repositoryWideCollector = new RepositoryWideLatestVersionCollector(); filters.add(repositoryWideCollector); } try { searchResult = searchByTerms( terms, repositoryId, from, count, exact, expandVersion, collapseResults, filters, searchers); if (searchResult == null) { collapseResults = false; continue; } else { repackIteratorSearchResponse( request, terms, result, collapseResults, from, count, searchResult, systemWideCollector, repositoryWideCollector); if (!result.isTooManyResults()) { // if we had collapseResults ON, and the totalHits are larger than actual (filtered) // results, and the actual result count is below COLLAPSE_OVERRIDE_TRESHOLD, // and full result set is smaller than HIT_LIMIT // then repeat without collapse if (collapseResults && result.getData().size() < searchResult.getTotalHitsCount() && result.getData().size() < COLLAPSE_OVERRIDE_TRESHOLD && searchResult.getTotalHitsCount() < GA_HIT_LIMIT) { collapseResults = false; continue; } } } } catch (IOException e) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, e.getMessage(), e); } // we came here, so we break the while-loop, we got what we need break; } catch (NoSuchRepositoryException e) { throw new ResourceException( Status.CLIENT_ERROR_BAD_REQUEST, "Repository to be searched does not exists!", e); } catch (AlreadyClosedException e) { runCount++; getLogger() .info( "NexusIndexer issue (NEXUS-3702), we got AlreadyClosedException that happens when Reindexing or other \"indexer intensive\" task is running on instance while searching! Redoing search again."); if (getLogger().isDebugEnabled()) { // just keep it silent (DEBUG) getLogger().debug("Got AlreadyClosedException exception!", e); } result.setData(null); } } if (result.getData() == null) { try { repackIteratorSearchResponse( request, terms, result, collapseResults, from, count, IteratorSearchResponse.empty(null), null, null); } catch (NoSuchRepositoryException e) { // will not happen } catch (IOException e) { // will not happen } getLogger() .info( "Nexus issue (NEXUS-3702): Was unable to perform search " + RETRIES + " times, giving up, and lying about TooManyResults. Please retry to reproduce this with DEBUG logs and report this issue!"); } return result; }