package edu.harvard.iq.dataverse.api.datadeposit;
import edu.harvard.iq.dataverse.ControlledVocabularyValue;
import edu.harvard.iq.dataverse.DatasetField;
import edu.harvard.iq.dataverse.DatasetFieldConstant;
import edu.harvard.iq.dataverse.DatasetFieldServiceBean;
import edu.harvard.iq.dataverse.DatasetFieldType;
import edu.harvard.iq.dataverse.DatasetVersion;
import edu.harvard.iq.dataverse.TermsOfUseAndAccess;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.authorization.users.User;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Named;
import org.apache.commons.lang.StringUtils;
import org.swordapp.server.SwordEntry;
import org.swordapp.server.SwordError;
@Stateless
@Named
public class SwordServiceBean {
private static final Logger logger = Logger.getLogger(SwordServiceBean.class.getCanonicalName());
@EJB
DatasetFieldServiceBean datasetFieldService;
/**
* Mutate the dataset version, adding a datasetContact (email address) from
* the dataverse that will own the dataset.
*/
public void addDatasetContact(DatasetVersion newDatasetVersion, User user) {
DatasetFieldType emailDatasetFieldType = datasetFieldService.findByNameOpt(DatasetFieldConstant.datasetContact);
DatasetField emailDatasetField = DatasetField.createNewEmptyDatasetField(emailDatasetFieldType, newDatasetVersion);
for (DatasetField childField : emailDatasetField.getDatasetFieldCompoundValues().get(0).getChildDatasetFields()) {
if (DatasetFieldConstant.datasetContactEmail.equals(childField.getDatasetFieldType().getName())) {
// set the value to the in user's email
childField.getSingleValue().setValue(user.getDisplayInfo().getEmailAddress());
}
}
newDatasetVersion.getDatasetFields().add(emailDatasetField);
}
/**
* Mutate the dataset version, adding a depositor for the dataset.
*/
public void addDatasetDepositor(DatasetVersion newDatasetVersion, User user) {
if (!user.isAuthenticated()) {
logger.info("returning early since user is not authenticated");
return;
}
AuthenticatedUser au = (AuthenticatedUser) user;
DatasetFieldType depositorDatasetFieldType = datasetFieldService.findByNameOpt(DatasetFieldConstant.depositor);
DatasetField depositorDatasetField = DatasetField.createNewEmptyDatasetField(depositorDatasetFieldType, newDatasetVersion);
depositorDatasetField.setSingleValue(au.getLastName() + ", " + au.getFirstName());
newDatasetVersion.getDatasetFields().add(depositorDatasetField);
}
/**
* If no subject exists, mutate the dataset version, adding "N/A" for the
* subject. Otherwise, leave the dataset alone.
*/
public void addDatasetSubjectIfMissing(DatasetVersion datasetVersion) {
DatasetFieldType subjectDatasetFieldType = datasetFieldService.findByNameOpt(DatasetFieldConstant.subject);
boolean subjectFieldExists = false;
List<DatasetField> datasetFields = datasetVersion.getDatasetFields();
for (DatasetField datasetField : datasetFields) {
logger.fine("datasetField: " + datasetField.getDisplayValue() + " ... " + datasetField.getDatasetFieldType().getName());
if (datasetField.getDatasetFieldType().getName().equals(subjectDatasetFieldType.getName())) {
subjectFieldExists = true;
logger.fine("subject field exists already");
break;
}
}
if (subjectFieldExists) {
// return early. nothing to do. dataset already has a subject
logger.fine("returning early because subject exists already");
return;
}
// if we made it here, we must not have a subject, so let's add one
DatasetField subjectDatasetField = DatasetField.createNewEmptyDatasetField(subjectDatasetFieldType, datasetVersion);
/**
* @todo Once dataverse has subject
* (https://github.com/IQSS/dataverse/issues/769), we should get subject
* from there for now, we'll use the global NA value. However, there is
* currently oddness in that if you go to edit the title of a dataset
* via the GUI you can not save the dataset without selecting a Subject:
* https://github.com/IQSS/dataverse/issues/1296#issuecomment-70146314
*/
ControlledVocabularyValue cvv = datasetFieldService.findNAControlledVocabularyValue();
subjectDatasetField.setSingleControlledVocabularyValue(cvv);
datasetVersion.getDatasetFields().add(subjectDatasetField);
}
/**
* The rules (from https://github.com/IQSS/dataverse/issues/805 ) are below.
*
* If you don't provide `<dcterms:license>` the license should be set to
* "CC0" on dataset creation.
*
* If you don't provide `<dcterms:license>` the license on dataset
* modification, the license should not change.
*
* To provide `<dcterms:rights>` you much either omit `<dcterms:license>`
* (for backwards compatibility since `<dcterms:license>` was not a required
* field for SWORD in DVN 3.6) or set `<dcterms:license>` to "NONE".
*
* It is invalid to provide "CC0" under `<dcterms:license>` in combination
* with any value under `<dcterms:rights>`.
*
* It is invalid to attempt to change the license to "CC0" if Terms of Use
* (`<dcterms:rights>`) is already on file.
*
* Both `<dcterms:rights>` and `<dcterms:license>` can only be specified
* once. Multiples are not allowed.
*
* Blank values are not allowed for `<dcterms:license>` (since it's new) but
* for backwards compatibility, blank values are allowed for
* `<dcterms:rights>` per
* https://github.com/IQSS/dataverse/issues/805#issuecomment-71670396
*
* @todo What about the "native" API? Are similar rules enforced? See also
* https://github.com/IQSS/dataverse/issues/1385
*/
public void setDatasetLicenseAndTermsOfUse(DatasetVersion datasetVersionToMutate, SwordEntry swordEntry) throws SwordError {
Map<String, List<String>> dcterms = swordEntry.getDublinCore();
List<String> listOfLicensesProvided = dcterms.get("license");
TermsOfUseAndAccess terms = new TermsOfUseAndAccess();
datasetVersionToMutate.setTermsOfUseAndAccess(terms);
if (listOfLicensesProvided == null) {
TermsOfUseAndAccess.License existingLicense = datasetVersionToMutate.getTermsOfUseAndAccess().getLicense();
if (existingLicense != null) {
// leave the license alone but set terms of use
setTermsOfUse(datasetVersionToMutate, dcterms, existingLicense);
} else {
TermsOfUseAndAccess.License unspecifiedLicense = TermsOfUseAndAccess.defaultLicense;
List<String> listOfRights = dcterms.get("rights");
if (listOfRights != null) {
int numRightsProvided = listOfRights.size();
if (numRightsProvided != 1) {
throw new SwordError("Only one Terms of Use (dcterms:rights) can be provided per dataset, not " + numRightsProvided);
} else {
// Set to NONE for backwards combatibility. We didn't require a license for SWORD in DVN 3.x.
unspecifiedLicense = TermsOfUseAndAccess.License.NONE;
}
}
terms.setLicense(existingLicense);
terms.setLicense(unspecifiedLicense);
setTermsOfUse(datasetVersionToMutate, dcterms, unspecifiedLicense);
}
return;
}
int numLicensesProvided = listOfLicensesProvided.size();
if (numLicensesProvided != 1) {
throw new SwordError("Only one license can be provided per dataset, not " + numLicensesProvided + ".");
}
String licenseProvided = listOfLicensesProvided.get(0);
if (StringUtils.isBlank(licenseProvided)) {
throw new SwordError("License provided was blank.");
}
TermsOfUseAndAccess.License licenseToSet;
try {
licenseToSet = TermsOfUseAndAccess.License.valueOf(licenseProvided);
} catch (IllegalArgumentException ex) {
throw new SwordError("License provided was \"" + licenseProvided + "\" but one " + Arrays.toString(DatasetVersion.License.values()) + " was expected.");
}
terms.setLicense(licenseToSet);
setTermsOfUse(datasetVersionToMutate, dcterms, licenseToSet);
}
private void setTermsOfUse(DatasetVersion datasetVersionToMutate, Map<String, List<String>> dcterms, TermsOfUseAndAccess.License providedLicense) throws SwordError {
if (providedLicense.equals(TermsOfUseAndAccess.License.CC0)) {
String existingTermsOfUse = datasetVersionToMutate.getTermsOfUseAndAccess().getTermsOfUse();
if (existingTermsOfUse != null) {
throw new SwordError("Can not change license to \"" + DatasetVersion.License.CC0 + "\" due to existing Terms of Use (dcterms:rights): \"" + existingTermsOfUse + "\". You can specify a license of \"" + DatasetVersion.License.NONE + "\'.");
}
}
List<String> listOfRightsProvided = dcterms.get("rights");
if (listOfRightsProvided != null) {
int numRightsProvided = listOfRightsProvided.size();
if (providedLicense.equals(DatasetVersion.License.CC0)) {
if (numRightsProvided > 0) {
throw new SwordError("Terms of Use (dcterms:rights) can not be specified in combination with the license \"" + TermsOfUseAndAccess.License.CC0 + "\". A license of \"" + TermsOfUseAndAccess.License.NONE + "\" can be used instead.");
}
} else {
if (numRightsProvided != 1) {
throw new SwordError("Only one Terms of Use (dcterms:rights) can be provided per dataset, not " + numRightsProvided);
}
String termsOfUseProvided = listOfRightsProvided.get(0);
if (StringUtils.isBlank(termsOfUseProvided)) {
/**
* for backwards compatibility, let dcterms:rights be blank
* (don't throw an error) (but don't persist an empty
* string):
* https://github.com/IQSS/dataverse/issues/805#issuecomment-71670396
*/
// throw new SwordError("Terms of Use (dcterms:rights) provided was blank.");
} else {
datasetVersionToMutate.getTermsOfUseAndAccess().setTermsOfUse(termsOfUseProvided);
}
}
}
}
}