Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Paul Warren
    @paulcwarren
    K. That makes sense Sunil. Thanks much.
    sunilfastcode
    @sunilfastcode
    Hi Paul, did you encounter this error before? I am using Postman to set the content and it fails: org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
    Paul Warren
    @paulcwarren
    The multipart file you attach to the request should be called 'file'
    sunilfastcode
    @sunilfastcode
    Yeah, I am calling it file, but am still getting that error. There are a number of StackOverflow questions about this issue and I have tried all the suggested solutions with no luck.
    Paul Warren
    @paulcwarren
    Hi Sunil, I updated the getting started with rest guide to include testing that includes an example of posting content with postman. Hopefully, that helps?
    Paul Warren
    @paulcwarren
    Did the gettingstarted guide help any @sunilfastcode ?
    sunilfastcode
    @sunilfastcode
    Hi @paulcwarren, I am still facing the same issue. The weird thing is that your examples all work without any problem when I create a separate project for Spring Content, but when I embed Spring Content into an existing Spring Boot application, I am facing this issue. I already spent 10+ hours trying various solutions with no luck. I am going to try again today and let you know.
    Paul Warren
    @paulcwarren
    That's annoying. I am sorry to hear that. Are you getting any sort of stack trace on the server?
    Thomas Pliakas
    @pliakas
    Hello, when I am saving a file, I want to keep the filename extension in the ContentId, e.g (1b3826ad-8803-4619-98af-68104572935e.mp4). Is this possible ?
    Paul Warren
    @paulcwarren
    I assume you are using a ContentStore, rather than a Store @pliakas ?
    Paul Warren
    @paulcwarren

    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.

    Thomas Pliakas
    @pliakas
    Thanks for the help Paul :)
    Piotr Chłystek
    @pchlystek

    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.

    Where I made a mistake?
    The exception is:
    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: {}
    And this is the ResourceContentStore:
    public interface ResourceContentStore extends ContentStore<Resource, String> {
    }
    Piotr Chłystek
    @pchlystek

    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.

    Paul Warren
    @paulcwarren
    I can try and help. By the looks, you have typed your ContentStore to a Spring Resource. ContentStores 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?
    Piotr Chłystek
    @pchlystek
    Resource it's a Entity class from my package, coincidence of names is accidental.
    In addition to spring-content-fs, I want spring-content-s3 (depending on deployment (and configuration) - onpremises / kubernetes installation), I want to keep files in other places.
    After adding the s3 starter to the application, the autoconfiguration does not create a ContentStore bean - ResourceContentStore.
    Piotr Chłystek
    @pchlystek
    Thank you for your interest in the problem.
    Paul Warren
    @paulcwarren
    Got it. Thanks for the clarifications. Then I think you are headed in the right direction. You should add both storage module dependencies. But because you have both that means Spring Content will enter a "strict" mode when parsing for Stores; i.e. because you have two storage modules on the classpath it wont know what implementation you want for ResourceContenStore so you will need to tell it by adding two stores that extend the implementation-specific ContentStores; i.e. FilesystemResourceContentStore extends FilesystemContentStoreand 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.
    Also, Spring Content REST should work on top of this too (in case you are using it)
    Piotr Chłystek
    @pchlystek
    I confirm that the solution proposed by you works. Thank you very much for your help!
    Paul Warren
    @paulcwarren
    Excellent. Glad I could help
    乐哥
    @lmtoo
    workingCopy need unlock?
    I have a newContentCopy method ,which to handle workingCopy and locking
    like this ```java
        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);
            }
        }
    but , this will have too many ObjectOptimisticLockingFailureException, which is the right coding about this?
    I should return newContent or content ? which is latest version ?
    乐哥
    @lmtoo
    @paulcwarren
    Paul Warren
    @paulcwarren
    You should return newContent. BUT, I wouldn't expect an unlock before version is called.
    A working copy is meant to be a private working copy that only you can see. If you 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.
    乐哥
    @lmtoo
    repository.unlock(newContent); will have a new version newContent , but if I change to ```java
    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
    IDEA will have >'return' inside 'finally' block
    'return' inside 'finally' block
    Paul Warren
    @paulcwarren
    newWorkingCopy creates a new object but but only partially sets it up in the version series. So unlocking immediately will leave it partially established. You should call version then unlock.
    Or alternatively, just call 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?
    乐哥
    @lmtoo
    'newWorkingCopy'? you mean LockingAndVersioningRepository.workingCopy?
    Paul Warren
    @paulcwarren
    Yes, sorry! Don't know my own code
    The more I look at your example the more I think you should be calling 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
    乐哥
    @lmtoo
    so, workingCopy will create a record to locks table? and version will not? workingCopy will have long time locking? version will have short time locking?
    yes, I will do that , thanks
    Paul Warren
    @paulcwarren
    lock and unlock create the entries in the locks table. Both workingCopy and version will transfer the lock to the new entity in the version series.
    are you trying to do automatic versioning? because I recently added support to spring content for spring data envers
    乐哥
    @lmtoo
    I just want to have new version entity, and handle lock and unlock
    Paul Warren
    @paulcwarren
    K. Spring data envers will automatically create a new version of an entity whenever you save it. And with the support in spring-content it will do that for every setContent operation too. This is all done through 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.