/** * 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.security; import java.io.IOException; import java.io.InputStreamReader; import java.util.List; import java.util.Map; import org.fcrepo.server.errors.ObjectNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.Builder; import edu.unc.lib.dl.fedora.PID; import edu.unc.lib.dl.util.ContentModelHelper; import edu.unc.lib.dl.util.TripleStoreQueryService; /** * A factory for retrieving information pertaining to patron level access, including publication status and object state * * @author bbpennel * */ public class PatronAccessFactory { private static final Logger log = LoggerFactory.getLogger(PatronAccessFactory.class); private static final String STATE_ACTIVE = ContentModelHelper.FedoraProperty.Active.toString(); private Map<String, Boolean> pid2Publish; private Map<String, Boolean> pid2StateActive; private TripleStoreQueryService tripleStoreQueryService = null; private String getPublishAndStateQuery; public PatronAccessFactory() { Builder<String, Boolean> mapBuilder = new Builder<String, Boolean>(); mapBuilder.maximumWeightedCapacity(256); this.pid2Publish = mapBuilder.build(); this.pid2StateActive = mapBuilder.build(); try { // Cache the query used for retrieving publication and object state java.io.InputStream inStream = this.getClass().getResourceAsStream("/getPublishAndState.itql"); java.io.InputStreamReader inStreamReader = new InputStreamReader(inStream); getPublishAndStateQuery = org.apache.commons.io.IOUtils.toString(inStreamReader); } catch (IOException e) { log.error("Failed to load queries", e); } } public Boolean isPublished(PID pid) throws ObjectNotFoundException { String pidString = pid.getPid(); if (!this.pid2Publish.containsKey(pidString)) { updateCache(pid); } return this.pid2Publish.get(pidString); } public Boolean isStateActive(PID pid) throws ObjectNotFoundException { String pidString = pid.getPid(); if (!this.pid2StateActive.containsKey(pidString)) { updateCache(pid); } return this.pid2StateActive.get(pidString); } private void updateCache(PID pid) throws ObjectNotFoundException { long start = System.currentTimeMillis(); String query = String.format(getPublishAndStateQuery, tripleStoreQueryService.getResourceIndexModelUri(), pid.getURI()); List<List<String>> results = tripleStoreQueryService.queryResourceIndex(query); if (log.isDebugEnabled()) log.debug("Update cache for {} found {}", pid.getPid(), results); // Object was not found if (results.size() == 0) throw new ObjectNotFoundException("Failed to find object " + pid.getPid()); // Since published may or may not be present, we may receive multiple entries for it String pidString = pid.getPid(); boolean published = true; for (List<String> entry : results) { if ("no".equals(entry.get(0))) { published = false; break; } } pid2Publish.put(pidString, published); log.debug("Publication cache for {} set to {}", pidString, published); // State will always be present, so we can use the first value String state = results.get(0).get(1); if (state == null || !STATE_ACTIVE.equals(state)) pid2StateActive.put(pidString, false); else pid2StateActive.put(pidString, true); log.debug("Patron Access Cache updated in {}ms", (System.currentTimeMillis() - start)); } public void invalidate(PID pid) { String pidString = pid.getPid(); log.debug("Invalidating patron access information for {}", pidString); this.pid2Publish.remove(pidString); this.pid2StateActive.remove(pidString); } public TripleStoreQueryService getTripleStoreQueryService() { return tripleStoreQueryService; } public void setTripleStoreQueryService(TripleStoreQueryService tripleStoreQueryService) { this.tripleStoreQueryService = tripleStoreQueryService; } }