diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index 729124b5271..f64d6818f94 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -124,7 +124,7 @@ Out of the box, Dataverse is configured for DOIs. Here are the configuration opt - :ref:`:DoiProvider <:DoiProvider>` - :ref:`:Protocol <:Protocol>` - :ref:`:Authority <:Authority>` -- :ref:`:DoiSeparator <:DoiSeparator>` +- :ref:`:Shoulder <:Shoulder>` - :ref:`:IdentifierGenerationStyle <:IdentifierGenerationStyle>` (optional) - :ref:`:DataFilePIDFormat <:DataFilePIDFormat>` (optional) @@ -552,7 +552,7 @@ See also these related database settings below: - :ref:`:DoiProvider` - :ref:`:Protocol` - :ref:`:Authority` -- :ref:`:DoiSeparator` +- :ref:`:Shoulder` .. _doi.username: @@ -717,7 +717,7 @@ As of this writing "EZID" and "DataCite" are the only valid options. DoiProvider ``curl -X PUT -d EZID http://localhost:8080/api/admin/settings/:DoiProvider`` -This setting relates to the ``:Protocol``, ``:Authority``, ``:DoiSeparator``, and ``:IdentifierGenerationStyle`` database settings below as well as the following JVM options: +This setting relates to the ``:Protocol``, ``:Authority``, ``:Shoulder``, and ``:IdentifierGenerationStyle`` database settings below as well as the following JVM options: - :ref:`doi.baseurlstring` - :ref:`doi.username` @@ -741,25 +741,23 @@ Use the authority assigned to you by your DoiProvider or HandleProvider. ``curl -X PUT -d 10.xxxx http://localhost:8080/api/admin/settings/:Authority`` -.. _:DoiSeparator: +.. _:Shoulder: -:DoiSeparator -+++++++++++++ - -It is recommended that you keep this as a slash ("/"). +:Shoulder +++++++++++++ -``curl -X PUT -d "/" http://localhost:8080/api/admin/settings/:DoiSeparator`` +Out of the box, the DOI shoulder is set to "FK2/" but this is for testing only! When you apply for your DOI namespace, you may have requested a shoulder. The following is only an example and a trailing slash is optional. -**Note:** The name DoiSeparator is a misnomer. This setting is used by some **handles**-specific code too. It *must* be set to '/' when using handles. +``curl -X PUT -d "MyShoulder/" http://localhost:8080/api/admin/settings/:Shoulder`` .. _:IdentifierGenerationStyle: :IdentifierGenerationStyle ++++++++++++++++++++++++++ -By default, Dataverse generates a random 6 character string to use as the identifier +By default, Dataverse generates a random 6 character string, pre-pended by the Shoulder if set, to use as the identifier for a Dataset. Set this to ``sequentialNumber`` to use sequential numeric values -instead. (the assumed default setting is ``randomString``). +instead (again pre-pended by the Shoulder if set). (the assumed default setting is ``randomString``). In addition to this setting, a database sequence must be created in the database. We provide the script below (downloadable :download:`here `). You may need to make some changes to suit your system setup, see the comments for more information: @@ -785,7 +783,7 @@ This setting controls the way that the "identifier" component of a file's persis By default the identifier for a file is dependent on its parent dataset. For example, if the identifier of a dataset is "TJCLKP", the identifier for a file within that dataset will consist of the parent dataset's identifier followed by a slash ("/"), followed by a random 6 character string, yielding "TJCLKP/MLGWJO". Identifiers in this format are what you should expect if you leave ``:DataFilePIDFormat`` undefined or set it to ``DEPENDENT`` and have not changed the ``:IdentifierGenerationStyle`` setting from its default. -Alternatively, the indentifier for File PIDs can be configured to be independent of Dataset PIDs using the setting "``INDEPENDENT``". In this case, file PIDs will not contain the PIDs of their parent datasets, and their PIDs will be generated the exact same way that datasets' PIDs are, based on the ``:IdentifierGenerationStyle`` setting described above (random 6 character strings or sequential numbers). +Alternatively, the identifier for File PIDs can be configured to be independent of Dataset PIDs using the setting "``INDEPENDENT``". In this case, file PIDs will not contain the PIDs of their parent datasets, and their PIDs will be generated the exact same way that datasets' PIDs are, based on the ``:IdentifierGenerationStyle`` setting described above (random 6 character strings or sequential numbers, pre-pended by any shoulder). The chart below shows examples from each possible combination of parameters from the two settings. ``:IdentifierGenerationStyle`` can be either ``randomString`` (the default) or ``sequentialNumber`` and ``:DataFilePIDFormat`` can be either ``DEPENDENT`` (the default) or ``INDEPENDENT``. In the examples below the "identifier" for the dataset is "TJCLKP" for "randomString" and "100001" for "sequentialNumber". diff --git a/scripts/api/setup-all.sh b/scripts/api/setup-all.sh index 56cc24b4af8..03cb2252f2c 100755 --- a/scripts/api/setup-all.sh +++ b/scripts/api/setup-all.sh @@ -49,9 +49,9 @@ curl -X PUT -d yes "$SERVER/admin/settings/:AllowSignUp" curl -X PUT -d /dataverseuser.xhtml?editMode=CREATE "$SERVER/admin/settings/:SignUpUrl" curl -X PUT -d doi "$SERVER/admin/settings/:Protocol" -curl -X PUT -d 10.5072/FK2 "$SERVER/admin/settings/:Authority" +curl -X PUT -d 10.5072 "$SERVER/admin/settings/:Authority" +curl -X PUT -d "FK2/" "$SERVER/admin/settings/:Shoulder" curl -X PUT -d EZID "$SERVER/admin/settings/:DoiProvider" -curl -X PUT -d / "$SERVER/admin/settings/:DoiSeparator" curl -X PUT -d burrito $SERVER/admin/settings/BuiltinUsers.KEY curl -X PUT -d localhost-only $SERVER/admin/settings/:BlockedApiPolicy echo diff --git a/scripts/api/setup-optional-harvard.sh b/scripts/api/setup-optional-harvard.sh index 2478ae139f9..b4dd6b33b53 100755 --- a/scripts/api/setup-optional-harvard.sh +++ b/scripts/api/setup-optional-harvard.sh @@ -2,6 +2,9 @@ SERVER=http://localhost:8080/api echo "Setting up Harvard-specific settings" +# :Authority and :Shoulder are commented out so this script can be used on test servers +#curl -X PUT -d 10.7910 "$SERVER/admin/settings/:Authority" +#curl -X PUT -d "DVN/" "$SERVER/admin/settings/:Shoulder" echo "- Application Status header" curl -s -X PUT -d 'Upgrade in progress...' $SERVER/admin/settings/:StatusMessageHeader echo "- Application Status message" diff --git a/scripts/database/upgrades/upgrade_v4.8.6_to_v4.9.0.sql b/scripts/database/upgrades/upgrade_v4.8.6_to_v4.9.0.sql index 77d727ad48c..d19a7f4e9c9 100644 --- a/scripts/database/upgrades/upgrade_v4.8.6_to_v4.9.0.sql +++ b/scripts/database/upgrades/upgrade_v4.8.6_to_v4.9.0.sql @@ -1,56 +1,71 @@ -ALTER TABLE externaltool ADD COLUMN type character varying(255); -ALTER TABLE externaltool ALTER COLUMN type SET NOT NULL; --- Previously, the only explore tool was TwoRavens. We now persist the name of the tool. -UPDATE guestbookresponse SET downloadtype = 'TwoRavens' WHERE downloadtype = 'Explore'; -ALTER TABLE filemetadata ADD COLUMN prov_freeform text; --- ALTER TABLE datafile ADD COLUMN prov_cplid int; -ALTER TABLE datafile ADD COLUMN prov_entityname text; - --- Moves DOI fields from Dataset to DVObject --- so that Identifiers may be added to DataFiles - -ALTER TABLE dvobject ADD COLUMN - authority character varying(255), - ADD COLUMN doiseparator character varying(255), - ADD COLUMN globalidcreatetime timestamp without time zone, - ADD COLUMN identifierRegistered boolean, - ADD COLUMN identifier character varying(255), - ADD COLUMN protocol character varying(255); - - -UPDATE dvobject -SET authority=(SELECT dataset.authority -FROM dataset -WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; - -UPDATE dvobject -SET doiseparator=(SELECT dataset.doiseparator -FROM dataset -WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; - -UPDATE dvobject -SET globalidcreatetime=(SELECT dataset.globalidcreatetime -FROM dataset -WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; - -UPDATE dvobject -SET identifierRegistered= true where globalidcreatetime is not null; - -UPDATE dvobject -SET identifier=(SELECT dataset.identifier -FROM dataset -WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; - -UPDATE dvobject -SET protocol=(SELECT dataset.protocol -FROM dataset -WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; - -ALTER TABLE dataset ALTER identifier DROP NOT NULL; - -ALTER TABLE dataset DROP COLUMN authority; -ALTER TABLE dataset DROP COLUMN doiseparator; -ALTER TABLE dataset DROP COLUMN globalidcreatetime; -ALTER TABLE dataset DROP COLUMN identifier; -ALTER TABLE dataset DROP COLUMN protocol; - +ALTER TABLE externaltool ADD COLUMN type character varying(255); +ALTER TABLE externaltool ALTER COLUMN type SET NOT NULL; +-- Previously, the only explore tool was TwoRavens. We now persist the name of the tool. +UPDATE guestbookresponse SET downloadtype = 'TwoRavens' WHERE downloadtype = 'Explore'; +ALTER TABLE filemetadata ADD COLUMN prov_freeform text; +-- ALTER TABLE datafile ADD COLUMN prov_cplid int; +ALTER TABLE datafile ADD COLUMN prov_entityname text; + +-- Moves DOI fields from Dataset to DVObject +-- so that Identifiers may be added to DataFiles + +ALTER TABLE dvobject ADD COLUMN + authority character varying(255), + ADD COLUMN globalidcreatetime timestamp without time zone, + ADD COLUMN doiseparator character varying(255), + ADD COLUMN identifierRegistered boolean, + ADD COLUMN identifier character varying(255), + ADD COLUMN protocol character varying(255); + +--Migrate data from Dataset to DvObject +UPDATE dvobject +SET authority=(SELECT dataset.authority +FROM dataset +WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; + +UPDATE dvobject +SET globalidcreatetime=(SELECT dataset.globalidcreatetime +FROM dataset +WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; + +UPDATE dvobject +SET doiseparator=(SELECT dataset.doiseparator +FROM dataset +WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; + +UPDATE dvobject +SET identifierRegistered= true where globalidcreatetime is not null; + +UPDATE dvobject +SET identifier=(SELECT dataset.identifier +FROM dataset +WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset') where dvobject.dtype='Dataset'; + +UPDATE dvobject +SET protocol=(SELECT dataset.protocol +FROM dataset +WHERE dataset.id=dvobject.id AND dvobject.dtype='Dataset' ) where dvobject.dtype='Dataset'; + +--Once in DvObject re-parse identifier and authority +UPDATE dvobject SET identifier=substring(authority, strpos(authority,'/')+1) || doiseparator || identifier WHERE strpos(authority,'/')>0 ; +UPDATE dvobject SET authority=substring(authority from 0 for strpos(authority,'/')) WHERE strpos(authority,'/')>0; + +ALTER TABLE dataset ALTER identifier DROP NOT NULL; + +ALTER TABLE dataset DROP COLUMN authority; +ALTER TABLE dataset DROP COLUMN doiseparator; +ALTER TABLE dataset DROP COLUMN globalidcreatetime; +ALTER TABLE dataset DROP COLUMN identifier; +ALTER TABLE dataset DROP COLUMN protocol; + +ALTER TABLE dvobject DROP COLUMN doiseparator; + +--Add new setting into content for shoulder +INSERT INTO setting(name, content) +VALUES (':Shoulder', (SELECT substring(content, strpos(content,'/')+1) || '/' from setting where name = ':Authority')); + + --strip shoulder from authority setting + UPDATE setting + SET content=(SELECT substring(content from 0 for strpos(content,'/')) + FROM setting + WHERE name=':Authority' and strpos(content,'/')>0) where name=':Authority'; diff --git a/src/main/java/edu/harvard/iq/dataverse/AbstractIdServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/AbstractIdServiceBean.java index 1f5ab39a9a3..11a28bebe20 100644 --- a/src/main/java/edu/harvard/iq/dataverse/AbstractIdServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/AbstractIdServiceBean.java @@ -26,9 +26,9 @@ public abstract class AbstractIdServiceBean implements IdServiceBean { SystemConfig systemConfig; @Override - public String getIdentifierForLookup(String protocol, String authority, String separator, String identifier) { + public String getIdentifierForLookup(String protocol, String authority, String identifier) { logger.log(Level.FINE,"getIdentifierForLookup"); - return protocol + ":" + authority + separator + identifier; + return protocol + ":" + authority + "/" + identifier; } @@ -96,7 +96,6 @@ public DvObject generateIdentifier(DvObject dvObject) { String protocol = dvObject.getProtocol() == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Protocol) : dvObject.getProtocol(); String authority = dvObject.getAuthority() == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Authority) : dvObject.getAuthority(); - String doiSeparator = dvObject.getDoiSeparator() == null ? settingsService.getValueForKey(SettingsServiceBean.Key.DoiSeparator) : dvObject.getDoiSeparator(); IdServiceBean idServiceBean = IdServiceBean.getBean(protocol, commandEngine.getContext()); if (dvObject.isInstanceofDataset()) { dvObject.setIdentifier(datasetService.generateDatasetIdentifier((Dataset) dvObject, idServiceBean)); @@ -109,9 +108,6 @@ public DvObject generateIdentifier(DvObject dvObject) { if (dvObject.getAuthority() == null) { dvObject.setAuthority(authority); } - if (dvObject.getDoiSeparator() == null) { - dvObject.setDoiSeparator(doiSeparator); - } return dvObject; } } diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java index 4f160f832e1..44a7e9efad9 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DOIDataCiteServiceBean.java @@ -95,15 +95,14 @@ public HashMap getIdentifierMetadata(DvObject dvObject) { * Looks up the metadata for a Global Identifier * @param protocol the identifier system, e.g. "doi" * @param authority the namespace that the authority manages in the identifier system - * @param separator the string that separates authority from local identifier part * @param identifier the local identifier part * @return a Map of metadata. It is empty when the lookup failed, e.g. when * the identifier does not exist. */ @Override - public HashMap lookupMetadataFromIdentifier(String protocol, String authority, String separator, String identifier) { + public HashMap lookupMetadataFromIdentifier(String protocol, String authority, String identifier) { logger.log(Level.FINE,"lookupMetadataFromIdentifier"); - String identifierOut = getIdentifierForLookup(protocol, authority, separator, identifier); + String identifierOut = getIdentifierForLookup(protocol, authority, identifier); HashMap metadata = new HashMap<>(); try { metadata = doiDataCiteRegisterService.getMetadata(identifierOut); diff --git a/src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java index 62a1504d384..4ed7003252a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DOIEZIdServiceBean.java @@ -99,16 +99,15 @@ public HashMap getIdentifierMetadata(DvObject dvObject) { * @param protocol the identifier system, e.g. "doi" * @param authority the namespace that the authority manages in the * identifier system - * @param separator the string that separates authority from local * identifier part * @param identifier the local identifier part * @return a Map of metadata. It is empty when the lookup failed, e.g. when * the identifier does not exist. */ @Override - public HashMap lookupMetadataFromIdentifier(String protocol, String authority, String separator, String identifier) { + public HashMap lookupMetadataFromIdentifier(String protocol, String authority, String identifier) { logger.log(Level.FINE,"lookupMetadataFromIdentifier"); - String identifierOut = getIdentifierForLookup(protocol, authority, separator, identifier); + String identifierOut = getIdentifierForLookup(protocol, authority, identifier); HashMap metadata = new HashMap<>(); try { metadata = ezidService.getMetadata(identifierOut); @@ -181,7 +180,7 @@ public void deleteIdentifier(DvObject dvObject) throws Exception { updateIdentifierStatus(dvObject, "unavailable | withdrawn by author"); HashMap metadata = new HashMap<>(); metadata.put("_target", "http://ezid.cdlib.org/id/" + dvObject.getProtocol() + ":" + dvObject.getAuthority() - + dvObject.getDoiSeparator() + dvObject.getIdentifier()); + + "/" + dvObject.getIdentifier()); try { modifyIdentifierTargetURL(dvObject); if (dvObject instanceof Dataset ) { @@ -189,7 +188,7 @@ public void deleteIdentifier(DvObject dvObject) throws Exception { for (DataFile df : dataset.getFiles()) { metadata = new HashMap<>(); metadata.put("_target", "http://ezid.cdlib.org/id/" + df.getProtocol() + ":" + df.getAuthority() - + df.getDoiSeparator() + df.getIdentifier()); + + "/" + df.getIdentifier()); modifyIdentifierTargetURL(df); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java index c221ae3134d..ea55ed918c1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataFileServiceBean.java @@ -53,7 +53,7 @@ public class DataFileServiceBean implements java.io.Serializable { private static final Logger logger = Logger.getLogger(DataFileServiceBean.class.getCanonicalName()); @EJB - DatasetServiceBean datasetService; + DvObjectServiceBean dvObjectService; @EJB PermissionServiceBean permissionService; @EJB @@ -165,26 +165,7 @@ public DataFile find(Object pk) { }*/ public DataFile findByGlobalId(String globalId) { - -/* - Concatenate pieces of global Id for selection until more permanent fix implemented - */ - String queryStr = "select s.id from dvobject s where s.protocol || ':' || s.authority || s.doiseparator || s.identifier = '" + globalId +"'"; - - DataFile file = null; - try { - Query query = em.createNativeQuery(queryStr); - Long fileId = new Long((Integer) query.getSingleResult()); - file = em.find(DataFile.class, fileId); - - } catch (javax.persistence.NoResultException e) { - // (set to .info, this can fill the log file with thousands of - // these messages during a large harvest run) - logger.fine("no file found: " + globalId); - // DO nothing, just return null. - } - return file; - + return (DataFile) dvObjectService.findByGlobalId(globalId, DataFile.DATAFILE_DTYPE_STRING); } public DataFile findReplacementFile(Long previousFileId){ @@ -1537,39 +1518,42 @@ public List selectFilesWithMissingOriginalTypes() { public String generateDataFileIdentifier(DataFile datafile, IdServiceBean idServiceBean) { String doiIdentifierType = settingsService.getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "randomString"); String doiDataFileFormat = settingsService.getValueForKey(SettingsServiceBean.Key.DataFilePIDFormat, "DEPENDENT"); - - String datasetIdentifer = ""; - //If format is dependent then pre-pend the dataset identifier - if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.DEPENDENT.toString())){ - datasetIdentifer = datafile.getOwner().getIdentifier() + "/"; + + String prepend = ""; + if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.DEPENDENT.toString())){ + //If format is dependent then pre-pend the dataset identifier + prepend = datafile.getOwner().getIdentifier() + "/"; + } else { + //If there's a shoulder prepend independent identifiers with it + prepend = settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder, ""); } switch (doiIdentifierType) { case "randomString": - return datasetIdentifer + generateIdentifierAsRandomString(datafile, idServiceBean); + return generateIdentifierAsRandomString(datafile, idServiceBean, prepend); case "sequentialNumber": if (doiDataFileFormat.equals(SystemConfig.DataFilePIDFormat.INDEPENDENT.toString())){ - return generateIdentifierAsIndependentSequentialNumber(datafile, idServiceBean); + return generateIdentifierAsIndependentSequentialNumber(datafile, idServiceBean, prepend); } else { - return generateIdentifierAsDependentSequentialNumber(datafile, idServiceBean); + return generateIdentifierAsDependentSequentialNumber(datafile, idServiceBean, prepend); } default: /* Should we throw an exception instead?? -- L.A. 4.6.2 */ - return datasetIdentifer + generateIdentifierAsRandomString(datafile, idServiceBean); + return generateIdentifierAsRandomString(datafile, idServiceBean, prepend); } } - private String generateIdentifierAsRandomString(DataFile datafile, IdServiceBean idServiceBean) { + private String generateIdentifierAsRandomString(DataFile datafile, IdServiceBean idServiceBean, String prepend) { String identifier = null; do { - identifier = RandomStringUtils.randomAlphanumeric(6).toUpperCase(); + identifier = prepend + RandomStringUtils.randomAlphanumeric(6).toUpperCase(); } while (!isIdentifierUniqueInDatabase(identifier, datafile, idServiceBean)); return identifier; } - private String generateIdentifierAsIndependentSequentialNumber(DataFile datafile, IdServiceBean idServiceBean) { + private String generateIdentifierAsIndependentSequentialNumber(DataFile datafile, IdServiceBean idServiceBean, String prepend) { String identifier; do { @@ -1581,13 +1565,13 @@ private String generateIdentifierAsIndependentSequentialNumber(DataFile datafile if (identifierNumeric == null) { return null; } - identifier = identifierNumeric.toString(); + identifier = prepend + identifierNumeric.toString(); } while (!isIdentifierUniqueInDatabase(identifier, datafile, idServiceBean)); return identifier; } - private String generateIdentifierAsDependentSequentialNumber(DataFile datafile, IdServiceBean idServiceBean) { + private String generateIdentifierAsDependentSequentialNumber(DataFile datafile, IdServiceBean idServiceBean, String prepend) { String identifier; Long retVal; @@ -1597,7 +1581,7 @@ private String generateIdentifierAsDependentSequentialNumber(DataFile datafile, do { retVal++; - identifier = datafile.getOwner().getIdentifier() + "/" + retVal.toString(); + identifier = prepend + retVal.toString(); } while (!isIdentifierUniqueInDatabase(identifier, datafile, idServiceBean)); diff --git a/src/main/java/edu/harvard/iq/dataverse/Dataset.java b/src/main/java/edu/harvard/iq/dataverse/Dataset.java index faf33db6b1f..ee240029d0b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Dataset.java +++ b/src/main/java/edu/harvard/iq/dataverse/Dataset.java @@ -38,8 +38,6 @@ * @author skraffmiller */ @NamedQueries({ - @NamedQuery(name = "Dataset.findByIdentifier", - query = "SELECT d FROM Dataset d WHERE d.identifier=:identifier"), @NamedQuery(name = "Dataset.findByOwnerIdentifier", query = "SELECT o.identifier FROM DvObject o WHERE o.owner.id=:owner_id") }) @@ -73,8 +71,7 @@ sequence. Used when the Dataverse is (optionally) configured to use @Entity @Table(indexes = { @Index(columnList = "guestbook_id"), - @Index(columnList = "thumbnailfile_id")}, - uniqueConstraints = @UniqueConstraint(columnNames = {"authority,protocol,identifier,doiseparator"})) + @Index(columnList = "thumbnailfile_id")}) public class Dataset extends DvObjectContainer { public static final String TARGET_URL = "/citation?persistentId="; @@ -84,18 +81,9 @@ public class Dataset extends DvObjectContainer { @OrderBy("id") private List files = new ArrayList<>(); - private String protocol; - private String authority; - private String doiSeparator; - - @Temporal(value = TemporalType.TIMESTAMP) - private Date globalIdCreateTime; - @Temporal(value = TemporalType.TIMESTAMP) private Date lastExportTime; - @Column(nullable = false) - private String identifier; @OneToMany(mappedBy = "dataset", orphanRemoval = true, cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}) @OrderBy("versionNumber DESC, minorVersionNumber DESC") @@ -631,7 +619,7 @@ public String getRemoteArchiveURL() { // the study: //String icpsrId = identifier; //return this.getOwner().getHarvestingClient().getArchiveUrl() + "/icpsrweb/ICPSR/studies/"+icpsrId+"?q="+icpsrId+"&searchSource=icpsr-landing"; - return "http://doi.org/" + authority + "/" + identifier; + return "http://doi.org/" + this.getAuthority() + "/" + this.getIdentifier(); } else if (HarvestingClient.HARVEST_STYLE_NESSTAR.equals(this.getHarvestedFrom().getHarvestStyle())) { String nServerURL = this.getHarvestedFrom().getArchiveUrl(); // chop any trailing slashes in the server URL - or they will result @@ -646,12 +634,12 @@ public String getRemoteArchiveURL() { String NesstarWebviewPage = nServerURL + "/webview/?mode=documentation&submode=abstract&studydoc=" + nServerURLencoded + "%2Fobj%2FfStudy%2F" - + identifier + + this.getIdentifier() + "&top=yes"; return NesstarWebviewPage; } else if (HarvestingClient.HARVEST_STYLE_ROPER.equals(this.getHarvestedFrom().getHarvestStyle())) { - return this.getHarvestedFrom().getArchiveUrl() + "/CFIDE/cf/action/catalog/abstract.cfm?archno=" + identifier; + return this.getHarvestedFrom().getArchiveUrl() + "/CFIDE/cf/action/catalog/abstract.cfm?archno=" + this.getIdentifier(); } else if (HarvestingClient.HARVEST_STYLE_HGL.equals(this.getHarvestedFrom().getHarvestStyle())) { // a bit of a hack, true. // HGL documents, when turned into Dataverse studies/datasets diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index 4f9982647d5..68564166015 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -221,7 +221,6 @@ public enum DisplayMode { private String version; private String protocol = ""; private String authority = ""; - private String separator = ""; private String customFields=""; private boolean noDVsAtAll = false; @@ -1368,8 +1367,6 @@ private String init(boolean initFull) { String nonNullDefaultIfKeyNotFound = ""; protocol = settingsWrapper.getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); authority = settingsWrapper.getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - separator = settingsWrapper.getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound); - if (dataset.getId() != null || versionId != null || persistentId != null) { // view mode for a dataset DatasetVersionServiceBean.RetrieveDatasetVersionResponse retrieveDatasetVersionResponse = null; @@ -1517,9 +1514,7 @@ private String init(boolean initFull) { dataset.setOwner(dataverseService.find(ownerId)); dataset.setProtocol(protocol); dataset.setAuthority(authority); - dataset.setDoiSeparator(separator); //Wait until the create command before actually getting an identifier - //dataset.setIdentifier(datasetService.generateDatasetIdentifier(protocol, authority, separator)); if (dataset.getOwner() == null) { return permissionsWrapper.notFound(); diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java index fc847ac0ef8..b62e98a54c0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java @@ -73,6 +73,9 @@ public class DatasetServiceBean implements java.io.Serializable { @EJB DatasetVersionServiceBean versionService; + @EJB + DvObjectServiceBean dvObjectService; + @EJB AuthenticationServiceBean authentication; @@ -191,48 +194,35 @@ public Dataset merge( Dataset ds ) { } public Dataset findByGlobalId(String globalId) { -/* - Concatenate pieces of global Id for selection until more permanent fix implemented - */ - String queryStr = "select s.id from dvobject s where s.protocol || ':' || s.authority || s.doiseparator || s.identifier = '" + globalId +"'"; - Dataset foundDataset = null; - try { - Query query = em.createNativeQuery(queryStr); - Long datasetId = new Long((Integer) query.getSingleResult()); - foundDataset = em.find(Dataset.class, datasetId); - } catch (javax.persistence.NoResultException e) { - // (set to .info, this can fill the log file with thousands of - // these messages during a large harvest run) - logger.fine("no ds found: " + globalId); - // DO nothing, just return null. - } - return foundDataset; + return (Dataset) dvObjectService.findByGlobalId(globalId, Dataset.DATASET_DTYPE_STRING); } public String generateDatasetIdentifier(Dataset dataset, IdServiceBean idServiceBean) { - String doiIdentifierType = settingsService.getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "randomString"); - switch (doiIdentifierType) { + String identifierType = settingsService.getValueForKey(SettingsServiceBean.Key.IdentifierGenerationStyle, "randomString"); + String shoulder = settingsService.getValueForKey(SettingsServiceBean.Key.Shoulder, ""); + + switch (identifierType) { case "randomString": - return generateIdentifierAsRandomString(dataset, idServiceBean); + return generateIdentifierAsRandomString(dataset, idServiceBean, shoulder); case "sequentialNumber": - return generateIdentifierAsSequentialNumber(dataset, idServiceBean); + return generateIdentifierAsSequentialNumber(dataset, idServiceBean, shoulder); default: /* Should we throw an exception instead?? -- L.A. 4.6.2 */ - return generateIdentifierAsRandomString(dataset, idServiceBean); + return generateIdentifierAsRandomString(dataset, idServiceBean, shoulder); } } - private String generateIdentifierAsRandomString(Dataset dataset, IdServiceBean idServiceBean) { + private String generateIdentifierAsRandomString(Dataset dataset, IdServiceBean idServiceBean, String shoulder) { String identifier = null; do { - identifier = RandomStringUtils.randomAlphanumeric(6).toUpperCase(); + identifier = shoulder + RandomStringUtils.randomAlphanumeric(6).toUpperCase(); } while (!isIdentifierUniqueInDatabase(identifier, dataset, idServiceBean)); return identifier; } - private String generateIdentifierAsSequentialNumber(Dataset dataset, IdServiceBean idServiceBean) { + private String generateIdentifierAsSequentialNumber(Dataset dataset, IdServiceBean idServiceBean, String shoulder) { String identifier; do { @@ -244,7 +234,7 @@ private String generateIdentifierAsSequentialNumber(Dataset dataset, IdServiceBe if (identifierNumeric == null) { return null; } - identifier = identifierNumeric.toString(); + identifier = shoulder + identifierNumeric.toString(); } while (!isIdentifierUniqueInDatabase(identifier, dataset, idServiceBean)); return identifier; @@ -252,7 +242,7 @@ private String generateIdentifierAsSequentialNumber(Dataset dataset, IdServiceBe /** * Check that a identifier entered by the user is unique (not currently used - * for any other study in this Dataverse Network) alos check for duplicate + * for any other study in this Dataverse Network) also check for duplicate * in EZID if needed * @param userIdentifier * @param dataset @@ -327,7 +317,7 @@ public String createCitationRIS(DatasetVersion version, FileMetadata fileMetadat for (DatasetAuthor author : authorList) { retString += "AU - " + author.getName().getDisplayValue() + "\r\n"; } - retString += "DO - " + version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + version.getDataset().getDoiSeparator() + version.getDataset().getIdentifier() + "\r\n"; + retString += "DO - " + version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + "/" + version.getDataset().getIdentifier() + "\r\n"; retString += "PY - " + version.getVersionYear() + "\r\n"; retString += "UR - " + version.getDataset().getPersistentURL() + "\r\n"; retString += "PB - " + publisher + "\r\n"; @@ -479,7 +469,7 @@ private void createEndNoteXML(XMLStreamWriter xmlw, DatasetVersion version, File } xmlw.writeStartElement("electronic-resource-num"); - String electResourceNum = version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + version.getDataset().getDoiSeparator() + version.getDataset().getIdentifier(); + String electResourceNum = version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + "/" + version.getDataset().getIdentifier(); xmlw.writeCharacters(electResourceNum); xmlw.writeEndElement(); //10.3886/ICPSR03259.v1 @@ -960,9 +950,6 @@ public void obtainPersistentIdentifiersForDatafiles(Dataset dataset) { if (datafile.getAuthority() == null) { datafile.setAuthority(settingsService.getValueForKey(SettingsServiceBean.Key.Authority, "")); } - if (datafile.getDoiSeparator() == null) { - datafile.setDoiSeparator(settingsService.getValueForKey(SettingsServiceBean.Key.DoiSeparator, "")); - } logger.info("identifier: " + datafile.getIdentifier()); diff --git a/src/main/java/edu/harvard/iq/dataverse/DvObject.java b/src/main/java/edu/harvard/iq/dataverse/DvObject.java index 6b47f2052f1..ef7ebee2df6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DvObject.java +++ b/src/main/java/edu/harvard/iq/dataverse/DvObject.java @@ -20,7 +20,9 @@ @NamedQuery(name = "DvObject.findById", query = "SELECT o FROM DvObject o WHERE o.id=:id"), @NamedQuery(name = "DvObject.ownedObjectsById", - query="SELECT COUNT(obj) FROM DvObject obj WHERE obj.owner.id=:id") + query="SELECT COUNT(obj) FROM DvObject obj WHERE obj.owner.id=:id"), + @NamedQuery(name = "DvObject.findByGlobalId", + query = "SELECT o FROM DvObject o WHERE o.identifier=:identifier and o.authority=:authority and o.protocol=:protocol and o.dtype=:dtype") }) @Entity // Inheritance strategy "JOINED" will create 4 db tables - @@ -32,7 +34,8 @@ @Table(indexes = {@Index(columnList="dtype") , @Index(columnList="owner_id") , @Index(columnList="creator_id") - , @Index(columnList="releaseuser_id")}) + , @Index(columnList="releaseuser_id")}, + uniqueConstraints = @UniqueConstraint(columnNames = {"authority,protocol,identifier"})) public abstract class DvObject extends DataverseEntity implements java.io.Serializable { public static final String DATAVERSE_DTYPE_STRING = "Dataverse"; @@ -112,13 +115,14 @@ public String visit(DataFile df) { @Column private String storageIdentifier; + @Column(insertable = false, updatable = false) private String dtype; + /* * Add DOI related fields */ private String protocol; private String authority; - private String doiSeparator; @Temporal(value = TemporalType.TIMESTAMP) private Date globalIdCreateTime; @@ -257,14 +261,6 @@ public void setAuthority(String authority) { this.authority = authority; } - public String getDoiSeparator() { - return doiSeparator; - } - - public void setDoiSeparator(String doiSeparator) { - this.doiSeparator = doiSeparator; - } - public Date getGlobalIdCreateTime() { return globalIdCreateTime; } diff --git a/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java index 7e73066d476..6dcd854c607 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DvObjectServiceBean.java @@ -59,6 +59,35 @@ public List findAll() { return em.createNamedQuery("DvObject.findAll", DvObject.class).getResultList(); } + public DvObject findByGlobalId(String globalIdString, String typeString) { + + try { + GlobalId gid = new GlobalId(globalIdString); + + DvObject foundDvObject = null; + try { + Query query; + query = em.createNamedQuery("DvObject.findByGlobalId"); + query.setParameter("identifier", gid.getIdentifier()); + query.setParameter("protocol", gid.getProtocol()); + query.setParameter("authority", gid.getAuthority()); + query.setParameter("dtype", typeString); + foundDvObject = (DvObject) query.getSingleResult(); + } catch (javax.persistence.NoResultException e) { + // (set to .info, this can fill the log file with thousands of + // these messages during a large harvest run) + logger.fine("no dvObject found: " + globalIdString); + // DO nothing, just return null. + return null; + } + return foundDvObject; + + } catch (IllegalArgumentException iae) { + logger.info("Invalid identifier: " + globalIdString); + return null; + } + } + public DvObject updateContentIndexTime(DvObject dvObject) { /** * @todo to avoid a possible OptimisticLockException, should we merge diff --git a/src/main/java/edu/harvard/iq/dataverse/GlobalId.java b/src/main/java/edu/harvard/iq/dataverse/GlobalId.java index 962ca02141b..3b18c4072fe 100644 --- a/src/main/java/edu/harvard/iq/dataverse/GlobalId.java +++ b/src/main/java/edu/harvard/iq/dataverse/GlobalId.java @@ -12,6 +12,7 @@ import java.util.logging.Logger; import java.net.URL; import javax.ejb.EJB; +import javax.persistence.Query; /** * @@ -25,6 +26,8 @@ public class GlobalId implements java.io.Serializable { public static final String HDL_RESOLVER_URL = "https://hdl.handle.net/"; public static final String DOI_RESOLVER_URL = "https://doi.org/"; + private static final Logger logger = Logger.getLogger(GlobalId.class.getName()); + @EJB SettingsServiceBean settingsService; @@ -96,7 +99,7 @@ public URL toURL() { url = new URL(HDL_RESOLVER_URL + authority + "/" + identifier); } } catch (MalformedURLException ex) { - Logger.getLogger(GlobalId.class.getName()).log(Level.SEVERE, null, ex); + logger.log(Level.SEVERE, null, ex); } return url; } @@ -107,8 +110,8 @@ public URL toURL() { * * Example 1: doi:10.5072/FK2/BYM3IW * protocol: doi - * authority: 10.5072/FK2 - * identifier: BYM3IW + * authority: 10.5072 + * identifier: FK2/BYM3IW * * Example 2: hdl:1902.1/111012 * protocol: hdl @@ -119,42 +122,41 @@ public URL toURL() { * */ - private boolean parsePersistentId(String identifierString){ + private boolean parsePersistentId(String identifierString) { - if (identifierString == null){ - return false; - } - - int index1 = identifierString.indexOf(':'); - int index2 = identifierString.lastIndexOf('/'); - if (index1==-1) { - return false; - } - - String protocol = identifierString.substring(0, index1); - - if (!"doi".equals(protocol) && !"hdl".equals(protocol)) { + if (identifierString == null) { return false; } - - - if (index2 == -1) { - return false; - } - - this.protocol = protocol; - this.authority = formatIdentifierString(identifierString.substring(index1+1, index2)); - this.identifier = formatIdentifierString(identifierString.substring(index2+1)); - - if (this.protocol.equals(DOI_PROTOCOL)) { - if (!this.checkDOIAuthority(this.authority)) { + int index1 = identifierString.indexOf(':'); + if (index1 > 0) { // ':' found with one or more characters before it + int index2 = identifierString.indexOf('/', index1 + 1); + if (index2 > 0 && (index2 + 1) < identifierString.length()) { // '/' found with one or more characters + // between ':' + protocol = identifierString.substring(0, index1); // and '/' and there are characters after '/' + if (!"doi".equals(protocol) && !"hdl".equals(protocol)) { + return false; + } + //Strip any whitespace, ; and ' from authority (should finding them cause a failure instead?) + authority = formatIdentifierString(identifierString.substring(index1 + 1, index2)); + if (protocol.equals(DOI_PROTOCOL)) { + if (!this.checkDOIAuthority(authority)) { + return false; + } + } + // Passed all checks + //Strip any whitespace, ; and ' from identifier (should finding them cause a failure instead?) + identifier = formatIdentifierString(identifierString.substring(index2 + 1)); + } else { + logger.info("Error parsing identifier: " + identifierString + + ": ':/' not found in string"); return false; } + } else { + logger.info("Error parsing identifier: " + identifierString + ": ':' not found in string"); + return false; } return true; - } - private String formatIdentifierString(String str){ diff --git a/src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java index f9beef5fdce..9f0f4d17bbd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/HandlenetServiceBean.java @@ -335,7 +335,7 @@ public HashMap getIdentifierMetadata(DvObject dvObject) { } @Override - public HashMap lookupMetadataFromIdentifier(String protocol, String authority, String separator, String identifier) { + public HashMap lookupMetadataFromIdentifier(String protocol, String authority, String identifier) { throw new NotImplementedException(); } diff --git a/src/main/java/edu/harvard/iq/dataverse/IdServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/IdServiceBean.java index 07d22ef5754..7994939c439 100644 --- a/src/main/java/edu/harvard/iq/dataverse/IdServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/IdServiceBean.java @@ -21,17 +21,16 @@ public interface IdServiceBean { HashMap getIdentifierMetadata(DvObject dvObject); - HashMap lookupMetadataFromIdentifier(String protocol, String authority, String separator, String identifier); + HashMap lookupMetadataFromIdentifier(String protocol, String authority, String identifier); /** * Concatenate the parts that make up a Global Identifier. * @param protocol the identifier system, e.g. "doi" * @param authority the namespace that the authority manages in the identifier system - * @param separator the string that separates authority from local identifier part * @param identifier the local identifier part * @return the Global Identifier, e.g. "doi:10.12345/67890" */ - String getIdentifierForLookup(String protocol, String authority, String separator, String identifier); + String getIdentifierForLookup(String protocol, String authority, String identifier); String modifyIdentifierTargetURL(DvObject dvObject) throws Exception; diff --git a/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java b/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java index 43d296edfee..6c1d2e0ca85 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/datadeposit/CollectionDepositManagerImpl.java @@ -97,12 +97,10 @@ public DepositReceipt createNew(String collectionUri, Deposit deposit, AuthCrede String nonNullDefaultIfKeyNotFound = ""; String protocol = settingsService.getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); String authority = settingsService.getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - String separator = settingsService.getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound); + dataset.setProtocol(protocol); dataset.setAuthority(authority); - dataset.setDoiSeparator(separator); //Wait until the create command before actually getting an identifier - //dataset.setIdentifier(datasetService.generateDatasetIdentifier(protocol, authority, separator)); logger.log(Level.FINE, "DS Deposit identifier: {0}", dataset.getIdentifier()); CreateDatasetCommand createDatasetCommand = new CreateDatasetCommand(dataset, dvReq, false); diff --git a/src/main/java/edu/harvard/iq/dataverse/api/dto/DatasetDTO.java b/src/main/java/edu/harvard/iq/dataverse/api/dto/DatasetDTO.java index e03135466bb..87564c96637 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/dto/DatasetDTO.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/dto/DatasetDTO.java @@ -13,7 +13,6 @@ public class DatasetDTO implements java.io.Serializable { private String protocol; private String authority; private String globalIdCreateTime; - private String doiSeparator; private String publisher; private String publicationDate; private DatasetVersionDTO datasetVersion; @@ -78,14 +77,6 @@ public void setDataFiles(List dataFiles) { this.dataFiles = dataFiles; } - public String getDoiSeparator() { - return doiSeparator; - } - - public void setDoiSeparator(String doiSeparator) { - this.doiSeparator = doiSeparator; - } - public String getPublisher() { return publisher; } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportDDIServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportDDIServiceBean.java index 54ad825cb85..df81b5dc76c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportDDIServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportDDIServiceBean.java @@ -1580,14 +1580,13 @@ private void parseStudyIdHandle(String _id, DatasetDTO datasetDTO) { } else { datasetDTO.setAuthority(_id.substring(index1+1, index2)); } - datasetDTO.setDoiSeparator("/"); datasetDTO.setProtocol("hdl"); datasetDTO.setIdentifier(_id.substring(index2+1)); } private void parseStudyIdDOI(String _id, DatasetDTO datasetDTO) throws ImportException{ int index1 = _id.indexOf(':'); - int index2 = _id.lastIndexOf('/'); + int index2 = _id.indexOf('/'); if (index1==-1) { throw new EJBException("Error parsing (DOI) IdNo: "+_id+". ':' not found in string"); } @@ -1599,7 +1598,6 @@ private void parseStudyIdDOI(String _id, DatasetDTO datasetDTO) throws ImportExc datasetDTO.setAuthority(_id.substring(index1+1, index2)); } datasetDTO.setProtocol("doi"); - datasetDTO.setDoiSeparator("/"); datasetDTO.setIdentifier(_id.substring(index2+1)); } @@ -1608,11 +1606,11 @@ private void parseStudyIdDoiICPSRdara(String _id, DatasetDTO datasetDTO) throws /* dara/ICPSR DOIs are formatted without the hdl: prefix; for example - 10.3886/ICPSR06635.v1 - so we assume that everything before the last "/" is the authority, + so we assume that everything before the "/" is the authority, and everything past it - the identifier: */ - int index = _id.lastIndexOf('/'); + int index = _id.indexOf('/'); if (index == -1) { throw new ImportException("Error parsing ICPSR/dara DOI IdNo: "+_id+". '/' not found in string"); @@ -1624,7 +1622,6 @@ private void parseStudyIdDoiICPSRdara(String _id, DatasetDTO datasetDTO) throws datasetDTO.setAuthority(_id.substring(0, index)); datasetDTO.setProtocol("doi"); - datasetDTO.setDoiSeparator("/"); datasetDTO.setIdentifier(_id.substring(index+1)); } diff --git a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java index 442043ed397..b5554816c0a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/imports/ImportGenericServiceBean.java @@ -393,7 +393,7 @@ private String getOtherIdFromDTO(DatasetVersionDTO datasetVersionDTO) { private String reassignIdentifierAsGlobalId(String identifierString, DatasetDTO datasetDTO) { int index1 = identifierString.indexOf(':'); - int index2 = identifierString.lastIndexOf('/'); + int index2 = identifierString.indexOf('/'); if (index1==-1) { logger.warning("Error parsing identifier: " + identifierString + ". ':' not found in string"); return null; @@ -420,14 +420,14 @@ private String reassignIdentifierAsGlobalId(String identifierString, DatasetDTO logger.warning("HTTP Url in supplied as the identifier is neither a Handle nor DOI resolver: "+identifierString); return null; } - // index2 was already found as the *last* index of '/' - so it's still good. + // index2 was already found as the index of '/' - so it's still good. } else { logger.warning("Unknown identifier format: "+identifierString); return null; } if (index2 == -1) { - logger.warning("Error parsing identifier: " + identifierString + ". Second separator not found in string"); + logger.warning("Error parsing identifier: " + identifierString + ". Second '/' not found in string"); return null; } @@ -435,7 +435,6 @@ private String reassignIdentifierAsGlobalId(String identifierString, DatasetDTO String identifier = identifierString.substring(index2 + 1); datasetDTO.setProtocol(protocol); - datasetDTO.setDoiSeparator("/"); datasetDTO.setAuthority(authority); datasetDTO.setIdentifier(identifier); diff --git a/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordProcessor.java b/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordProcessor.java index b0f9d84640e..af7caf32a7c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordProcessor.java +++ b/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordProcessor.java @@ -69,7 +69,7 @@ public Object processItem(Object object) throws Exception { DatasetVersion version = dataset.getLatestVersion(); String path = object.toString(); - String gid = dataset.getAuthority() + dataset.getDoiSeparator() + dataset.getIdentifier(); + String gid = dataset.getAuthority() + "/" + dataset.getIdentifier(); String relativePath = path.substring(path.indexOf(gid) + gid.length() + 1); // skip if it already exists diff --git a/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java b/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java index 56e4cbcc976..abcc95c6da4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java +++ b/src/main/java/edu/harvard/iq/dataverse/batch/jobs/importer/filesystem/FileRecordWriter.java @@ -243,7 +243,7 @@ private DataFile createPackageDataFile(List files) { totalSize = 0L; } - String gid = dataset.getAuthority() + dataset.getDoiSeparator() + dataset.getIdentifier(); + String gid = dataset.getAuthority() + "/" + dataset.getIdentifier(); packageFile.setChecksumType(DataFile.ChecksumType.SHA1); // initial default @@ -373,16 +373,12 @@ private DataFile createPackageDataFile(List files) { String nonNullDefaultIfKeyNotFound = ""; String protocol = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); String authority = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - String doiSeparator = commandEngine.getContext().settings().getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound); if (packageFile.getProtocol() == null) { packageFile.setProtocol(protocol); } if (packageFile.getAuthority() == null) { packageFile.setAuthority(authority); } - if (packageFile.getDoiSeparator() == null) { - packageFile.setDoiSeparator(doiSeparator); - } if (!packageFile.isIdentifierRegistered()) { String doiRetString = ""; @@ -415,7 +411,7 @@ private DataFile createDataFile(File file) { DatasetVersion version = dataset.getLatestVersion(); String path = file.getAbsolutePath(); - String gid = dataset.getAuthority() + dataset.getDoiSeparator() + dataset.getIdentifier(); + String gid = dataset.getAuthority() + "/" + dataset.getIdentifier(); String relativePath = path.substring(path.indexOf(gid) + gid.length() + 1); DataFile datafile = new DataFile("application/octet-stream"); // we don't determine mime type diff --git a/src/main/java/edu/harvard/iq/dataverse/dataaccess/FileAccessIO.java b/src/main/java/edu/harvard/iq/dataverse/dataaccess/FileAccessIO.java index 7848118d360..93d67be3d63 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dataaccess/FileAccessIO.java +++ b/src/main/java/edu/harvard/iq/dataverse/dataaccess/FileAccessIO.java @@ -155,7 +155,7 @@ public void open (DataAccessOption... options) throws IOException { if (dataset.getFileSystemDirectory() != null && !Files.exists(dataset.getFileSystemDirectory())) { Files.createDirectories(dataset.getFileSystemDirectory()); } - dataset.setStorageIdentifier("file://"+dataset.getAuthority()+dataset.getDoiSeparator()+dataset.getIdentifier()); + dataset.setStorageIdentifier("file://"+dataset.getAuthority()+"/"+dataset.getIdentifier()); } } else if (dvObject instanceof Dataverse) { diff --git a/src/main/java/edu/harvard/iq/dataverse/dataaccess/SwiftAccessIO.java b/src/main/java/edu/harvard/iq/dataverse/dataaccess/SwiftAccessIO.java index 8621e83714c..a8a69e63cfe 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dataaccess/SwiftAccessIO.java +++ b/src/main/java/edu/harvard/iq/dataverse/dataaccess/SwiftAccessIO.java @@ -520,7 +520,7 @@ private StoredObject initializeSwiftFileObject(boolean writeAccess, String auxIt //swiftFolderPath = dataFile.getOwner().getDisplayName(); String swiftFolderPathSeparator = "-"; - String authorityNoSlashes = owner.getAuthority().replace(owner.getDoiSeparator(), swiftFolderPathSeparator); + String authorityNoSlashes = owner.getAuthority().replace("/", swiftFolderPathSeparator); swiftFolderPath = owner.getProtocol() + swiftFolderPathSeparator + authorityNoSlashes.replace(".", swiftFolderPathSeparator) + swiftFolderPathSeparator + owner.getIdentifier(); @@ -570,7 +570,7 @@ private StoredObject initializeSwiftFileObject(boolean writeAccess, String auxIt Properties p = getSwiftProperties(); swiftEndPoint = p.getProperty("swift.default.endpoint"); String swiftFolderPathSeparator = "-"; - String authorityNoSlashes = dataset.getAuthority().replace(dataset.getDoiSeparator(), swiftFolderPathSeparator); + String authorityNoSlashes = dataset.getAuthority().replace("/", swiftFolderPathSeparator); swiftFolderPath = dataset.getProtocol() + swiftFolderPathSeparator + authorityNoSlashes.replace(".", swiftFolderPathSeparator) + swiftFolderPathSeparator + dataset.getIdentifier(); @@ -830,7 +830,7 @@ public String getSwiftContainerName() { swiftFolderPathSeparator = "_"; } if (dvObject instanceof DataFile) { - String authorityNoSlashes = this.getDataFile().getOwner().getAuthority().replace(this.getDataFile().getOwner().getDoiSeparator(), swiftFolderPathSeparator); + String authorityNoSlashes = this.getDataFile().getOwner().getAuthority().replace("/", swiftFolderPathSeparator); return this.getDataFile().getOwner().getProtocol() + swiftFolderPathSeparator + authorityNoSlashes.replace(".", swiftFolderPathSeparator) + swiftFolderPathSeparator + this.getDataFile().getOwner().getIdentifier(); diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetCommand.java index 340a39a994f..f657e47eaa3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetCommand.java @@ -144,9 +144,9 @@ public Dataset execute(CommandContext ctxt) throws CommandException { dataFile.setCreateDate(theDataset.getCreateDate()); } String nonNullDefaultIfKeyNotFound = ""; + String protocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); String authority = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - String doiSeparator = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound); String doiProvider = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DoiProvider, nonNullDefaultIfKeyNotFound); if (theDataset.getProtocol() == null) { theDataset.setProtocol(protocol); @@ -154,9 +154,6 @@ public Dataset execute(CommandContext ctxt) throws CommandException { if (theDataset.getAuthority() == null) { theDataset.setAuthority(authority); } - if (theDataset.getDoiSeparator() == null) { - theDataset.setDoiSeparator(doiSeparator); - } if (theDataset.getStorageIdentifier() == null) { try { DataAccess.createNewStorageIO(theDataset, "placeholder"); @@ -164,7 +161,7 @@ public Dataset execute(CommandContext ctxt) throws CommandException { // if setting the storage identifier through createNewStorageIO fails, dataset creation // does not have to fail. we just set the storage id to a default -SF String storageDriver = (System.getProperty("dataverse.files.storage-driver-id") != null) ? System.getProperty("dataverse.files.storage-driver-id") : "file"; - theDataset.setStorageIdentifier(storageDriver + "://" + theDataset.getAuthority() + theDataset.getDoiSeparator() + theDataset.getIdentifier()); + theDataset.setStorageIdentifier(storageDriver + "://" + theDataset.getAuthority() + "/" + theDataset.getIdentifier()); logger.info("Failed to create StorageIO. StorageIdentifier set to default. Not fatal." + "(" + ioex.getMessage() + ")"); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java index 239f1f3bd62..3d60844dfba 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/RegisterDvObjectCommand.java @@ -37,7 +37,6 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { String nonNullDefaultIfKeyNotFound = ""; String protocol = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Protocol, nonNullDefaultIfKeyNotFound); String authority = ctxt.settings().getValueForKey(SettingsServiceBean.Key.Authority, nonNullDefaultIfKeyNotFound); - String doiSeparator = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound); IdServiceBean idServiceBean = IdServiceBean.getBean(target.getProtocol(), ctxt); try { //Test to see if identifier already present @@ -55,10 +54,6 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { if (target.getAuthority() == null) { target.setAuthority(authority); } - if (target.getDoiSeparator() == null) { - target.setDoiSeparator(doiSeparator); - } - } if (idServiceBean.alreadyExists(target)) { @@ -88,9 +83,6 @@ protected void executeImpl(CommandContext ctxt) throws CommandException { if (df.getAuthority() == null) { df.setAuthority(authority); } - if (df.getDoiSeparator() == null) { - df.setDoiSeparator(doiSeparator); - } } doiRetString = idServiceBean.createIdentifier(df); if (doiRetString != null && doiRetString.contains(df.getIdentifier())) { diff --git a/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java index 5b3b901a0b1..489b75bde4a 100644 --- a/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/settings/SettingsServiceBean.java @@ -185,7 +185,8 @@ public enum Key { Authority, /** DoiProvider for global id */ DoiProvider, - DoiSeparator, + /** Shoulder for global id - used to create a common prefix on identifiers */ + Shoulder, /* Removed for now - tried to add here but DOI Service Bean didn't like it at start-up DoiUsername, DoiPassword, diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java index 5da814c5b36..5f0c3af09d3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonParser.java @@ -255,7 +255,6 @@ public Dataset parseDataset(JsonObject obj) throws JsonParseException { dataset.setAuthority(obj.getString("authority", null) == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Authority) : obj.getString("authority")); dataset.setProtocol(obj.getString("protocol", null) == null ? settingsService.getValueForKey(SettingsServiceBean.Key.Protocol) : obj.getString("protocol")); - dataset.setDoiSeparator(obj.getString("doiSeparator", null) == null ? settingsService.getValueForKey(SettingsServiceBean.Key.DoiSeparator) : obj.getString("doiSeparator")); dataset.setIdentifier(obj.getString("identifier",null)); DatasetVersion dsv = new DatasetVersion(); diff --git a/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java b/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java index 9bd987dd5ab..71ca9c181c4 100644 --- a/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/GlobalIdTest.java @@ -50,8 +50,8 @@ public void testValidDOI() { GlobalId instance = new GlobalId("doi:10.5072/FK2/BYM3IW"); assertEquals("doi", instance.getProtocol()); - assertEquals("10.5072/FK2", instance.getAuthority()); - assertEquals("BYM3IW", instance.getIdentifier()); + assertEquals("10.5072", instance.getAuthority()); + assertEquals("FK2/BYM3IW", instance.getIdentifier()); // TODO review the generated test code and remove the default call to fail. } @@ -72,14 +72,14 @@ public void testContructFromDataset(){ Dataset testDS = new Dataset(); testDS.setProtocol("doi"); - testDS.setAuthority("10.5072/FK2"); - testDS.setIdentifier("BYM3IW"); + testDS.setAuthority("10.5072"); + testDS.setIdentifier("FK2/BYM3IW"); GlobalId instance = new GlobalId(testDS); assertEquals("doi", instance.getProtocol()); - assertEquals("10.5072/FK2", instance.getAuthority()); - assertEquals("BYM3IW", instance.getIdentifier()); + assertEquals("10.5072", instance.getAuthority()); + assertEquals("FK2/BYM3IW", instance.getIdentifier()); } diff --git a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java index 156bf6ee015..ff02a3eefa8 100644 --- a/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/util/json/JsonParserTest.java @@ -421,8 +421,7 @@ public void testParseEmptyDataset() throws JsonParseException { dsJson = Json.createReader(reader).readObject(); System.out.println(dsJson != null); Dataset actual = sut.parseDataset(dsJson); - assertEquals("10.5072/FK2", actual.getAuthority()); - assertEquals("/", actual.getDoiSeparator()); + assertEquals("10.5072", actual.getAuthority()); assertEquals("doi", actual.getProtocol()); } catch (IOException ioe) { throw new JsonParseException("Couldn't read test file", ioe); @@ -430,6 +429,7 @@ public void testParseEmptyDataset() throws JsonParseException { } /** + * * Expect an exception when the dataset version JSON contains fields * that the {@link DatasetFieldService} doesn't know about. * @throws JsonParseException as expected @@ -625,11 +625,9 @@ private static class MockSettingsSvc extends SettingsServiceBean { public String getValueForKey( Key key /*, String defaultValue */) { switch (key) { case Authority: - return "10.5072/FK2"; + return "10.5072"; case Protocol: return "doi"; - case DoiSeparator: - return "/"; default: break; }