/** * 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.cdr.services.solr; import static edu.unc.lib.dl.util.ContentModelHelper.CDRProperty.embargoUntil; import static edu.unc.lib.dl.util.ContentModelHelper.Datastream.RELS_EXT; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; import org.jdom2.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.unc.lib.dl.fedora.DatastreamDocument; import edu.unc.lib.dl.fedora.FedoraException; import edu.unc.lib.dl.fedora.ManagementClient; import edu.unc.lib.dl.fedora.OptimisticLockException; import edu.unc.lib.dl.fedora.PID; import edu.unc.lib.dl.services.OperationsMessageSender; import edu.unc.lib.dl.util.IndexingActionType; import edu.unc.lib.dl.util.PremisEventLogger; import edu.unc.lib.dl.util.TripleStoreQueryService; import edu.unc.lib.dl.xml.JDOMNamespaceUtil; /** * Service which clears all expired embargoes and triggers reindexing of impacted objects * * @author bbpennel */ public class EmbargoUpdateService { private static final Logger LOG = LoggerFactory.getLogger(EmbargoUpdateService.class); private TripleStoreQueryService tripleStoreQueryService; private ManagementClient managementClient; private OperationsMessageSender messageSender; private static final String EMBARGO_USER = "embargo-update-service"; private final String staleEmbargoQuery; public EmbargoUpdateService() throws IOException { staleEmbargoQuery = IOUtils.toString( this.getClass().getResourceAsStream("embargo-update-candidates.sparql"), "UTF-8"); } public void updateEmbargoes() { List<PID> candidates = this.findCandidateObjects(); LOG.info("Clearing {} expired embargoes", candidates.size()); if (candidates != null && candidates.size() > 0) { // Remove expired embargoes for (PID pid : candidates) { removeEmbargo(pid); } // Trigger reindexing of newly unembargoed objects messageSender.sendIndexingOperation(EMBARGO_USER, candidates, IndexingActionType.UPDATE_ACCESS); } } @SuppressWarnings({ "unchecked", "rawtypes" }) private List<PID> findCandidateObjects() { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); String windowEnd = formatter.format(calendar.getTime()); // replace model URI and date tokens String query = String.format(staleEmbargoQuery, tripleStoreQueryService.getResourceIndexModelUri(), windowEnd); List<PID> expiringEmbargoes = new ArrayList<>(); List<Map> bindings = (List<Map>) ((Map) tripleStoreQueryService.sendSPARQL(query).get("results")) .get("bindings"); for (Map binding : bindings) { expiringEmbargoes.add(new PID((String) ((Map) binding.get("pid")).get("value"))); } return expiringEmbargoes; } private void removeEmbargo(PID pid) { while (true) { try { DatastreamDocument ds = managementClient.getXMLDatastreamIfExists(pid, RELS_EXT.getName()); Element descEl = ds.getDocument().getRootElement().getChild("Description", JDOMNamespaceUtil.RDF_NS); String embargo = descEl.getChildTextTrim(embargoUntil.getPredicate(), embargoUntil.getNamespace()); descEl.removeChildren(embargoUntil.getPredicate(), embargoUntil.getNamespace()); managementClient.modifyDatastream(pid, RELS_EXT.getName(), "Clearing expired embargo", ds.getLastModified(), ds.getDocument()); // Record an event indicating that an embargo expired for this object PremisEventLogger logger = new PremisEventLogger(EMBARGO_USER); Element event = logger.logEvent(PremisEventLogger.Type.MIGRATION, "Embargo expiration", pid); PremisEventLogger.addDetailedOutcome(event, "success", "Expired an embargo which ended " + embargo, null); managementClient.writePremisEventsToFedoraObject(logger, pid); return; } catch (OptimisticLockException e) { LOG.debug("Failed to get optimistic lock on {}, retrying", pid); } catch (FedoraException e) { LOG.error("Failed to clear embargo on {}", pid, e); return; } } } public void setTripleStoreQueryService(TripleStoreQueryService tripleStoreQueryService) { this.tripleStoreQueryService = tripleStoreQueryService; } public void setManagementClient(ManagementClient managementClient) { this.managementClient = managementClient; } public void setMessageSender(OperationsMessageSender messageSender) { this.messageSender = messageSender; } }