Merge pull request #1479 from tdonohue/DS-3277

DS-3277 : Create new 'handle_id_seq' for handle_id column. Use 'handle_seq' to mint new handles.
This commit is contained in:
Tim Donohue
2016-08-24 10:14:38 -05:00
committed by GitHub
10 changed files with 202 additions and 16 deletions

View File

@@ -26,8 +26,8 @@ public class Handle implements ReloadableEntity<Integer> {
@Id
@Column(name="handle_id")
@GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="handle_seq")
@SequenceGenerator(name="handle_seq", sequenceName="handle_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="handle_id_seq")
@SequenceGenerator(name="handle_id_seq", sequenceName="handle_id_seq", allocationSize = 1)
private Integer id;
@Column(name = "handle", unique = true)
@@ -57,6 +57,7 @@ public class Handle implements ReloadableEntity<Integer> {
}
@Override
public Integer getID() {
return id;
}
@@ -91,6 +92,7 @@ public class Handle implements ReloadableEntity<Integer> {
return resourceTypeId;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
@@ -105,6 +107,7 @@ public class Handle implements ReloadableEntity<Integer> {
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(id)

View File

@@ -8,20 +8,22 @@
package org.dspace.handle;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.content.DSpaceObject;
import org.dspace.content.service.SiteService;
import org.dspace.core.ConfigurationManager;
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;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Interface to the <a href="http://www.handle.net" target=_new>CNRI Handle
* System </a>.
@@ -46,6 +48,8 @@ public class HandleServiceImpl implements HandleService
@Autowired(required = true)
protected HandleDAO handleDAO;
@Autowired(required = true)
protected ConfigurationService configurationService;
@Autowired
protected SiteService siteService;
@@ -66,7 +70,7 @@ public class HandleServiceImpl implements HandleService
return null;
}
String url = ConfigurationManager.getProperty("dspace.url")
String url = configurationService.getProperty("dspace.url")
+ "/handle/" + handle;
if (log.isDebugEnabled())
@@ -81,9 +85,9 @@ public class HandleServiceImpl implements HandleService
public String resolveUrlToHandle(Context context, String url)
throws SQLException
{
String dspaceUrl = ConfigurationManager.getProperty("dspace.url")
String dspaceUrl = configurationService.getProperty("dspace.url")
+ "/handle/";
String handleResolver = ConfigurationManager.getProperty("handle.canonical.prefix");
String handleResolver = configurationService.getProperty("handle.canonical.prefix");
String handle = null;
@@ -119,8 +123,8 @@ public class HandleServiceImpl implements HandleService
// 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 = ConfigurationManager.getProperty("handle.canonical.prefix");
if (handlePrefix == null || handlePrefix.length() == 0)
String handlePrefix = configurationService.getProperty("handle.canonical.prefix");
if (StringUtils.isBlank(handlePrefix))
{
handlePrefix = "http://hdl.handle.net/";
}
@@ -133,7 +137,7 @@ public class HandleServiceImpl implements HandleService
throws SQLException
{
Handle handle = handleDAO.create(context, new Handle());
String handleId = createId(handle.getID());
String handleId = createId(context);
handle.setHandle(handleId);
handle.setDSpaceObject(dso);
@@ -302,8 +306,8 @@ public class HandleServiceImpl implements HandleService
@Override
public String getPrefix()
{
String prefix = ConfigurationManager.getProperty("handle.prefix");
if (null == prefix)
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);
@@ -386,18 +390,22 @@ public class HandleServiceImpl implements HandleService
}
/**
* Create a new handle id. The implementation uses the PK of the RDBMS
* Handle table.
* Create/mint a new handle id.
*
* @param context DSpace Context
* @return A new handle id
* @exception SQLException
* If a database error occurs
*/
protected String createId(int id) throws SQLException
protected String createId(Context context) throws SQLException
{
// Get configured prefix
String handlePrefix = getPrefix();
return handlePrefix + (handlePrefix.endsWith("/") ? "" : "/") + id;
// 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

View File

@@ -24,6 +24,8 @@ import java.util.List;
*/
public interface HandleDAO extends GenericDAO<Handle> {
public Long getNextHandleSuffix(Context context) throws SQLException;
public List<Handle> getHandlesByDSpaceObject(Context context, DSpaceObject dso) throws SQLException;
public Handle findByHandle(Context context, String handle)throws SQLException;

View File

@@ -7,6 +7,9 @@
*/
package org.dspace.handle.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.core.AbstractHibernateDAO;
@@ -15,6 +18,10 @@ import org.dspace.handle.dao.HandleDAO;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.hibernate.dialect.Dialect;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.service.jdbc.dialect.internal.StandardDialectResolver;
import org.hibernate.service.jdbc.dialect.spi.DialectResolver;
import java.sql.SQLException;
import java.util.Collections;
@@ -29,6 +36,9 @@ import java.util.List;
*/
public class HandleDAOImpl extends AbstractHibernateDAO<Handle> implements HandleDAO
{
// The name of the sequence used to determine next available handle
private static final String HANDLE_SEQUENCE = "handle_seq";
protected HandleDAOImpl()
{
super();
@@ -94,4 +104,45 @@ public class HandleDAOImpl extends AbstractHibernateDAO<Handle> implements Handl
public int countRows(Context context) throws SQLException {
return count(createQuery(context, "SELECT count(*) FROM Handle"));
}
/**
* Return next available value of Handle suffix (based on DB sequence).
* @param context Current DSpace Context
* @return next available Handle suffix (as a Long)
* @throws SQLException if database error or sequence doesn't exist
*/
@Override
public Long getNextHandleSuffix(Context context) throws SQLException
{
// Create a new Hibernate ReturningWork, which will return the
// result of the next value in the Handle Sequence.
ReturningWork<Long> nextValReturningWork = new ReturningWork<Long>() {
@Override
public Long execute(Connection connection) throws SQLException {
Long nextVal = 0L;
// Determine what dialect we are using for this DB
DialectResolver dialectResolver = new StandardDialectResolver();
Dialect dialect = dialectResolver.resolveDialect(connection.getMetaData());
// Find the next value in our sequence (based on DB dialect)
try (PreparedStatement preparedStatement = connection.prepareStatement(dialect.getSequenceNextValString(HANDLE_SEQUENCE)))
{
// Execute query and return results
try(ResultSet resultSet = preparedStatement.executeQuery())
{
if(resultSet.next())
{
// Return result of query (from first column)
nextVal = resultSet.getLong(1);
}
}
}
return nextVal;
}
};
// Run our work, returning the next value in the sequence (see 'nextValReturningWork' above)
return getHibernateSession(context).doReturningWork(nextValReturningWork);
}
}

View File

@@ -0,0 +1,30 @@
--
-- 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/
--
------------------------------------------------------
-- DS-2775 Drop unused sequences
------------------------------------------------------
DROP SEQUENCE bitstream_seq;
DROP SEQUENCE bundle2bitstream_seq;
DROP SEQUENCE bundle_seq;
DROP SEQUENCE collection2item_seq;
DROP SEQUENCE collection_seq;
DROP SEQUENCE community2collection_seq;
DROP SEQUENCE community2community_seq;
DROP SEQUENCE community_seq;
DROP SEQUENCE dcvalue_seq;
DROP SEQUENCE eperson_seq;
DROP SEQUENCE epersongroup2eperson_seq;
DROP SEQUENCE epersongroup2workspaceitem_seq;
DROP SEQUENCE epersongroup_seq;
DROP SEQUENCE group2group_seq;
DROP SEQUENCE group2groupcache_seq;
DROP SEQUENCE historystate_seq;
DROP SEQUENCE item2bundle_seq;
DROP SEQUENCE item_seq;

View File

@@ -0,0 +1,15 @@
--
-- 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/
--
----------------------------------------------------------------------------------
-- DS-3277 : 'handle_id' column needs its own separate sequence, so that Handles
-- can be minted from 'handle_seq'
----------------------------------------------------------------------------------
-- Create a new sequence for 'handle_id' column.
-- The role of this sequence is to simply provide a unique internal ID to the database.
CREATE SEQUENCE handle_id_seq;

View File

@@ -0,0 +1,44 @@
--
-- 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/
--
----------------------------------------------------------------------------------
-- DS-3277 : 'handle_id' column needs its own separate sequence, so that Handles
-- can be minted from 'handle_seq'
----------------------------------------------------------------------------------
-- Create a new sequence for 'handle_id' column.
-- The role of this sequence is to simply provide a unique internal ID to the database.
CREATE SEQUENCE handle_id_seq;
-- Initialize new 'handle_id_seq' to the maximum value of 'handle_id'
DECLARE
curr NUMBER := 0;
BEGIN
SELECT max(handle_id) INTO curr FROM handle;
curr := curr + 1;
EXECUTE IMMEDIATE 'DROP SEQUENCE handle_id_seq';
EXECUTE IMMEDIATE 'CREATE SEQUENCE handle_id_seq START WITH ' || NVL(curr,1);
END;
/
-- Ensure the 'handle_seq' is updated to the maximum *suffix* in 'handle' column,
-- as this sequence is used to mint new Handles.
-- Code borrowed from update-sequences.sql and updateseq.sql
DECLARE
curr NUMBER := 0;
BEGIN
SELECT max(to_number(regexp_replace(handle, '.*/', ''), '999999999999')) INTO curr FROM handle WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$');
curr := curr + 1;
EXECUTE IMMEDIATE 'DROP SEQUENCE handle_seq';
EXECUTE IMMEDIATE 'CREATE SEQUENCE handle_seq START WITH ' || NVL(curr,1);
END;
/

View File

@@ -0,0 +1,30 @@
--
-- 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/
--
----------------------------------------------------------------------------------
-- DS-3277 : 'handle_id' column needs its own separate sequence, so that Handles
-- can be minted from 'handle_seq'
----------------------------------------------------------------------------------
-- Create a new sequence for 'handle_id' column.
-- The role of this sequence is to simply provide a unique internal ID to the database.
CREATE SEQUENCE handle_id_seq;
-- Initialize new 'handle_id_seq' to the maximum value of 'handle_id'
SELECT setval('handle_id_seq', max(handle_id)) FROM handle;
-- Ensure the 'handle_seq' is updated to the maximum *suffix* in 'handle' column,
-- as this sequence is used to mint new Handles.
-- Code borrowed from update-sequences.sql
SELECT setval('handle_seq',
CAST (
max(
to_number(regexp_replace(handle, '.*/', ''), '999999999999')
)
AS BIGINT)
)
FROM handle
WHERE handle SIMILAR TO '%/[0123456789]*';

View File

@@ -61,7 +61,9 @@
@updateseq.sql metadataschemaregistry_seq metadataschemaregistry metadata_schema_id ""
@updateseq.sql harvested_collection_seq harvested_collection id ""
@updateseq.sql harvested_item_seq harvested_item id ""
@updateseq.sql webapp_seq webapp id ""
@updateseq.sql webapp_seq webapp webapp_id ""
@updateseq.sql requestitem_seq requestitem requestitem_id ""
@updateseq.sql handle_id_seq handle handle_id ""
-- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
-- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'

View File

@@ -60,6 +60,7 @@ SELECT setval('harvested_collection_seq', max(id)) FROM harvested_collection;
SELECT setval('harvested_item_seq', max(id)) FROM harvested_item;
SELECT setval('webapp_seq', max(webapp_id)) FROM webapp;
SELECT setval('requestitem_seq', max(requestitem_id)) FROM requestitem;
SELECT setval('handle_id_seq', max(handle_id)) FROM handle;
-- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
-- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'