Assuming you are then you should be able to register a converter that converts from your entity's type to String. This will be invoked every time content is accessed:
@Bean
public FilesystemStoreConfigurer configurer() {
return new FilesystemStoreConfigurer() {
@Override
public void configureFilesystemStoreConverters(ConverterRegistry registry) {
registry.addConverter(new Converter<File, String>() {
@Override
public String convert(File file) {
if (file.getContentId() == null) {
file.setContentId(format("%s.%s", UUID.randomUUID().toString(), mimeTypeToExtension(file.getMimeType())));
}
return file.getContentId();
}
});
}
};
}
You can use this converter to add the file extension to the store's filename. Note, this basically means you take control of creating the contentId.
Hello, I have a problem with configuring two storage types - FS and S3 (not at the same moment) in my Spring Boot app.
I have the class with the configuration for FS:
@Configuration
@ConditionalOnProperty(value = "storage.type", havingValue = "springContentFilesystem")
@EnableFilesystemStores
public class SpringContentFilesystemStorageConfig {
@Bean
FileSystemResourceLoader storageLocationResourceLoader(StorageProperties storageProperties) {
return new FileSystemResourceLoader(storageProperties.getAbsoluteStorageLocationPath().toString());
}
@Bean
StorageService storageService(ResourceContentStore resourceContentStore) {
return new SpringContentStorageService(resourceContentStore);
}
}
and the second one for S3:
@Configuration
@ConditionalOnProperty(value = "storage.type", havingValue = "springContentS3")
@EnableS3Stores
public class SpringContentS3StorageConfig {
@Bean
public AmazonS3 s3Client(@Value("${storage.s3.region}") String s3region) {
return AmazonS3ClientBuilder.standard()
.withRegion(Regions.fromName(s3region))
.withCredentials(new EnvironmentVariableCredentialsProvider())
.build();
}
@Bean
StorageService storageService(ResourceContentStore resourceContentStore) {
return new SpringContentStorageService(resourceContentStore);
}
}
Currently, this class with the configuration is not imported / scanned anywhere - just adding spring-content-s3-boot-starter to the classpath (pom.xml) causes that the Bean of the ContentStore type is not created - context does not get up.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'storageService' defined in com.mypackage.storage.springcontent.SpringContentFilesystemStorageConfig: Unsatisfied dependency expressed through method 'storageService' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mypackage.storage.springcontent.ResourceContentStore' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
public interface ResourceContentStore extends ContentStore<Resource, String> {
}
In my opinion, the problem lies somewhere in the auto-configuration when we have these two modules simultaneously:
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs-boot-starter</artifactId>
<version>1.1.0.M4</version>
</dependency>
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-s3-boot-starter</artifactId>
<version>1.1.0.M4</version>
</dependency>
But I can't figure out exactly what's going on.
ContentStore
s are for associating content with Spring Data Entities and therefore you would type your ContentStore to your Entity; e.g. something like public interface MyEntityContentStore extends ContentStore<MyEntity, String>
. If you don't want to do this then you would probably be best using a Store; e.g. public interface MyStore extends Store<String>
. Which are you trying to do?
ResourceContentStore
.
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