All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dspace.handle.HandleServiceImpl Maven / Gradle / Ivy

The newest version!
/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.handle;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject;
import org.dspace.content.service.SiteService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.dao.HandleDAO;
import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Interface to the CNRI Handle
 * System.
 *
 * 

* Currently, this class simply maps handles to local facilities; handles which * are owned by other sites (including other DSpaces) are treated as * non-existent. *

* * @author Peter Breton */ public class HandleServiceImpl implements HandleService { /** * log category */ private static final Logger log = LogManager.getLogger(); /** * Prefix registered to no one */ static final String EXAMPLE_PREFIX = "123456789"; @Autowired(required = true) protected HandleDAO handleDAO; @Autowired(required = true) protected ConfigurationService configurationService; @Autowired protected SiteService siteService; private static final Pattern[] IDENTIFIER_PATTERNS = { Pattern.compile("^hdl:(.*)$"), Pattern.compile("^info:hdl/(.*)$"), Pattern.compile("^https?://hdl\\.handle\\.net/(.*)$"), Pattern.compile("^https?://.+/handle/(.*)$") }; /** * Public Constructor */ protected HandleServiceImpl() { } @Override public String resolveToURL(Context context, String handle) throws SQLException { Handle dbhandle = findHandleInternal(context, handle); if (dbhandle == null) { return null; } String url = configurationService.getProperty("dspace.ui.url") + "/handle/" + handle; log.debug("Resolved {} to {}", handle, url); return url; } @Override public String resolveUrlToHandle(Context context, String url) throws SQLException { String dspaceUrl = configurationService.getProperty("dspace.ui.url") + "/handle/"; String handleResolver = getCanonicalPrefix(); String handle = null; if (url.startsWith(dspaceUrl)) { handle = url.substring(dspaceUrl.length()); } if (url.startsWith(handleResolver)) { handle = url.substring(handleResolver.length()); } if (null == handle) { return null; } // remove trailing slashes while (handle.startsWith("/")) { handle = handle.substring(1); } Handle dbhandle = findHandleInternal(context, handle); return (null == dbhandle) ? null : handle; } @Override public String getCanonicalPrefix() { // Let the admin define a new prefix, if not then we'll use the // CNRI default. This allows the admin to use "hdl:" if they want to or // use a locally branded prefix handle.myuni.edu. String handlePrefix = configurationService.getProperty("handle.canonical.prefix", "https://hdl.handle.net/"); return handlePrefix; } @Override public String getCanonicalForm(String handle) { return getCanonicalPrefix() + handle; } @Override public String createHandle(Context context, DSpaceObject dso) throws SQLException { Handle handle = handleDAO.create(context, new Handle()); String handleId = createId(context); handle.setHandle(handleId); handle.setDSpaceObject(dso); dso.addHandle(handle); handle.setResourceTypeId(dso.getType()); handleDAO.save(context, handle); log.debug("Created new handle for {} (ID={}) {}", () -> Constants.typeText[dso.getType()], () -> dso.getID(), () -> handleId); return handleId; } @Override public String createHandle(Context context, DSpaceObject dso, String suppliedHandle) throws SQLException, IllegalStateException { return createHandle(context, dso, suppliedHandle, false); } @Override public String createHandle(Context context, DSpaceObject dso, String suppliedHandle, boolean force) throws SQLException, IllegalStateException { //Check if the supplied handle is already in use -- cannot use the same handle twice Handle handle = findHandleInternal(context, suppliedHandle); if (handle != null && handle.getDSpaceObject() != null) { //Check if this handle is already linked up to this specified DSpace Object if (handle.getDSpaceObject().getID().equals(dso.getID())) { //This handle already links to this DSpace Object -- so, there's nothing else we need to do return suppliedHandle; } else { //handle found in DB table & already in use by another existing resource throw new IllegalStateException( "Attempted to create a handle which is already in use: " + suppliedHandle); } } else if (handle != null && handle.getResourceTypeId() != null) { //If there is a 'resource_type_id' (but 'resource_id' is empty), then the object using // this handle was previously unbound (see unbindHandle() method) -- likely because object was deleted int previousType = handle.getResourceTypeId(); //Since we are restoring an object to a pre-existing handle, double check we are restoring the same // *type* of object // (e.g. we will not allow an Item to be restored to a handle previously used by a Collection) if (previousType != dso.getType()) { throw new IllegalStateException("Attempted to reuse a handle previously used by a " + Constants.typeText[previousType] + " for a new " + Constants.typeText[dso.getType()]); } } else if (handle == null) { //if handle not found, create it //handle not found in DB table -- create a new table entry handle = handleDAO.create(context, new Handle()); handle.setHandle(suppliedHandle); } handle.setResourceTypeId(dso.getType()); handle.setDSpaceObject(dso); dso.addHandle(handle); handleDAO.save(context, handle); log.debug("Created new handle for {} (ID={}) {}", () -> Constants.typeText[dso.getType()], () -> dso.getID(), () -> suppliedHandle); return suppliedHandle; } @Override public void unbindHandle(Context context, DSpaceObject dso) throws SQLException { Iterator handles = dso.getHandles().iterator(); if (handles.hasNext()) { while (handles.hasNext()) { final Handle handle = handles.next(); handles.remove(); //Only set the "resouce_id" column to null when unbinding a handle. // We want to keep around the "resource_type_id" value, so that we // can verify during a restore whether the same *type* of resource // is reusing this handle! handle.setDSpaceObject(null); handleDAO.save(context, handle); log.debug("Unbound Handle {} from object {} id={}", () -> handle.getHandle(), () -> Constants.typeText[dso.getType()], () -> dso.getID()); } } else { log.trace( "Cannot find Handle entry to unbind for object {} id={}. Handle could have been unbound before.", Constants.typeText[dso.getType()], dso.getID()); } } @Override public DSpaceObject resolveToObject(Context context, String handle) throws IllegalStateException, SQLException { Handle dbhandle = findHandleInternal(context, handle); // check if handle was allocated previously, but is currently not // associated with a DSpaceObject // (this may occur when 'unbindHandle()' is called for an obj that was removed) if (dbhandle == null || (dbhandle.getDSpaceObject() == null) || (dbhandle.getResourceTypeId() == null)) { //if handle has been unbound, just return null (as this will result in a PageNotFound) return null; } return dbhandle.getDSpaceObject(); } @Override public String findHandle(Context context, DSpaceObject dso) throws SQLException { List handles = dso.getHandles(); if (CollectionUtils.isEmpty(handles)) { return null; } else { //TODO: Move this code away from the HandleService & into the Identifier provider //Attempt to retrieve a handle that does NOT look like {handle.part}/{handle.part}.{version} String result = handles.iterator().next().getHandle(); for (Handle handle : handles) { //Ensure that the handle doesn't look like this 12346/213.{version} //If we find a match that indicates that we have a proper handle if (!handle.getHandle().matches(".*/.*\\.\\d+")) { result = handle.getHandle(); } } return result; } } @Override public List getHandlesForPrefix(Context context, String prefix) throws SQLException { List handles = handleDAO.findByPrefix(context, prefix); List handleStrings = new ArrayList<>(handles.size()); for (Handle handle : handles) { handleStrings.add(handle.getHandle()); } return handleStrings; } @Override public String getPrefix() { String prefix = configurationService.getProperty("handle.prefix"); if (StringUtils.isBlank(prefix)) { prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly log.error("handle.prefix is not configured; using {}", prefix); } return prefix; } @Override public long countHandlesByPrefix(Context context, String prefix) throws SQLException { return handleDAO.countHandlesByPrefix(context, prefix); } @Override public int updateHandlesWithNewPrefix(Context context, String newPrefix, String oldPrefix) throws SQLException { return handleDAO.updateHandlesWithNewPrefix(context, newPrefix, oldPrefix); } @Override public void modifyHandleDSpaceObject(Context context, String handle, DSpaceObject newOwner) throws SQLException { Handle dbHandle = findHandleInternal(context, handle); if (dbHandle != null) { // Check if we have to remove the handle from the current handle list // or if object is already deleted. if (dbHandle.getDSpaceObject() != null) { // Remove the old handle from the current handle list dbHandle.getDSpaceObject().getHandles().remove(dbHandle); } // Transfer the current handle to the new object dbHandle.setDSpaceObject(newOwner); dbHandle.setResourceTypeId(newOwner.getType()); newOwner.getHandles().add(0, dbHandle); handleDAO.save(context, dbHandle); } } //////////////////////////////////////// // Internal methods //////////////////////////////////////// /** * Find the database row corresponding to handle. * * @param context DSpace context * @param handle The handle to resolve * @return The database row corresponding to the handle * @throws SQLException If a database error occurs */ protected Handle findHandleInternal(Context context, String handle) throws SQLException { if (handle == null) { throw new IllegalArgumentException("Handle is null"); } return handleDAO.findByHandle(context, handle); } /** * Create/mint a new handle id. * * @param context DSpace Context * @return A new handle id * @throws SQLException If a database error occurs */ protected String createId(Context context) throws SQLException { // Get configured prefix String handlePrefix = getPrefix(); // Get next available suffix (as a Long, since DSpace uses an incrementing sequence) Long handleSuffix = handleDAO.getNextHandleSuffix(context); return handlePrefix + (handlePrefix.endsWith("/") ? "" : "/") + handleSuffix.toString(); } @Override public int countTotal(Context context) throws SQLException { return handleDAO.countRows(context); } @Override public String parseHandle(String identifier) { if (identifier == null) { return null; } if (identifier.startsWith(getPrefix() + "/")) { // prefix is the equivalent of 123456789 in 123456789/???; don't strip return identifier; } String canonicalPrefix = configurationService.getProperty("handle.canonical.prefix"); if (identifier.startsWith(canonicalPrefix + "/")) { // prefix is the equivalent of https://hdl.handle.net/ in https://hdl.handle.net/123456789/???; strip return StringUtils.stripStart(identifier, canonicalPrefix); } for (Pattern pattern : IDENTIFIER_PATTERNS) { Matcher matcher = pattern.matcher(identifier); if (matcher.matches()) { return matcher.group(1); } } // Check additional prefixes supported in the config file String[] additionalPrefixes = getAdditionalPrefixes(); for (String additionalPrefix : additionalPrefixes) { if (identifier.startsWith(additionalPrefix + "/")) { // prefix is the equivalent of 123456789 in 123456789/???; don't strip return identifier; } } return null; } @Override public String[] getAdditionalPrefixes() { return configurationService.getArrayProperty("handle.additional.prefixes"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy