diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java index 9a532c8a9d..a7df6a526a 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -92,6 +92,31 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp return bitstreamDAO.findAll(context, Bitstream.class); } + @Override + public Bitstream clone(Context context, Bitstream bitstream) + throws SQLException { + // Create a new bitstream with a new ID. + Bitstream clonedBitstream = bitstreamDAO.create(context, new Bitstream()); + // Set the internal identifier, file size, checksum, and + // checksum algorithm as same as the given bitstream. + clonedBitstream.setInternalId(bitstream.getInternalId()); + clonedBitstream.setSizeBytes(bitstream.getSize()); + clonedBitstream.setChecksum(bitstream.getChecksum()); + clonedBitstream.setChecksumAlgorithm(bitstream.getChecksumAlgorithm()); + try { + //Update our bitstream but turn off the authorization system since permissions + //haven't been set at this point in time. + context.turnOffAuthorisationSystem(); + update(context, clonedBitstream); + } catch (AuthorizeException e) { + log.error(e); + //Can never happen since we turn off authorization before we update + } finally { + context.restoreAuthSystemState(); + } + return clonedBitstream; + } + @Override public Iterator findAll(Context context, int limit, int offset) throws SQLException { return bitstreamDAO.findAll(context, limit, offset); diff --git a/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java b/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java index 29780e5e93..1880aa3166 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/BitstreamService.java @@ -35,6 +35,22 @@ public interface BitstreamService extends DSpaceObjectService, DSpace public Iterator findAll(Context context, int limit, int offset) throws SQLException; + /** + * Clone the given bitstream by firstly creating a new bitstream, with a new ID. + * Then set the internal identifier, file size, checksum, and + * checksum algorithm as same as the given bitstream. + * This allows multiple bitstreams to share the same internal identifier of assets . + * An example of such a use case scenario is versioning. + * + * @param context + * DSpace context object + * @param bitstream + * Bitstream to be cloned + * @return the clone + * @throws SQLException if database error + */ + public Bitstream clone(Context context, Bitstream bitstream) throws SQLException; + /** * Create a new bitstream, with a new ID. The checksum and file size are * calculated. No authorization checks are made in this method. diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java index 072190dee4..18e1f33388 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageServiceImpl.java @@ -348,14 +348,18 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini */ @Override public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, IOException, AuthorizeException { - Bitstream clonedBitstream = bitstreamService.create(context, bitstreamService.retrieve(context, bitstream)); + Bitstream clonedBitstream = bitstreamService.clone(context, bitstream); + clonedBitstream.setStoreNumber(bitstream.getStoreNumber()); + List metadataValues = bitstreamService .getMetadata(bitstream, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + for (MetadataValue metadataValue : metadataValues) { - bitstreamService - .addMetadata(context, clonedBitstream, metadataValue.getMetadataField(), metadataValue.getLanguage(), - metadataValue.getValue(), metadataValue.getAuthority(), metadataValue.getConfidence()); + bitstreamService.addMetadata(context, clonedBitstream, metadataValue.getMetadataField(), + metadataValue.getLanguage(), metadataValue.getValue(), metadataValue.getAuthority(), + metadataValue.getConfidence()); } + bitstreamService.update(context, clonedBitstream); return clonedBitstream; } diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java index 59ab6aa399..95963b14ca 100644 --- a/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java +++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/service/BitstreamStorageService.java @@ -140,6 +140,19 @@ public interface BitstreamStorageService { */ public void cleanup(boolean deleteDbRecords, boolean verbose) throws SQLException, IOException, AuthorizeException; + /** + * Clone the given bitstream to a new bitstream with a new ID. + * Metadata of the given bitstream are also copied to the new bitstream. + * + * @param context + * DSpace context object + * @param bitstream + * the bitstream to be cloned + * @return id of the clone bitstream. + * @throws SQLException if database error + * @throws IOException if IO error + * @throws AuthorizeException if authorization error + */ public Bitstream clone(Context context, Bitstream bitstream) throws SQLException, IOException, AuthorizeException; /** diff --git a/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java b/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java index a016539549..8b0ca9aeb8 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java +++ b/dspace-api/src/main/java/org/dspace/versioning/AbstractVersionProvider.java @@ -81,7 +81,10 @@ public abstract class AbstractVersionProvider { authorizeService.addPolicies(c, bundlePolicies, bundleNew); for (Bitstream nativeBitstream : nativeBundle.getBitstreams()) { - Bitstream bitstreamNew = createBitstream(c, nativeBitstream); + // Metadata and additional information like internal identifier, + // file size, checksum, and checksum algorithm are set by the bitstreamStorageService.clone(...) + // and respectively bitstreamService.clone(...) method. + Bitstream bitstreamNew = bitstreamStorageService.clone(c, nativeBitstream); bundleService.addBitstream(c, bundleNew, bitstreamNew); @@ -106,19 +109,6 @@ public abstract class AbstractVersionProvider { } - protected Bitstream createBitstream(Context context, Bitstream nativeBitstream) - throws AuthorizeException, SQLException, IOException { - Bitstream newBitstream = bitstreamStorageService.clone(context, nativeBitstream); - List bitstreamMeta = bitstreamService - .getMetadata(nativeBitstream, Item.ANY, Item.ANY, Item.ANY, Item.ANY); - for (MetadataValue value : bitstreamMeta) { - bitstreamService - .addMetadata(context, newBitstream, value.getMetadataField(), value.getLanguage(), value.getValue(), - value.getAuthority(), value.getConfidence()); - } - return newBitstream; - } - public void setIgnoredMetadataFields(Set ignoredMetadataFields) { this.ignoredMetadataFields = ignoredMetadataFields; }