/** * Copyright 2008 The University of North Carolina at Chapel Hill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.unc.lib.dl.search.solr.model; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.unc.lib.dl.search.solr.model.BriefObjectMetadata; import edu.unc.lib.dl.search.solr.model.HierarchicalFacetNode; import edu.unc.lib.dl.search.solr.model.SearchResultResponse; import edu.unc.lib.dl.util.ContentModelHelper; public class HierarchicalBrowseResultResponse extends SearchResultResponse { protected static final Logger log = LoggerFactory.getLogger(HierarchicalBrowseResultResponse.class); private Map<String, Long> subcontainerCounts; private Set<String> matchingContainerPids = null; private Long rootCount; private ResultNode rootNode; public HierarchicalBrowseResultResponse() { super(); subcontainerCounts = new HashMap<String, Long>(); matchingContainerPids = new HashSet<String>(); } public void setSearchResultResponse(SearchResultResponse response) { this.setFacetFields(response.getFacetFields()); this.setResultCount(response.getResultCount()); this.setGeneratedQuery(response.getGeneratedQuery()); this.setResultList(response.getResultList()); this.setSearchState(response.getSearchState()); } public Map<String, Long> getSubcontainerCounts() { return subcontainerCounts; } public void setSubcontainerCounts(Map<String, Long> subcontainerCounts) { this.subcontainerCounts = subcontainerCounts; } public void populateSubcontainerCounts(List<FacetField> facetFields) { subcontainerCounts = new HashMap<String, Long>(); for (FacetField facetField : facetFields) { if (facetField.getValues() != null) { for (FacetField.Count facetValue : facetField.getValues()) { log.debug("Popsub|" + facetValue.getName() + ":" + facetValue.getCount()); int index = facetValue.getName().indexOf(","); index = facetValue.getName().indexOf(",", index + 1); if (index != -1) subcontainerCounts.put(facetValue.getName().substring(0, index), facetValue.getCount()); } } } } public void removeContainersWithoutContents() { ListIterator<BriefObjectMetadata> resultIt = this.getResultList().listIterator(this.getResultList().size()); while (resultIt.hasPrevious()) { BriefObjectMetadata briefObject = resultIt.previous(); if (briefObject == null || briefObject.getContentModel() == null) continue; if ((!briefObject.getCountMap().containsKey("child") || briefObject.getCountMap().get("child") == 0) && briefObject.getContentModel().contains(ContentModelHelper.Model.CONTAINER.toString())) { if (this.matchingContainerPids != null && this.matchingContainerPids.contains(briefObject.getId())) { // The container was directly found by the users query, so leave it as is. } else { log.debug("Removing container " + briefObject.getId() + "from hierarchical result because it has no children"); resultIt.remove(); // If an item is being filtered out, then decrement the counts for it and all its ancestors in // subcontainer counts if (briefObject.getAncestorPathFacet() != null && briefObject.getAncestorPathFacet().getFacetNodes() != null) { for (HierarchicalFacetNode facetTier : briefObject.getAncestorPathFacet().getFacetNodes()) { String tierIdentifier = facetTier.getSearchValue(); Long count = this.subcontainerCounts.get(tierIdentifier); if (count != null) this.subcontainerCounts.put(tierIdentifier, count - 1); } } } } } } public void populateMatchingContainerPids(SolrDocumentList containerList, String fieldName) { this.matchingContainerPids = new HashSet<String>(); for (SolrDocument container : containerList) { this.matchingContainerPids.add((String) container.getFirstValue(fieldName)); } } /** * Appends item results to the end of the list and adds them as children of the root. * * @param itemResults */ public void populateItemResults(List<BriefObjectMetadata> itemResults) { this.getResultList().addAll(itemResults); } /** * Generates a tree representation of the current result set and stores its root. * * Assumes the first result is the root node Assumes that the result set is sorted such that if a parent is present, * it will always appear before its children */ public void generateResultTree() { if (this.getResultList() == null || this.getResultList().size() == 0) return; Map<String, ResultNode> nodeMap = new HashMap<String, ResultNode>(); ResultNode parentNode = new ResultNode(this.getResultList().get(0)); nodeMap.put(parentNode.getMetadata().getId(), parentNode); this.rootNode = parentNode; for (int i = 1; i < this.getResultList().size(); i++) { BriefObjectMetadata metadata = this.getResultList().get(i); // Find the closest parent record for (int j = metadata.getAncestorPathFacet().getFacetNodes().size() - 1; j >= 0; j--) { parentNode = nodeMap.get(metadata.getAncestorPathFacet().getFacetNodes().get(j).getSearchKey()); if (parentNode != null) break; } // Couldn't find any parent record, skip this item if (parentNode == null) continue; ResultNode currentNode = new ResultNode(metadata); parentNode.getChildren().add(currentNode); nodeMap.put(metadata.getId(), currentNode); } } public int getChildNodeIndex(String pid) { if (pid == null) return -1; for (int i = 0; i < rootNode.getChildren().size(); i++) { ResultNode childNode = rootNode.getChildren().get(i); if (childNode.getMetadata().getPid().getPid().equals(pid)) return i; } return -1; } public ResultNode findNode(String pid) { return findNode(pid, this.rootNode); } private ResultNode findNode(String pid, ResultNode node) { if (node.getMetadata().getPid().getPid().equals(pid)) return node; for (ResultNode childNode: node.getChildren()) { ResultNode found = findNode(pid, childNode); if (found != null) return found; } return null; } public void addNodes(List<BriefObjectMetadata> nodes) { } public Long getRootCount() { return rootCount; } public void setRootCount(Long rootCount) { this.rootCount = rootCount; } public Set<String> getMatchingContainerPids() { return matchingContainerPids; } public void setMatchingContainerPids(Set<String> matchingContainerPids) { this.matchingContainerPids = matchingContainerPids; } public void setMatchingContainerPids(List<String> matchingContainerPids) { this.matchingContainerPids = new HashSet<String>(matchingContainerPids); } public ResultNode getRootNode() { return rootNode; } public void setRootNode(ResultNode rootNode) { this.rootNode = rootNode; } public static class ResultNode { private BriefObjectMetadata metadata; private List<ResultNode> children; boolean isTopLevel; public ResultNode() { this.children = new ArrayList<ResultNode>(); } public ResultNode(BriefObjectMetadata metadata) { this(); this.metadata = metadata; } public BriefObjectMetadata getMetadata() { return metadata; } public void setMetadata(BriefObjectMetadata metadata) { this.metadata = metadata; } public List<ResultNode> getChildren() { return children; } public void setChildren(List<ResultNode> children) { this.children = children; } public Boolean getIsTopLevel() { if (metadata.getAncestorNames() != null && (metadata.getAncestorPath() == null || metadata.getAncestorPath().size() == 0)) return true; return null; } public void setIsTopLevel(boolean isTopLevel) { this.isTopLevel = isTopLevel; } public ResultNode addChild(BriefObjectMetadata metadata) { ResultNode newNode = new ResultNode(metadata); this.children.add(newNode); return newNode; } } }