1

What I intend to do: I'd like to use multiple ContentStores in the same system: one for freshly uploaded files (filesystem), one for (long term) archiving (AWS S3 or maybe GCS).

What I tried (and what actually does work):

  1. Extended class File by another attribute private String contentStoreName;

  2. Creating two ContentStores like described here: Spring-Content: Moving files from content store to another content store

  3. Extending gettingstarted.FileContentController.setContent(Long, MultipartFile) by setting an identifier for the used ContentStore: f.get().setContentStoreName("regular");

  4. Getting the content in dependence of the stored contentStoreName:

    InputStream input;
    if (Objects.equals(f.get().getContentStoreName(), "archive")) {
        input = archiveContentStore.getContent(f.get());
    } else {
        input = regularContentStore.getContent(f.get());
    }
    
  5. Changing the contentStoreName when moving from one ContentStore to another:

    Resource resource = regularContentStore.getResource(fileEntity.get());
    archiveContentStore.setContent(fileEntity.get(), resource);
    fileEntity.get().setContentStoreName("archive");
    filesRepo.save(fileEntity.get());
    

The smell about this: Despite this code works, I guess it's not the intended way, because Spring-content usually does a lot with annotations and some magic in the background. But I can't find an annotation for an identifier / name for the ContentStore.

Question: Is there a more intended way of doing this in Spring-Content?

S. Doe
  • 685
  • 1
  • 6
  • 25

1 Answers1

1

Beyond supporting multiple storage modules in a single application (via the FilesystemContentStore, et al annotations) Spring Content does not currently provide any logic for supporting classes of storage. That would be a layer that you need to create on top of Spring Content as you are starting to do.

In terms of Spring Content annotations it might be helpful for you to understand what modules manage what annotations.

Spring Content storage modules; FS, S3, etc all implement ContentStore and in doing so all provide management of the @ContentId and @ContentLength attributes (in addition to managing the actual content operations). Looks like you are using the ContentStore API (getContent/setContent) and therefore your entity's content id and length attributes will be managed for you.

Spring Content REST then provides management of @MimeType and @OriginalFileName attributes (in addition to providing comprehensive REST endpoints). My guess is that you are not using this and instead providing your own custom controller REST API that uses the 'contentStoreName' attribute to decide which store to put/get the content from. This approach seems fine.

That is all to say that a slightly more elegant approach, perhaps, that would allow you to use Spring Content REST might be to implement your own custom Archiving Storage module and encapsulate the "switching" logic you have above in its setContent/getContent/unsetContent methods. Note, this is actually quite easy (just 4 or 5 classes and I would point you at the GCP and Azure modules for inspiration). Note, that the REST API (for ContentStore) only calls those 3 APIs too so those are the only ones you would need to implement. This would mean you get to use Spring Content REST and all the features it provides; set of rest endpoints, byte range support and so on as well as encapsulating your "archiving" logic nicely.

Paul Warren
  • 2,411
  • 1
  • 15
  • 22