metadata_values = dsoService
.getMetadata(dso, MetadataSchemaEnum.DC.getName(), Item.ANY, Item.ANY, Item.ANY);
@@ -189,10 +191,11 @@ public Model convert(Context context, DSpaceObject dso)
@Override
public boolean supports(int type) {
- //TAMU Customization - Map more than just ITEMs
- return (type == Constants.ITEM || type == Constants.COLLECTION || type == Constants.COMMUNITY);
+ // TAMU Customization - Map more than just ITEMs
// should be changed, if Communities and Collections have metadata as well.
// return (type == Constants.ITEM);
+ return (type == Constants.ITEM || type == Constants.COLLECTION || type == Constants.COMMUNITY);
+ // END TAMU Customization - Map more than just ITEMs
}
protected Model loadConfiguration() {
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/BitstreamRestController.java
deleted file mode 100644
index ef4c419c02c1..000000000000
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/BitstreamRestController.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * 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.app.rest;
-
-import static org.dspace.app.rest.utils.ContextUtil.obtainContext;
-import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
-import static org.springframework.web.bind.annotation.RequestMethod.PUT;
-
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.UUID;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.Response;
-
-import org.apache.catalina.connector.ClientAbortException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.Logger;
-import org.dspace.app.rest.converter.ConverterService;
-import org.dspace.app.rest.exception.DSpaceBadRequestException;
-import org.dspace.app.rest.model.BitstreamRest;
-import org.dspace.app.rest.model.hateoas.BitstreamResource;
-import org.dspace.app.rest.utils.ContextUtil;
-import org.dspace.app.rest.utils.HttpHeadersInitializer;
-import org.dspace.app.rest.utils.Utils;
-import org.dspace.authorize.AuthorizeException;
-import org.dspace.content.Bitstream;
-import org.dspace.content.BitstreamFormat;
-import org.dspace.content.service.BitstreamFormatService;
-import org.dspace.content.service.BitstreamService;
-import org.dspace.core.Context;
-import org.dspace.disseminate.service.CitationDocumentService;
-import org.dspace.eperson.EPerson;
-import org.dspace.services.ConfigurationService;
-import org.dspace.services.EventService;
-import org.dspace.usage.UsageEvent;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.rest.webmvc.ResourceNotFoundException;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.prepost.PostAuthorize;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * This is a specialized controller to provide access to the bitstream binary
- * content
- *
- * The mapping for requested endpoint try to resolve a valid UUID, for example
- *
- * {@code
- * https:///api/core/bitstreams/26453b4d-e513-44e8-8d5b-395f62972eff/content
- * }
- *
- *
- * @author Andrea Bollini (andrea.bollini at 4science.it)
- * @author Tom Desair (tom dot desair at atmire dot com)
- * @author Frederic Van Reet (frederic dot vanreet at atmire dot com)
- */
-@RestController
-@RequestMapping("/api/" + BitstreamRest.CATEGORY + "/" + BitstreamRest.PLURAL_NAME
- + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
-public class BitstreamRestController {
-
- private static final Logger log = org.apache.logging.log4j.LogManager
- .getLogger(BitstreamRestController.class);
-
- //Most file systems are configured to use block sizes of 4096 or 8192 and our buffer should be a multiple of that.
- private static final int BUFFER_SIZE = 4096 * 10;
-
- @Autowired
- private BitstreamService bitstreamService;
-
- @Autowired
- BitstreamFormatService bitstreamFormatService;
-
- @Autowired
- private EventService eventService;
-
- @Autowired
- private CitationDocumentService citationDocumentService;
-
- @Autowired
- private ConfigurationService configurationService;
-
- @Autowired
- ConverterService converter;
-
- @Autowired
- Utils utils;
-
- @PreAuthorize("hasPermission(#uuid, 'BITSTREAM', 'READ')")
- @RequestMapping( method = {RequestMethod.GET, RequestMethod.HEAD}, value = "content")
- public ResponseEntity retrieve(@PathVariable UUID uuid, HttpServletResponse response,
- HttpServletRequest request) throws IOException, SQLException, AuthorizeException {
-
-
- Context context = ContextUtil.obtainContext(request);
-
- Bitstream bit = bitstreamService.find(context, uuid);
- EPerson currentUser = context.getCurrentUser();
-
- if (bit == null) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- return null;
- }
-
- Long lastModified = bitstreamService.getLastModified(bit);
- BitstreamFormat format = bit.getFormat(context);
- String mimetype = format.getMIMEType();
- String name = getBitstreamName(bit, format);
-
- if (StringUtils.isBlank(request.getHeader("Range"))) {
- //We only log a download request when serving a request without Range header. This is because
- //a browser always sends a regular request first to check for Range support.
- eventService.fireEvent(
- new UsageEvent(
- UsageEvent.Action.VIEW,
- request,
- context,
- bit));
- }
-
- try {
- long filesize = bit.getSizeBytes();
- Boolean citationEnabledForBitstream = citationDocumentService.isCitationEnabledForBitstream(bit, context);
-
- HttpHeadersInitializer httpHeadersInitializer = new HttpHeadersInitializer()
- .withBufferSize(BUFFER_SIZE)
- .withFileName(name)
- .withChecksum(bit.getChecksum())
- .withMimetype(mimetype)
- .with(request)
- .with(response);
-
- if (lastModified != null) {
- httpHeadersInitializer.withLastModified(lastModified);
- }
-
- //Determine if we need to send the file as a download or if the browser can open it inline
- //The file will be downloaded if its size is larger than the configured threshold,
- //or if its mimetype/extension appears in the "webui.content_disposition_format" config
- long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold");
- if ((dispositionThreshold >= 0 && filesize > dispositionThreshold)
- || checkFormatForContentDisposition(format)) {
- httpHeadersInitializer.withDisposition(HttpHeadersInitializer.CONTENT_DISPOSITION_ATTACHMENT);
- }
-
- org.dspace.app.rest.utils.BitstreamResource bitstreamResource =
- new org.dspace.app.rest.utils.BitstreamResource(name, uuid,
- currentUser != null ? currentUser.getID() : null,
- context.getSpecialGroupUuids(), citationEnabledForBitstream);
-
- //We have all the data we need, close the connection to the database so that it doesn't stay open during
- //download/streaming
- context.complete();
-
- //Send the data
- if (httpHeadersInitializer.isValid()) {
- HttpHeaders httpHeaders = httpHeadersInitializer.initialiseHeaders();
-
- // TAMU Customization - only return headers for HEAD request
- if ("HEAD".equals(request.getMethod())) {
- log.debug("HEAD request - no response body");
- return ResponseEntity.ok().headers(httpHeaders).build();
- }
-
- return ResponseEntity.ok().headers(httpHeaders).body(bitstreamResource);
- }
-
- } catch (ClientAbortException ex) {
- log.debug("Client aborted the request before the download was completed. " +
- "Client is probably switching to a Range request.", ex);
- } catch (Exception e) {
- throw e;
- }
- return null;
- }
-
- private String getBitstreamName(Bitstream bit, BitstreamFormat format) {
- String name = bit.getName();
- if (name == null) {
- // give a default name to the file based on the UUID and the primary extension of the format
- name = bit.getID().toString();
- if (format != null && format.getExtensions() != null && format.getExtensions().size() > 0) {
- name += "." + format.getExtensions().get(0);
- }
- }
- return name;
- }
-
- private boolean isNotAnErrorResponse(HttpServletResponse response) {
- Response.Status.Family responseCode = Response.Status.Family.familyOf(response.getStatus());
- return responseCode.equals(Response.Status.Family.SUCCESSFUL)
- || responseCode.equals(Response.Status.Family.REDIRECTION);
- }
-
- private boolean checkFormatForContentDisposition(BitstreamFormat format) {
- // never automatically download undefined formats
- if (format == null) {
- return false;
- }
- List formats = List.of((configurationService.getArrayProperty("webui.content_disposition_format")));
- boolean download = formats.contains(format.getMIMEType());
- if (!download) {
- for (String ext : format.getExtensions()) {
- if (formats.contains(ext)) {
- download = true;
- break;
- }
- }
- }
- return download;
- }
-
- /**
- * This method will update the bitstream format of the bitstream that corresponds to the provided bitstream uuid.
- *
- * @param uuid The UUID of the bitstream for which to update the bitstream format
- * @param request The request object
- * @return The wrapped resource containing the bitstream which in turn contains the bitstream format
- * @throws SQLException If something goes wrong in the database
- */
- @RequestMapping(method = PUT, consumes = {"text/uri-list"}, value = "format")
- @PreAuthorize("hasPermission(#uuid, 'BITSTREAM','WRITE')")
- @PostAuthorize("returnObject != null")
- public BitstreamResource updateBitstreamFormat(@PathVariable UUID uuid,
- HttpServletRequest request) throws SQLException {
-
- Context context = obtainContext(request);
-
- List bitstreamFormats = utils.constructBitstreamFormatList(request, context);
-
- if (bitstreamFormats.size() > 1) {
- throw new DSpaceBadRequestException("Only one bitstream format is allowed");
- }
-
- BitstreamFormat bitstreamFormat = bitstreamFormats.stream().findFirst()
- .orElseThrow(() -> new DSpaceBadRequestException("No valid bitstream format was provided"));
-
- Bitstream bitstream = bitstreamService.find(context, uuid);
-
- if (bitstream == null) {
- throw new ResourceNotFoundException("Bitstream with id: " + uuid + " not found");
- }
-
- bitstream.setFormat(context, bitstreamFormat);
-
- context.commit();
-
- BitstreamRest bitstreamRest = converter.toRest(context.reloadEntity(bitstream), utils.obtainProjection());
- return converter.toResource(bitstreamRest);
- }
-}
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/model/CollectionRest.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/model/CollectionRest.java
index 71ea3936b63b..2c039b8d7d6e 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/model/CollectionRest.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/model/CollectionRest.java
@@ -10,48 +10,22 @@
import com.fasterxml.jackson.annotation.JsonProperty;
/**
- * TAMU Customization - Customized Collection REST Resource
+ * The Collection REST Resource
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
@LinksRest(links = {
- // TAMU Customization - proxy license step
- @LinkRest(
- name = CollectionRest.LICENSES,
- method = "getLicenses"
- ),
- @LinkRest(
- name = CollectionRest.LICENSE,
- method = "getLicense"
- ),
- @LinkRest(
- name = CollectionRest.LOGO,
- method = "getLogo"
- ),
- @LinkRest(
- name = CollectionRest.MAPPED_ITEMS,
- method = "getMappedItems"
- ),
- @LinkRest(
- name = CollectionRest.PARENT_COMMUNITY,
- method = "getParentCommunity"
- ),
- @LinkRest(
- name = CollectionRest.ADMIN_GROUP,
- method = "getAdminGroup"
- ),
- @LinkRest(
- name = CollectionRest.SUBMITTERS_GROUP,
- method = "getSubmittersGroup"
- ),
- @LinkRest(
- name = CollectionRest.ITEM_READ_GROUP,
- method = "getItemReadGroup"
- ),
- @LinkRest(
- name = CollectionRest.BITSTREAM_READ_GROUP,
- method = "getBitstreamReadGroup"
- ),
+ @LinkRest(name = CollectionRest.LICENSE, method = "getLicense"),
+ // TAMU Customization - proxy license step
+ @LinkRest(name = CollectionRest.LICENSES, method = "getLicenses"),
+ // END TAMU Customization - proxy license step
+ @LinkRest(name = CollectionRest.LOGO, method = "getLogo"),
+ @LinkRest(name = CollectionRest.MAPPED_ITEMS, method = "getMappedItems"),
+ @LinkRest(name = CollectionRest.PARENT_COMMUNITY, method = "getParentCommunity"),
+ @LinkRest(name = CollectionRest.ADMIN_GROUP, method = "getAdminGroup"),
+ @LinkRest(name = CollectionRest.SUBMITTERS_GROUP, method = "getSubmittersGroup"),
+ @LinkRest(name = CollectionRest.ITEM_READ_GROUP, method = "getItemReadGroup"),
+ @LinkRest(name = CollectionRest.BITSTREAM_READ_GROUP, method = "getBitstreamReadGroup"),
})
public class CollectionRest extends DSpaceObjectRest {
public static final String NAME = "collection";
@@ -62,6 +36,7 @@ public class CollectionRest extends DSpaceObjectRest {
public static final String LICENSE = "license";
// TAMU Customization - proxy license step
public static final String LICENSES = "licenses";
+ // END TAMU Customization - proxy license step
public static final String LOGO = "logo";
public static final String MAPPED_ITEMS = "mappedItems";
public static final String PARENT_COMMUNITY = "parentCommunity";
@@ -82,6 +57,11 @@ public String getType() {
return NAME;
}
+ @Override
+ public String getTypePlural() {
+ return PLURAL_NAME;
+ }
+
private int archivedItemsCount;
public int getArchivedItemsCount() {
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/model/LicenseRest.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/model/LicenseRest.java
index 8d988e03c813..8d245f69d5b9 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/model/LicenseRest.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/model/LicenseRest.java
@@ -7,67 +7,73 @@
*/
package org.dspace.app.rest.model;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-
/**
- * TAMU Customization - Customized License REST resource.
+ * The License text REST resource.
*
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
-public class LicenseRest extends RestAddressableModel {
-
+public class LicenseRest implements RestModel {
public static final String NAME = "license";
+ public static final String PLURAL_NAME = "licenses";
- private final String name;
+ private boolean custom = false;
+ private String text;
+ // TAMU Customization - proxy license step
+ private final String name;
private final String label;
+ // END TAMU Customization - proxy license step
- private final String text;
-
- private final boolean custom;
-
+ // TAMU Customization - proxy license step
private LicenseRest(String name, String label, String text, boolean custom) {
+ super();
this.name = name;
this.label = label;
this.text = text;
this.custom = custom;
}
+ // END TAMU Customization - proxy license step
- public String getName() {
- return name;
+ public boolean isCustom() {
+ return custom;
}
- public String getLabel() {
- return label;
+ public void setCustom(boolean custom) {
+ this.custom = custom;
}
public String getText() {
return text;
}
- public boolean isCustom() {
- return custom;
+ public void setText(String text) {
+ this.text = text;
}
- @Override
- public String getType() {
- return NAME;
+ // TAMU Customization - proxy license step
+ public String getName() {
+ return name;
}
+ public String getLabel() {
+ return label;
+ }
+ // END TAMU Customization - proxy license step
+
@Override
- @JsonIgnore
- public String getCategory() {
- return null;
+ public String getType() {
+ return NAME;
}
@Override
- @JsonIgnore
- public Class getController() {
- return null;
+ public String getTypePlural() {
+ return PLURAL_NAME;
}
+ // TAMU Customization - proxy license step
public static LicenseRest of(String name, String label, String text, boolean custom) {
return new LicenseRest(name, label, text, custom);
}
+ // END TAMU Customization - proxy license step
}
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicenseLinkRepository.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicenseLinkRepository.java
index c809e0e6a50c..db2a072582ed 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicenseLinkRepository.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicenseLinkRepository.java
@@ -9,9 +9,9 @@
import java.sql.SQLException;
import java.util.UUID;
-import javax.annotation.Nullable;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.annotation.Nullable;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.LicenseRest;
@@ -20,30 +20,35 @@
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.dspace.core.service.LicenseService;
-import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
+// TAMU Customization - proxy license step
+import org.dspace.services.ConfigurationService;
+// END TAMU Customization - proxy license step
+
/**
- * TAMU Customization - Customized License Link repository for "license" subresource of an individual collection.
+ * Link repository for "license" subresource of an individual collection.
*
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
-@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME + "." + CollectionRest.LICENSE)
+@Component(CollectionRest.CATEGORY + "." + CollectionRest.PLURAL_NAME + "." + CollectionRest.LICENSE)
public class CollectionLicenseLinkRepository extends AbstractDSpaceRestRepository
implements LinkRestRepository {
@Autowired
- private CollectionService collectionService;
+ CollectionService collectionService;
@Autowired
- private LicenseService licenseService;
+ LicenseService licenseService;
+ // TAMU Customization - proxy license step
@Autowired
- private ConfigurationService configurationService;
+ ConfigurationService configurationService;
+ // END TAMU Customization - proxy license step
@PreAuthorize("hasPermission(#collectionId, 'COLLECTION', 'READ')")
public LicenseRest getLicense(@Nullable HttpServletRequest request,
@@ -56,8 +61,7 @@ public LicenseRest getLicense(@Nullable HttpServletRequest request,
if (collection == null) {
throw new ResourceNotFoundException("No such collection: " + collectionId);
}
-
- // TAMU Customization - use customized LicenseRest DTO
+ // TAMU Customization - proxy license step - use customized LicenseRest DTO
String license = "default";
boolean custom = false;
@@ -74,18 +78,20 @@ public LicenseRest getLicense(@Nullable HttpServletRequest request,
}
return LicenseRest.of(license, label, text, custom);
- // LicenseRest licenseRest = new LicenseRest();
- // String text = collection.getLicenseCollection();
- // if (StringUtils.isNotBlank(text)) {
- // licenseRest.setCustom(true);
- // licenseRest.setText(text);
- // } else {
- // licenseRest.setText(licenseService.getDefaultSubmissionLicense());
- // }
- // return licenseRest;
+ /*
+ LicenseRest licenseRest = new LicenseRest();
+ String text = collection.getLicenseCollection();
+ if (StringUtils.isNotBlank(text)) {
+ licenseRest.setCustom(true);
+ licenseRest.setText(text);
+ } else {
+ licenseRest.setText(licenseService.getDefaultSubmissionLicense());
+ }
+ return licenseRest;
+ */
+ // TAMU Customization - proxy license step - use customized LicenseRest DTO
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
-
}
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicensesLinkRepository.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicensesLinkRepository.java
index 3ca30fc98455..206524155d48 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicensesLinkRepository.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/CollectionLicensesLinkRepository.java
@@ -7,14 +7,11 @@
*/
package org.dspace.app.rest.repository;
-import java.io.File;
import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
import java.util.UUID;
-import javax.annotation.Nullable;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.annotation.Nullable;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.LicenseRest;
@@ -23,39 +20,51 @@
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.dspace.core.service.LicenseService;
-import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
+// TAMU Customization - proxy license step
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dspace.services.ConfigurationService;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+// END TAMU Customization - proxy license step
+
/**
- * TAMU Customization - Customized License Link repository for "license" subresource of an individual collection.
+ * Link repository for "license" subresource of an individual collection.
*
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
-@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME + "." + CollectionRest.LICENSES)
+@Component(CollectionRest.CATEGORY + "." + CollectionRest.PLURAL_NAME + "." + CollectionRest.LICENSES)
+// TAMU Customization - proxy license step
+// public class CollectionLicenseLinkRepository extends AbstractDSpaceRestRepository
public class CollectionLicensesLinkRepository extends AbstractDSpaceRestRepository
+// END TAMU Customization - proxy license step
implements LinkRestRepository {
@Autowired
- private CollectionService collectionService;
+ CollectionService collectionService;
@Autowired
- private LicenseService licenseService;
+ LicenseService licenseService;
+ // TAMU Customization - proxy license step
@Autowired
- private ConfigurationService configurationService;
+ ConfigurationService configurationService;
+ // END TAMU Customization - proxy license step
- // TAMU Customization - get available licenses
+ // TAMU Customization - proxy license step - get available licenses slight refactor of getLicense
@PreAuthorize("hasPermission(#collectionId, 'COLLECTION', 'READ')")
public Page getLicenses(@Nullable HttpServletRequest request,
- UUID collectionId,
- @Nullable Pageable optionalPageable,
- Projection projection) {
+ UUID collectionId,
+ @Nullable Pageable optionalPageable,
+ Projection projection) {
try {
Context context = obtainContext();
Collection collection = collectionService.find(context, collectionId);
@@ -99,5 +108,5 @@ public Page getLicenses(@Nullable HttpServletRequest request,
throw new RuntimeException(e);
}
}
-
+ // END TAMU Customization - proxy license step - get available licenses slight refactor of getLicense
}
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java
index f03cc6e15539..e9472d73daab 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java
@@ -14,8 +14,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.Parameter;
@@ -73,7 +73,7 @@
* @author Andrea Bollini (andrea.bollini at 4science.it)
* @author Pasquale Cavallo (pasquale.cavallo at 4science.it)
*/
-@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME)
+@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.PLURAL_NAME)
public class WorkspaceItemRestRepository extends DSpaceRestRepository
implements ReloadableEntityObjectRepository {
@@ -251,7 +251,7 @@ public Iterable upload(Context context, HttpServletRequest re
}
SubmissionConfig submissionConfig =
- submissionConfigService.getSubmissionConfigByCollection(collection.getHandle());
+ submissionConfigService.getSubmissionConfigByCollection(collection);
List result = null;
List records = new ArrayList<>();
try {
@@ -300,6 +300,7 @@ public Iterable upload(Context context, HttpServletRequest re
if (UploadableStep.class.isAssignableFrom(stepClass)
&& !((UploadableStep) stepInstance).isExclusiveMatchingStepId()) {
// if (UploadableStep.class.isAssignableFrom(stepClass)) {
+ // END TAMU Customization - proxy license step - respect exclusivity of uploadable step
UploadableStep uploadableStep = (UploadableStep) stepInstance;
for (MultipartFile mpFile : uploadfiles) {
ErrorRest err = uploadableStep.upload(context,
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/SubmissionService.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/SubmissionService.java
index e05195da2390..5a401856f62e 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/SubmissionService.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/SubmissionService.java
@@ -8,20 +8,15 @@
package org.dspace.app.rest.submit;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
import java.util.UUID;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.Part;
-import org.apache.commons.io.IOUtils;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
-import org.atteo.evo.inflector.English;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.RESTAuthorizationException;
@@ -32,9 +27,11 @@
import org.dspace.app.rest.model.CheckSumRest;
import org.dspace.app.rest.model.ErrorRest;
import org.dspace.app.rest.model.MetadataValueRest;
+import org.dspace.app.rest.model.PotentialDuplicateRest;
import org.dspace.app.rest.model.WorkspaceItemRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.step.DataCCLicense;
+import org.dspace.app.rest.model.step.DataDuplicateDetection;
import org.dspace.app.rest.model.step.DataUpload;
import org.dspace.app.rest.model.step.UploadBitstreamRest;
import org.dspace.app.rest.projection.Projection;
@@ -53,11 +50,14 @@
import org.dspace.content.MetadataValue;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.service.CollectionService;
+import org.dspace.content.service.DuplicateDetectionService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.content.virtual.PotentialDuplicate;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.Utils;
+import org.dspace.discovery.SearchServiceException;
import org.dspace.license.service.CreativeCommonsService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.RequestService;
@@ -70,11 +70,22 @@
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.data.rest.webmvc.json.patch.PatchException;
import org.springframework.jdbc.datasource.init.UncategorizedScriptException;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
+// TAMU Customization - proxy license step
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+import java.util.Optional;
+
+import jakarta.servlet.http.Part;
+
+import org.apache.commons.io.IOUtils;
+// END TAMU Customization - proxy license step
+
/**
* Service to manipulate in-progress submissions.
*
@@ -87,6 +98,7 @@ public class SubmissionService {
// TAMU Customization - proxy license step
private static final String FORM_DATA_SECTION_ID = "sectionId";
+ // END TAMU Customization - proxy license step
@Autowired
protected ConfigurationService configurationService;
@@ -110,6 +122,8 @@ public class SubmissionService {
@Autowired
private org.dspace.app.rest.utils.Utils utils;
private SubmissionConfigService submissionConfigService;
+ @Autowired
+ private DuplicateDetectionService duplicateDetectionService;
public SubmissionService() throws SubmissionConfigReaderException {
submissionConfigService = SubmissionServiceFactory.getInstance().getSubmissionConfigService();
@@ -227,7 +241,7 @@ public UploadBitstreamRest buildUploadBitstream(ConfigurationService configurati
data.setCheckSum(checksum);
data.setSizeBytes(source.getSizeBytes());
data.setUrl(configurationService.getProperty("dspace.server.url") + "/api/" + BitstreamRest.CATEGORY + "/" +
- English.plural(BitstreamRest.NAME) + "/" + source.getID() + "/content");
+ BitstreamRest.PLURAL_NAME + "/" + source.getID() + "/content");
return data;
}
@@ -249,7 +263,7 @@ public XmlWorkflowItem createWorkflowItem(Context context, String requestUriList
if (StringUtils.isBlank(requestUriListString)) {
throw new UnprocessableEntityException("Malformed body..." + requestUriListString);
}
- String regex = "\\/api\\/" + WorkspaceItemRest.CATEGORY + "\\/" + English.plural(WorkspaceItemRest.NAME)
+ String regex = "\\/api\\/" + WorkspaceItemRest.CATEGORY + "\\/" + WorkspaceItemRest.PLURAL_NAME
+ "\\/";
String[] split = requestUriListString.split(regex, 2);
if (split.length != 2) {
@@ -322,6 +336,51 @@ public DataCCLicense getDataCCLicense(InProgressSubmission obj)
return result;
}
+ /**
+ * Prepare section data containing a list of potential duplicates, for use in submission steps.
+ * This method belongs in SubmissionService and not DuplicateDetectionService because it depends on
+ * the DataDuplicateDetection class which only appears in the REST project.
+ *
+ * @param context DSpace context
+ * @param obj The in-progress submission object
+ * @return A DataDuplicateDetection object which implements SectionData for direct use in
+ * a submission step (see DuplicateDetectionStep)
+ * @throws SearchServiceException if an error is encountered during Discovery search
+ */
+ public DataDuplicateDetection getDataDuplicateDetection(Context context, InProgressSubmission obj)
+ throws SearchServiceException {
+ // Test for a valid object or throw a not found exception
+ if (obj == null) {
+ throw new ResourceNotFoundException("Duplicate data step could not find valid in-progress submission obj");
+ }
+ // Initialise an empty section data object
+ DataDuplicateDetection data = new DataDuplicateDetection();
+
+ // Get the item for this submission object, throw a not found exception if null
+ Item item = obj.getItem();
+ if (item == null) {
+ throw new ResourceNotFoundException("Duplicate data step could not find valid item for the" +
+ " current in-progress submission obj id=" + obj.getID());
+ }
+ // Initialise empty list of PotentialDuplicateRest objects for use in the section data object
+ List potentialDuplicateRestList = new LinkedList<>();
+
+ // Get discovery search result for a duplicate detection search based on this item and populate
+ // the list of REST objects
+ List potentialDuplicates = duplicateDetectionService.getPotentialDuplicates(context, item);
+ for (PotentialDuplicate potentialDuplicate : potentialDuplicates) {
+ // Convert and add the potential duplicate to the list
+ potentialDuplicateRestList.add(converter.toRest(
+ potentialDuplicate, utils.obtainProjection()));
+ }
+
+ // Set the final duplicates list of the section data object
+ data.setPotentialDuplicates(potentialDuplicateRestList);
+
+ // Return section data
+ return data;
+ }
+
/**
* Utility method used by the {@link WorkspaceItemRestRepository} and
* {@link WorkflowItemRestRepository} to deal with the upload in an inprogress
@@ -336,10 +395,9 @@ public DataCCLicense getDataCCLicense(InProgressSubmission obj)
*/
public List uploadFileToInprogressSubmission(Context context, HttpServletRequest request,
AInprogressSubmissionRest wsi, InProgressSubmission source, MultipartFile file) {
-
// TAMU Customization - proxy license step
Optional sectionId = getSectionId(request);
-
+ // END TAMU Customization - proxy license step
List errors = new ArrayList();
SubmissionConfig submissionConfig =
submissionConfigService.getSubmissionConfigByName(wsi.getSubmissionDefinition().getName());
@@ -360,7 +418,6 @@ public List uploadFileToInprogressSubmission(Context context, HttpSer
stepClass = loader.loadClass(stepConfig.getProcessingClassName());
if (UploadableStep.class.isAssignableFrom(stepClass)) {
Object stepInstance = stepClass.newInstance();
-
// TAMU Customization - proxy license step - exclusive and only when matching step id
boolean isExclusiveMatchingStepId = ((UploadableStep) stepInstance).isExclusiveMatchingStepId();
if (isExclusiveMatchingStepId) {
@@ -372,6 +429,8 @@ public List uploadFileToInprogressSubmission(Context context, HttpSer
} else {
stepInstancesAndConfigs.add(new Object[] {stepInstance, stepConfig});
}
+ // stepInstancesAndConfigs.add(new Object[] {stepInstance, stepConfig});
+ // END TAMU Customization - proxy license step - exclusive and only when matching step id
}
} catch (Exception e) {
log.error(e.getMessage(), e);
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/UploadableStep.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/UploadableStep.java
index e3895be514ab..3ec77b24ade1 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/UploadableStep.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/UploadableStep.java
@@ -16,20 +16,22 @@
import org.springframework.web.multipart.MultipartFile;
/**
- * TAMU Customized interface for submission Steps that need to deal with file upload
+ * The interface for submission Steps that need to deal with file upload
*
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
public interface UploadableStep extends RestProcessingStep {
+ // TAMU Customization - proxy license step
/**
- * TAMU Customization - Method to specify step only invokes upload exclusively
+ * Method to specify step only invokes upload exclusively
* when matching step id from multipart form
*/
- default public boolean isExclusiveMatchingStepId() {
+ public default boolean isExclusiveMatchingStepId() {
return false;
}
+ // END TAMU Customization - proxy license step
/**
* The method to implement to support upload of a file in the submission section (aka panel / step)
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java
index 3c716e05bea1..e69ba241feda 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java
@@ -7,26 +7,34 @@
*/
package org.dspace.app.rest.submit.factory.impl;
-import javax.servlet.http.HttpServletRequest;
-
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.BooleanUtils;
-import org.dspace.app.rest.utils.ProxyLicenseUtils;
import org.dspace.content.InProgressSubmission;
import org.dspace.content.Item;
+import org.dspace.content.LicenseUtils;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
+import org.dspace.eperson.EPerson;
import org.springframework.beans.factory.annotation.Autowired;
+// TAMU Customization - proxy license step
+import org.dspace.app.rest.utils.ProxyLicenseUtils;
+// END TAMU Customization - proxy license step
+
/**
- * TAMU Customization - Customized Submission "add" PATCH operation
+ * Submission "add" PATCH operation
*
- * To accept/reject the granted license:
+ * To accept/reject the license.
*
* Example:
* curl -X PATCH http://${dspace.server.url}/api/submission/workspaceitems/31599 -H "Content-Type:
* application/json" -d '[{ "op": "add", "path": "/sections/license/granted", "value":"true"}]'
*
*
+ * Please note that according to the JSON Patch specification RFC6902 a
+ * subsequent add operation on the "granted" path will have the effect to
+ * replace the previous granted license with a new one.
+ *
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
public class LicenseAddPatchOperation extends AddPatchOperation {
@@ -62,12 +70,27 @@ void add(Context context, HttpServletRequest currentRequest, InProgressSubmissio
}
Item item = source.getItem();
-
+ // TAMU Customization - proxy license step
if (grant) {
ProxyLicenseUtils.grantLicense(context, item);
} else {
ProxyLicenseUtils.revokeLicense(context, item);
}
+ /*
+ EPerson submitter = context.getCurrentUser();
+
+ // remove any existing DSpace license (just in case the user
+ // accepted it previously)
+ itemService.removeDSpaceLicense(context, item);
+
+ if (grant) {
+ String license = LicenseUtils.getLicenseText(context.getCurrentLocale(), source.getCollection(), item,
+ submitter);
+
+ LicenseUtils.grantLicense(context, item, license, null);
+ }
+ */
+ // END TAMU Customization - proxy license step
}
}
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseRemovePatchOperation.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseRemovePatchOperation.java
index 2130364e1580..531cd7550688 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseRemovePatchOperation.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseRemovePatchOperation.java
@@ -7,19 +7,21 @@
*/
package org.dspace.app.rest.submit.factory.impl;
-import javax.servlet.http.HttpServletRequest;
-
-import org.dspace.app.rest.utils.ProxyLicenseUtils;
+import jakarta.servlet.http.HttpServletRequest;
import org.dspace.content.InProgressSubmission;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
+// TAMU Customization - proxy license step
+import org.dspace.app.rest.utils.ProxyLicenseUtils;
+// END TAMU Customization - proxy license step
+
/**
- * TAMU Customization - Customized Submission License "remove" patch operation.
+ * Submission License "remove" patch operation.
*
- * To revoke previous granted license:
+ * To remove a previous granted license:
*
* Example:
* curl -X PATCH http://${dspace.server.url}/api/submission/workspaceitems/31599 -H "Content-Type:
@@ -37,7 +39,11 @@ public class LicenseRemovePatchOperation extends RemovePatchOperation {
void remove(Context context, HttpServletRequest currentRequest, InProgressSubmission source, String path,
Object value) throws Exception {
Item item = source.getItem();
+ // TAMU Customization - proxy license step
+ // itemService.removeDSpaceLicense(context, item);
ProxyLicenseUtils.revokeLicense(context, item);
+ // END TAMU Customization - proxy license step
+
}
@Override
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java
index cf05cb74c727..188fda85bfb5 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java
@@ -7,13 +7,78 @@
*/
package org.dspace.app.rest.submit.factory.impl;
+// TAMU Customization - proxy license step
+/*
+import jakarta.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.BooleanUtils;
+import org.dspace.content.InProgressSubmission;
+import org.dspace.content.Item;
+import org.dspace.content.LicenseUtils;
+import org.dspace.content.service.ItemService;
+import org.dspace.core.Context;
+import org.dspace.eperson.EPerson;
+import org.springframework.beans.factory.annotation.Autowired;
+*/
+// END TAMU Customization - proxy license step
+
/**
- * TAMU Customization - Customized Submission "replace" patch operation
+ * Submission "replace" patch operation
*
* {@link LicenseAddPatchOperation}
*
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
+// TAMU Customization - proxy license step
public class LicenseReplacePatchOperation extends LicenseAddPatchOperation {
+}
+/*
+public class LicenseReplacePatchOperation extends ReplacePatchOperation {
+
+ @Autowired
+ ItemService itemService;
+
+ @Override
+ void replace(Context context, HttpServletRequest currentRequest, InProgressSubmission source, String path,
+ Object value) throws Exception {
+
+ Boolean grant = null;
+ // we are friendly with the client and accept also a string representation for the boolean
+ if (value instanceof String) {
+ grant = BooleanUtils.toBooleanObject((String) value);
+ } else {
+ grant = (Boolean) value;
+ }
+
+ if (grant == null) {
+ throw new IllegalArgumentException(
+ "Value is not a valid boolean expression (permitted value: on/off, true/false and yes/no");
+ }
+
+ Item item = source.getItem();
+ EPerson submitter = context.getCurrentUser();
+
+ // remove any existing DSpace license (just in case the user
+ // accepted it previously)
+ itemService.removeDSpaceLicense(context, item);
+
+ if (grant) {
+ String license = LicenseUtils.getLicenseText(context.getCurrentLocale(), source.getCollection(), item,
+ submitter);
+
+ LicenseUtils.grantLicense(context, item, license, null);
+ }
+ }
+
+ @Override
+ protected Class getArrayClassForEvaluation() {
+ return String[].class;
+ }
+
+ @Override
+ protected Class getClassForEvaluation() {
+ return String.class;
+ }
}
+*/
+// END TAMU Customization - proxy license step
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedAddPatchOperation.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedAddPatchOperation.java
index afd7d893f9ab..90cedb1b7043 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedAddPatchOperation.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedAddPatchOperation.java
@@ -8,7 +8,7 @@
package org.dspace.app.rest.submit.factory.impl;
import java.io.File;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.utils.ProxyLicenseUtils;
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedRemovePatchOperation.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedRemovePatchOperation.java
index 8c61efc0acd3..9f7ef1f266ed 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedRemovePatchOperation.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseSelectedRemovePatchOperation.java
@@ -7,7 +7,7 @@
*/
package org.dspace.app.rest.submit.factory.impl;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.dspace.content.InProgressSubmission;
import org.dspace.content.Item;
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/step/ProxyLicenseStep.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/step/ProxyLicenseStep.java
index 107cd90bd0d9..e53b78397d5c 100644
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/step/ProxyLicenseStep.java
+++ b/dspace/modules/server/src/main/java/org/dspace/app/rest/submit/step/ProxyLicenseStep.java
@@ -2,7 +2,7 @@
import java.util.ArrayList;
import java.util.List;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
@@ -27,6 +27,11 @@
import org.dspace.core.Context;
import org.springframework.web.multipart.MultipartFile;
+/**
+ * TAMU Customization
+ *
+ * Proxy License step for DSpace Spring Rest.
+ */
public class ProxyLicenseStep extends LicenseStep implements UploadableStep {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ProxyLicenseStep.class);
diff --git a/dspace/modules/server/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java b/dspace/modules/server/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java
deleted file mode 100644
index 464e23b58798..000000000000
--- a/dspace/modules/server/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * 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.app.rest.utils;
-
-import static java.util.Objects.isNull;
-import static java.util.Objects.nonNull;
-import static javax.mail.internet.MimeUtility.encodeText;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpHeaders;
-
-/**
- * This class takes data from the Bitstream/File that has to be send. It'll then digest this input and save it in
- * its local variables.
- * When calling {{@link #initialiseHeaders()}}, the input and information will be used to set the proper headers
- * with this info and return an Object of {@link HttpHeaders} to be used in the response that'll be generated
- */
-public class HttpHeadersInitializer {
-
- protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
- private static final String METHOD_HEAD = "HEAD";
- private static final String MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES";
- private static final String CONTENT_TYPE_MULTITYPE_WITH_BOUNDARY = "multipart/byteranges; boundary=" +
- MULTIPART_BOUNDARY;
- public static final String CONTENT_DISPOSITION_INLINE = "inline";
- public static final String CONTENT_DISPOSITION_ATTACHMENT = "attachment";
- private static final String IF_NONE_MATCH = "If-None-Match";
- private static final String IF_MODIFIED_SINCE = "If-Modified-Since";
- private static final String ETAG = "ETag";
- private static final String IF_MATCH = "If-Match";
- private static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
- private static final String CONTENT_TYPE = "Content-Type";
- private static final String ACCEPT_RANGES = "Accept-Ranges";
- private static final String BYTES = "bytes";
- private static final String LAST_MODIFIED = "Last-Modified";
- private static final String EXPIRES = "Expires";
- private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
- private static final String IMAGE = "image";
- private static final String ACCEPT = "Accept";
- private static final String CONTENT_DISPOSITION = "Content-Disposition";
- private static final String CONTENT_DISPOSITION_FORMAT = "%s;filename=\"%s\"";
- private static final String CACHE_CONTROL = "Cache-Control";
-
- private int bufferSize = 1000000;
-
- private static final long DEFAULT_EXPIRE_TIME = 60L * 60L * 1000L;
-
- //no-cache so request is always performed for logging
- private static final String CACHE_CONTROL_SETTING = "private,no-cache";
-
- private HttpServletRequest request;
- private HttpServletResponse response;
- private String contentType;
- private String disposition;
- private long lastModified;
- private long length;
- private String fileName;
- private String checksum;
-
- public HttpHeadersInitializer() {
- //Convert to BufferedInputStream so we can re-read the stream
- }
-
- public HttpHeadersInitializer with(HttpServletRequest httpRequest) {
- request = httpRequest;
- return this;
- }
-
- public HttpHeadersInitializer with(HttpServletResponse httpResponse) {
- response = httpResponse;
- return this;
- }
-
- public HttpHeadersInitializer withLength(long length) {
- this.length = length;
- return this;
- }
-
- public HttpHeadersInitializer withFileName(String fileName) {
- this.fileName = fileName;
- return this;
- }
-
- public HttpHeadersInitializer withChecksum(String checksum) {
- this.checksum = checksum;
- return this;
- }
-
- public HttpHeadersInitializer withMimetype(String mimetype) {
- this.contentType = mimetype;
- return this;
- }
-
- public HttpHeadersInitializer withLastModified(long lastModified) {
- this.lastModified = lastModified;
- return this;
- }
-
- public HttpHeadersInitializer withBufferSize(int bufferSize) {
- if (bufferSize > 0) {
- this.bufferSize = bufferSize;
- }
- return this;
- }
- public HttpHeadersInitializer withDisposition(String contentDisposition) {
- this.disposition = contentDisposition;
- return this;
- }
-
- /**
- * This method will be called to create a {@link HttpHeaders} object which will contain the headers needed
- * to form a proper response when returning the Bitstream/File
- * @return A {@link HttpHeaders} object containing the information for the Bitstream/File to be sent
- * @throws IOException If something goes wrong
- */
- public HttpHeaders initialiseHeaders() throws IOException {
-
- HttpHeaders httpHeaders = new HttpHeaders();
- // Validate and process range -------------------------------------------------------------
-
- log.debug("Content-Type : {}", contentType);
- //TODO response.reset() => Can be re-instated/investigated once we upgrade to Spring 5.2.9, see issue #3056
- // Initialize response.
- response.setBufferSize(bufferSize);
- if (contentType != null) {
- httpHeaders.put(CONTENT_TYPE, Collections.singletonList(contentType));
- }
- httpHeaders.put(ACCEPT_RANGES, Collections.singletonList(BYTES));
- if (checksum != null) {
- httpHeaders.put(ETAG, Collections.singletonList(checksum));
- }
- httpHeaders.put(LAST_MODIFIED, Collections.singletonList(FastHttpDateFormat.formatDate(lastModified)));
- httpHeaders.put(EXPIRES, Collections.singletonList(FastHttpDateFormat.formatDate(
- System.currentTimeMillis() + DEFAULT_EXPIRE_TIME)));
-
- //No-cache so that we can log every download
- httpHeaders.put(CACHE_CONTROL, Collections.singletonList(CACHE_CONTROL_SETTING));
-
- if (isNullOrEmpty(disposition)) {
- if (contentType == null) {
- contentType = APPLICATION_OCTET_STREAM;
- } else if (!contentType.startsWith(IMAGE)) {
- String accept = request.getHeader(ACCEPT);
- disposition = accept != null && accepts(accept,
- contentType) ? CONTENT_DISPOSITION_INLINE :
- CONTENT_DISPOSITION_ATTACHMENT;
- }
-
- }
-
- httpHeaders.put(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,
- Collections.singletonList(HttpHeaders.ACCEPT_RANGES));
- // TAMU Customization - without knowing details only add Content-Disposition header if disposition defined
- // httpHeaders.put(CONTENT_DISPOSITION, Collections.singletonList(String.format(CONTENT_DISPOSITION_FORMAT,
- // disposition,
- // encodeText(fileName))));
- if (!isNullOrEmpty(disposition)) {
- httpHeaders.put(CONTENT_DISPOSITION, Collections.singletonList(String.format(CONTENT_DISPOSITION_FORMAT,
- disposition,
- encodeText(fileName))));
- }
-
- log.debug("Content-Disposition : {}", disposition);
-
- // Content phase
- // TAMU Customization - return headers regardless of request verb
- // if (METHOD_HEAD.equals(request.getMethod())) {
- // log.debug("HEAD request - skipping content");
- // return null;
- // }
-
- return httpHeaders;
-
- }
-
- /**
- * This method will validate whether or not the given Response/Request/Information/Variables are valid.
- * If they're invalid, the Response shouldn't be given.
- * This will do null checks on the response, request, inputstream and filename.
- * Other than this, it'll check Request headers to see if their information is correct.
- * @return
- * @throws IOException
- */
- public boolean isValid() throws IOException {
- if (response == null || request == null) {
- return false;
- }
-
- if (StringUtils.isEmpty(fileName)) {
- response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- return false;
- }
-
- // Validate request headers for caching ---------------------------------------------------
- // If-None-Match header should contain "*" or ETag. If so, then return 304.
- String ifNoneMatch = request.getHeader(IF_NONE_MATCH);
- if (nonNull(ifNoneMatch) && matches(ifNoneMatch, checksum)) {
- log.debug("If-None-Match header should contain \"*\" or ETag. If so, then return 304.");
- response.setHeader(ETAG, checksum); // Required in 304.
- response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
- return false;
- }
-
- // If-Modified-Since header should be greater than LastModified. If so, then return 304.
- // This header is ignored if any If-None-Match header is specified.
- long ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE);
- if (isNull(ifNoneMatch) && ifModifiedSince != -1 && ifModifiedSince + 1000 > lastModified) {
- log.debug("If-Modified-Since header should be greater than LastModified. If so, then return 304.");
- response.setHeader(ETAG, checksum); // Required in 304.
- response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
- return false;
- }
-
- // Validate request headers for resume ----------------------------------------------------
-
- // If-Match header should contain "*" or ETag. If not, then return 412.
- String ifMatch = request.getHeader(IF_MATCH);
- if (nonNull(ifMatch) && !matches(ifMatch, checksum)) {
- log.error("If-Match header should contain \"*\" or ETag. If not, then return 412.");
- response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
- return false;
- }
-
- // If-Unmodified-Since header should be greater than LastModified. If not, then return 412.
- long ifUnmodifiedSince = request.getDateHeader(IF_UNMODIFIED_SINCE);
- if (ifUnmodifiedSince != -1 && ifUnmodifiedSince + 1000 <= lastModified) {
- log.error("If-Unmodified-Since header should be greater than LastModified. If not, then return 412.");
- response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
- return false;
- }
-
- return true;
- }
-
-
- private static boolean isNullOrEmpty(String disposition) {
- return StringUtils.isBlank(disposition);
- }
-
-
- private static boolean accepts(String acceptHeader, String toAccept) {
- String[] acceptValues = acceptHeader.split("\\s*(,|;)\\s*");
- Arrays.sort(acceptValues);
-
- return Arrays.binarySearch(acceptValues, toAccept) > -1
- || Arrays.binarySearch(acceptValues, toAccept.replaceAll("/.*$", "/*")) > -1
- || Arrays.binarySearch(acceptValues, "*/*") > -1;
- }
-
- private static boolean matches(String matchHeader, String toMatch) {
- String[] matchValues = matchHeader.split("\\s*,\\s*");
- Arrays.sort(matchValues);
- return Arrays.binarySearch(matchValues, toMatch) > -1 || Arrays.binarySearch(matchValues, "*") > -1;
- }
-
-}