ResourceContenStore
so you will need to tell it by adding two stores that extend the implementation-specific ContentStores
; i.e. FilesystemResourceContentStore extends FilesystemContentStore
and S3ResourceContentStore extends S3ContentStore
. That will have a bit of a ripple effect into your storageService bean initializor methods but SpringContentStorageService
can be typed to just ContentStore
. I believe that might work for you.
public static <T, ID extends Serializable> T newContentCopy(LockingAndVersioningRepository<T, ID> repository, T content, Consumer<T> onNewCopy) {
content = repository.lock(content);
try {
T newContent = repository.workingCopy(content);
try {
onNewCopy.accept(newContent);
return newContent;
} finally {
repository.unlock(newContent);
}
} finally {
repository.unlock(content);
}
}
unlock
someone else could then lock content and create another working copy. I am not sure that I have tested that! My assumption has always been that the lock extends across newWorkinCopy
and version
but that said, perhaps unlock should throw an error if a working copy exists.
public static <T, ID extends Serializable> T newContentCopy(LockingAndVersioningRepository<T, ID> repository, T content, Predicate<T> predicate, Consumer<T> onNewCopy) {
content = repository.lock(content);
try {
if (predicate.test(content)){
T newContent = repository.workingCopy(content);
try {
onNewCopy.accept(newContent);
} finally {
return repository.unlock(newContent);
}
}
} finally {
repository.unlock(content);
}
return null;
}```java
'return' inside 'finally' block
version
instead on newWorkingCopy
as it looks like you have no need for a real private working copy that can be edited multiple times and saved before versioning?
version
, not workingCopy
. Working copies is a construct brought over from CMIS and is meant for use cases where you have a user that will want to edit their 'word doc' many times before versioning it. Your code suggests you dont want working copies. You just want to version
save
and setContent
and because it is handled by hibernate removes the need for the pessimistic locking. It is more of an auditing thing but I mention it because it might be a better solution for you, depending on your use case.
workingCopy
doesn't set @SuccessorId, I think I have to use this method
version
can replaced with workingCopy
?
Is it theoretically possible to place two store systems on classpath e.g. s3 and filesystem and based on the application property switch which one should be used ?
I tried something like this:
@ConditionalOnProperty(prefix = "springcontentdemo.storage", name = "type", havingValue = "filesystem")
@EnableFilesystemStores("com.springcontentdemo.store")
@Configuration
public class FilesystemStorageConfig { ... }
@ConditionalOnProperty(prefix = "springcontentdemo.storage.", name = "type", havingValue = "s3", matchIfMissing = true)
@EnableS3Stores("com.springcontentdemo.store")
@Configuration
public class S3StorageConfig { ... }
and i have spring-content-fs and spring-content-s3 as project dependencies and it is not working ... content store beans are not created ... it looks like FilesystemStoreRegistrar and S3StoresRegistrar are in conflict in case they both are on classpath.
Even in case I remove one of these two spring config classes then it does not help ... it starts working only when I remove one of these two dependencies (s3 or fs) from project
Is it ok that in DefaultS3StoreImpl#setContent(S, java.io.InputStream)
method os
variable is closed twice ? one using IOUtils.closeQuietly(os)
and the second time in finally block os.close()
?
problem is that this second closing of output stream sometimes (not sure when and why) causes that SimpleStorageResource.finishSimpleUpload() method is invoked again, so s3client is uploading file twice and the second try fails with this error:Caused by: com.amazonaws.SdkClientException: Unable to verify integrity of data upload. Client calculated content hash (contentMD5: FQeFaRaSLRVt4MnXW7KyWQ== in base 64) didn't match hash (etag: 5289df737df57326fcdd22597afb1fac in hex) calculated by Amazon S3.
I can reproduce it very easily when I try to call setContent method twice with different stream, e.g. something like this:
designPlanAttachmentStore.setContent(attachment, new ByteArrayInputStream(FILE_DATA));
designPlanAttachmentStore.setContent(attachment2, new ByteArrayInputStream(FILE_DATA_2));
the first setContent call is always successful (calling of os.close() in finally block does not trigger finishSimpleUpload()), but it always fails on the second setContent call as in this case os.close() in finally block trigger finishSimpleUpload()
I'm not sure if problem is this os.close()
in finally block or there is some issue in SimpleStorageResource