/** * 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.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.solr.client.solrj.beans.Field; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.unc.lib.dl.acl.util.ObjectAccessControlsBean; import edu.unc.lib.dl.search.solr.service.ObjectPathFactory; import edu.unc.lib.dl.search.solr.util.SearchFieldKeys; import edu.unc.lib.dl.util.ContentModelHelper; import edu.unc.lib.dl.util.ContentModelHelper.CDRProperty; import edu.unc.lib.dl.util.DateTimeUtil; /** * Stores a single Solr tuple representing an object from a search result. Can be populated directly by Solrj's * queryResponse.getBeans. * * @author bbpennel */ public class BriefObjectMetadataBean extends IndexDocumentBean implements BriefObjectMetadata { private static final Logger LOG = LoggerFactory.getLogger(BriefObjectMetadataBean.class); protected static ObjectPathFactory pathFactory; protected CutoffFacet ancestorPathFacet; protected CutoffFacet path; protected ObjectPath objectPath; protected String ancestorNames; protected String parentName; protected List<MultivaluedHierarchicalFacet> contentTypeFacet; protected List<Datastream> datastreamObjects; // Inverted map of the roleGroup, clustering roles into buckets by group Map<String, Collection<String>> groupRoleMap; protected Map<String, Long> countMap; protected ObjectAccessControlsBean accessControlBean; protected Map<String, List<String>> relationsMap; private List<Tag> tags; public BriefObjectMetadataBean() { countMap = new HashMap<String, Long>(2); } // TODO getDefaultWebData getDefaultWebObject getFilesizeByDatastream public String getIdWithoutPrefix() { int index = id.indexOf(":"); if (index != -1) { return id.substring(index + 1); } return id; } @Override public CutoffFacet getAncestorPathFacet() { return ancestorPathFacet; } public void setAncestorPathFacet(CutoffFacet ancestorPathFacet) { this.ancestorPathFacet = ancestorPathFacet; } @Override @Field public void setAncestorPath(List<String> ancestorPaths) { super.setAncestorPath(ancestorPaths); this.ancestorPathFacet = new CutoffFacet(SearchFieldKeys.ANCESTOR_PATH.name(), ancestorPaths, 0); } /** * Returns a HierarchicalFacet of the full path for this object, including the ancestor path and itself. * * @return */ @Override public CutoffFacet getPath() { if (path == null) { if (this.ancestorPath == null) { this.path = new CutoffFacet(SearchFieldKeys.ANCESTOR_PATH.name(), "1," + this.id + "," + this.title, 0L); } else { path = new CutoffFacet(ancestorPathFacet); path.addNode(id); } } return path; } @Override public List<MultivaluedHierarchicalFacet> getContentTypeFacet() { return contentTypeFacet; } @Field public void setContentType(ArrayList<String> contentTypes) { super.setContentType(contentTypes); this.contentTypeFacet = MultivaluedHierarchicalFacet.createMultivaluedHierarchicalFacets( SearchFieldKeys.CONTENT_TYPE.name(), contentTypes); } @Override public List<Datastream> getDatastreamObjects() { return datastreamObjects; } @Override public Datastream getDatastreamObject(String datastreamName) { if (datastreamName == null || this.datastreamObjects == null) return null; String[] datastreamParts = datastreamName.split("/", 2); String pid; if (datastreamParts.length > 1) { pid = datastreamParts[0]; if (pid.equals(this.id)) { pid = null; } datastreamName = datastreamParts[1]; } else { pid = null; } for (Datastream datastream: this.datastreamObjects) { if (datastream.equals(datastreamName) && (pid == null || pid.equals(datastream.getOwner().getPid()))) return datastream; } return null; } @Override @Field public void setDatastream(List<String> datastream) { super.setDatastream(datastream); datastreamObjects = new ArrayList<Datastream>() { private static final long serialVersionUID = 1L; @Override public boolean contains(Object o) { if (o instanceof String) return indexOf(new Datastream((String) o)) != -1; return indexOf(o) != -1; } }; for (String value : datastream) { datastreamObjects.add(new Datastream(value)); } } @Override @Field public void setRoleGroup(List<String> roleGroup) { super.setRoleGroup(roleGroup); groupRoleMap = new HashMap<String, Collection<String>>(); if (roleGroup != null) { for (String roleGroupPair : roleGroup) { String[] roleGroupData = roleGroupPair.split("\\|"); if (roleGroupData.length == 2) { Collection<String> roles = groupRoleMap.get(roleGroupData[1]); if (roles == null) { roles = new ArrayList<String>(); groupRoleMap.put(roleGroupData[1], roles); } roles.add(roleGroupData[0]); } } } } @Override public Map<String, Collection<String>> getGroupRoleMap() { return groupRoleMap; } public void setAccessControlBean(ObjectAccessControlsBean aclBean) { this.accessControlBean = aclBean; } @Override public ObjectAccessControlsBean getAccessControlBean() { if (this.accessControlBean == null && this.roleGroup != null) { this.accessControlBean = new ObjectAccessControlsBean(pid, this.roleGroup); } return this.accessControlBean; } @Override @Field public void setRelations(List<String> relations) { super.setRelations(relations); this.relationsMap = new HashMap<String, List<String>>(this.relations.size()); for (String relation: this.relations) { if (relation == null) continue; String[] rdfParts = relation.split("\\|", 2); List<String> values = this.relationsMap.get(rdfParts[0]); if (values == null) { values = new ArrayList<String>(); this.relationsMap.put(rdfParts[0], values); } values.add(rdfParts[1]); } } @Override public List<String> getRelation(String relationName) { if (relationsMap == null) return null; return this.relationsMap.get(relationName); } @Override public Datastream getDefaultWebData() { if (this.relationsMap == null) return null; List<String> defaultWebDataValues = this.relationsMap.get(ContentModelHelper.CDRProperty.defaultWebData.getPredicate()); if (defaultWebDataValues == null) return null; String defaultWebData = defaultWebDataValues.get(0); if (defaultWebData == null) return null; return this.getDatastreamObject(defaultWebData); } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("id: " + id + "\n"); sb.append("ancestorPath: " + ancestorPath + "\n"); sb.append("ancestorNames: " + ancestorNames + "\n"); sb.append("resourceType: " + resourceType + "\n"); sb.append("displayOrder: " + displayOrder + "\n"); sb.append("contentType: " + contentType + "\n"); sb.append("datastream: " + datastream + "\n"); sb.append("title: " + title + "\n"); sb.append("abstractText: " + abstractText + "\n"); sb.append("keyword: " + keyword + "\n"); sb.append("subject: " + subject + "\n"); sb.append("language: " + language + "\n"); sb.append("creator: " + creator + "\n"); sb.append("department: " + department + "\n"); sb.append("dateCreated: " + dateCreated + "\n"); sb.append("dateAdded: " + dateAdded + "\n"); sb.append("dateUpdated: " + dateUpdated + "\n"); sb.append("timestamp: " + timestamp + "\n"); sb.append("contentStatus: " + contentStatus + "\n"); return sb.toString(); } @Override public String getParentCollectionName() { if (parentName != null) { return parentName; } if (objectPath == null) { if (pathFactory != null && parentCollection != null) { parentName = pathFactory.getName(parentCollection); } } else { parentName = objectPath.getName(parentCollection); } return parentName; } @Override public Map<String, Long> getCountMap() { return this.countMap; } @Override public void setCountMap(Map<String, Long> countMap) { this.countMap = countMap; } @Override public List<Tag> getTags() { if (this.tags == null) return null; return Collections.unmodifiableList(this.tags); } @Override public void addTag(Tag t) { if (this.tags == null) this.tags = new ArrayList<Tag>(); this.tags.add(t); } @Override public Date getActiveEmbargo() { List<String> embargoUntil = getRelation(CDRProperty.embargoUntil.getPredicate()); if (embargoUntil != null) { Date result = null; Date dateNow = new Date(); for (String embargo : embargoUntil) { Date embargoDate; try { embargoDate = DateTimeUtil.parseUTCToDate(embargo); if (embargoDate.after(dateNow)) { if (result == null || embargoDate.after(result)) { result = embargoDate; } } } catch (ParseException e) { LOG.error("Failed to parse embargo", e); } } return result; } return null; } @Override public ObjectPath getObjectPath() { // Retrieve the ancestor path on demand if it is not already set if (objectPath == null && pathFactory != null) { this.objectPath = pathFactory.getPath(this); } return objectPath; } @Override public void setObjectPath(ObjectPath objectPath) { this.objectPath = objectPath; } public static void setPathFactory(ObjectPathFactory pathFactory) { BriefObjectMetadataBean.pathFactory = pathFactory; } @Override public String getAncestorNames() { if (ancestorNames == null) { if (objectPath == null && pathFactory != null) { objectPath = pathFactory.getPath(this); } if (objectPath != null) { StringBuilder ancestorNames = new StringBuilder(); for (ObjectPathEntry entry : objectPath.getEntries()) { ancestorNames.append('/').append(entry.getName().replaceAll("\\/", "\\\\/")); } this.ancestorNames = ancestorNames.toString(); } } return ancestorNames; } }