Class DefaultStorageService
- All Implemented Interfaces:
StorageService
- Author:
- Chad Harchar (charchar), Samarth Dhruva (samarthd)
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final class
A simple object holding information about aZipEntry
which failed validation for some reason.static class
A simple object holding information about the results of extracting the contents of a zip file. -
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final AssetService<Asset>
protected AssetStorageUtils
protected static final String
protected static final String
protected final FileUploadStateService<FileUploadState>
protected final FolderService<Folder>
protected final ImageOperationService
protected final InternalAssetProperties
static final String
protected final jakarta.servlet.MultipartConfigElement
static final String
protected final com.broadleafcommerce.common.extension.data.DataRouteReference
protected final StorageProvider
protected final com.broadleafcommerce.common.extension.TypeFactory
static final String
-
Constructor Summary
ConstructorsConstructorDescriptionDefaultStorageService
(AssetService<Asset> assetService, FolderService<Folder> folderService, jakarta.servlet.MultipartConfigElement multipartConfigElement, StorageProvider storageProvider, InternalAssetProperties internalAssetProperties, com.broadleafcommerce.common.extension.TypeFactory typeFactory, ImageOperationService imageOperationService, FileUploadStateService<FileUploadState> fileUploadStateService, jakarta.activation.FileTypeMap mimeFileTypeMap, AssetUrlGenerationHelper assetUrlGenerationHelper, com.broadleafcommerce.common.extension.data.DataRouteReference reference) -
Method Summary
Modifier and TypeMethodDescriptionvoid
addAttributesToAsset
(@NonNull Asset asset, @NonNull ResourceWithMetadata resource) Responsible for adding any attributes to the asset that are derived from the uploadedResource
.void
addAttributesToAsset
(@NonNull Asset asset, @NonNull File file) Responsible for adding any attributes to the asset that are derived from the uploaded file.protected void
addImageAttributes
(@NonNull Asset asset, @NonNull Dimension imageDimension) protected void
batchOptimizeFiles
(Map<String, File> filesToOptimizeByNormalizedPath) Delegates toImageOperationService
to optimize the given files as a batch.protected String
buildErrorMessage
(@NonNull List<DefaultStorageService.ZipEntryValidationError> errors) protected void
buildFolderAndPutInMap
(String directoryPath, Map<String, Folder> foldersByNormalizedPath, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Given a directory path that was found in a zip file, build aFolder
for it and put it in the givenfoldersByPath
map.createAllFolders
(Map<String, Folder> foldersToCreateByNormalizedPath, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, Asset assetRequest) Creates all of the givenFolders
in the data store, and returns the created items.createAssetsForSuccessfullyUploadedFiles
(DefaultStorageService.ZipExtractionResult zipExtractionResult, Map<String, String> contextDiscriminatedUrlsByNormalizedPath, Map<String, Folder> createdFoldersByNormalizedPath, BulkAddResourcesResponse addResourcesResponse, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) CreatesAssets
in the data store for the files that were successfully uploaded to the storage provider.protected String
createUniqueUrlFromFilename
(String filename, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Creates a URL for the given filename.protected String
createUniqueUrlFromFilename
(String filename, String folderName, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Creates a URL for the given filename.protected boolean
exceedsMaxIndividualAssetSize
(long individualAssetSizeInBytes) protected boolean
exceedsMaxZipFileSize
(long zipSizeInBytes) protected void
extractCurrentEntryToFile
(ZipInputStream zipInputStream, File extractionTarget) Reads the current zip entry's data and writes it to theextractionTarget
.protected void
extractToFileAndPutInMap
(String entryPath, Path tempDirectoryForExtraction, ZipInputStream zipInputStream, Map<String, File> filesByNormalizedPath) Creates a new file inside oftempDirectoryForExtraction
, extracts the current zip entry's data to it viaextractCurrentEntryToFile(ZipInputStream, File)
, and then puts the appropriate mapping infilesByPath
.extractZip
(File zipFile, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) protected Asset
generateAssetForUploadRequest
(Asset assetRequest, String mimeType, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Generates a newAsset
object for an upload using the mime type and optional properties provided inassetRequest
.generateAssetsForFiles
(Stream<Map.Entry<String, File>> filesByNormalizedPath, Map<String, String> contextDiscriminatedUrlsByNormalizedPath, Map<String, Folder> createdFoldersByNormalizedPath, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) protected String
generateContextDiscriminatedUniqueUrl
(String filePath, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Given a file path, generate a unique URL with a context-discrimination prefix that's suitable for being supplied to the storage provider.protected String
generateContextDiscriminatedUniqueUrl
(String filePath, String folderName, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Given a file path, generate a unique URL with a context-discrimination prefix that's suitable for being supplied to the storage provider.generateContextDiscriminatedUniqueUrls
(Collection<String> filePaths, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Deprecated.generateContextDiscriminatedUniqueUrls
(Collection<String> filePaths, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean ignoreFolderName) Given a collection of file names, generates a unique URL for each with a context-discrimination prefix that's suitable for being supplied to the storage provider.getAssetDimensions
(@NonNull ResourceWithMetadata videoResource) Gets dimensions for given assetResourceWithMetadata
getAssetDimensions
(@NonNull File assetFile) Gets dimensions for given asset filegetAssetDimensions
(@NonNull InputStream fileInputStream) Gets dimensions for given assetInputStream
protected AssetStorageUtils
protected AssetUrlGenerationHelper
getFailedNormalizedFilePaths
(DefaultStorageService.ZipExtractionResult zipExtractionResult, BulkAddResourcesResponse addResourcesResponse, Map<String, String> contextDiscriminatedUrlsByNormalizedPath) getImageDimensions
(@NonNull ResourceWithMetadata imageResource) Deprecated, for removal: This API element is subject to removal in a future version.getImageDimensions
(@NonNull File assetFile) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofgetAssetDimensions(InputStream)
getImageDimensions
(@NonNull ImageInputStream imageInputStream) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofgetAssetDimensions(InputStream)
protected String
protected jakarta.activation.FileTypeMap
protected String
getMimeType
(String fileName) protected String
getMimeType
(org.springframework.web.multipart.MultipartFile file) protected String
getMimeTypeNotSupportedErrorMessage
(String mimeType) protected String
getParentDirectoryPath
(String normalizedPath) Gets the parent directory path from the given normalized path.protected String
getParentFolderId
(String normalizedPath, Map<String, Folder> createdFoldersByNormalizedPath, Asset assetRequest) Gets the parent directory path fromnormalizedPath
, gets theFolder
for that parent directory path increatedFoldersByNormalizedPath
, and returns itsFolder.getId()
.protected String
protected void
handleExceptionWithZipFile
(FileUploadState uploadState, String zipFileName, Exception e, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) protected void
handleFailedValidationWithZipFile
(FileUploadState uploadState, String zipFileName, String errorMessage, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) protected boolean
isWhitelistedMimeType
(String mimeType) protected boolean
protected void
mapEligibleProperties
(Asset targetAsset, Asset source) Ifsource
is present, will copy itsAsset.getTags()
,Asset.getFolderId()
andAsset.getLocale()
totargetAsset
.protected boolean
matchesAnyResourceNameToIgnore
(String resourceName) protected void
processZipExtractionResult
(DefaultStorageService.ZipExtractionResult zipExtractionResult, FileUploadState uploadState, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg) Deprecated.protected void
processZipExtractionResult
(DefaultStorageService.ZipExtractionResult zipExtractionResult, FileUploadState uploadState, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg, boolean ignoreFolderName) Given aDefaultStorageService.ZipExtractionResult
, creates all of the necessaryFolders
in the data store, uploads the extracted files to the storage provider (after optimizing them if necessary), and createsAssets
in the data store for all successfully uploaded files.protected boolean
readEntryAndReturnIfSizeExceedsLimit
(ZipInputStream zipInputStream) Reads and counts the byte size of the current entry in the zip input stream, reporting if the size exceeds theInternalAssetProperties.getMaxIndividualAssetSize()
.void
removeFile
(String filename) Deprecated, for removal: This API element is subject to removal in a future version.void
removeFile
(String filename, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Remove the provided file from the storage provider.void
setAssetStorageUtils
(AssetStorageUtils assetStorageUtils) protected void
setUploadStatus
(FileUploadState uploadState, BulkAddResourcesResponse bulkAddResourcesResponse) protected File
storeFile
(String url, InputStream fileInputStream, String fileName) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofstoreResource(String, InputStream, String)
protected File
storeMultipartFile
(String url, org.springframework.web.multipart.MultipartFile file, boolean optimizeImg) Deprecated, for removal: This API element is subject to removal in a future version.protected ResourceWithMetadata
storeMultipartFileResource
(String url, org.springframework.web.multipart.MultipartFile file, boolean optimizeImg) protected ResourceWithMetadata
storeResource
(String url, InputStream inputStream, String fileName) void
unzipAndUploadResourcesAsync
(File sourceZipFile, String fileUploadStateId, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg) Deprecated.void
unzipAndUploadResourcesAsync
(File sourceZipFile, String fileUploadStateId, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg, boolean ignoreFolderName) uploadResource
(org.springframework.web.multipart.MultipartFile file, Asset assetRequest, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg) Uploads a single file, creating anAsset
for it (optionally using details specified inassetRequest
if present).validateEntriesInZip
(File sourceZipFile) Reads and validates all of the non-directory (and non-ignored) entries in the given zip file.validateEntry
(ZipEntry entry, ZipInputStream zipInputStream) Reads the entry and validates its mime type and size are acceptable.validateEntryName
(String filename) Validates that the filename of the Zip entry does not contain any path traversals.protected String
validateFileAndCreateUrl
(org.springframework.web.multipart.MultipartFile file, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Validates the uploaded file and creates a URL for it.protected String
validateFileAndCreateUrl
(org.springframework.web.multipart.MultipartFile file, String folderName, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Validates the uploaded file and creates a URL for it.protected void
validateIndividualAssetSize
(long individualSizeInBytes) protected String
validateZipAndReturnErrorMessage
(File sourceZipFile) Validates that the given file does not exceed theInternalAssetProperties.getMaxZipFileSize()
, and validates the individual files inside as described invalidateEntriesInZip(File)
.protected void
validateZipFileSize
(long zipSizeInBytes) void
validateZipResource
(@NonNull org.springframework.web.multipart.MultipartFile file) A simple method intended to be used to pre-validate aMultipartFile
received in an API request when expecting a zip file.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Methods inherited from interface com.broadleafcommerce.asset.service.StorageService
addAttributesToAsset
-
Field Details
-
FAILED_TO_STORE_FILE_ERROR_MESSAGE
- See Also:
-
FILE_UPLOAD_ERROR_MESSAGE
- See Also:
-
MIME_TYPE_NOT_SUPPORTED_FMT
- See Also:
-
ONLY_ZIP_SUPPORTED
- See Also:
-
ZIP_FILENAME_PATH_TRAVERSAL
- See Also:
-
assetService
-
folderService
-
multipartConfigElement
protected final jakarta.servlet.MultipartConfigElement multipartConfigElement -
storageProvider
-
internalAssetProperties
-
typeFactory
protected final com.broadleafcommerce.common.extension.TypeFactory typeFactory -
imageOperationService
-
fileUploadStateService
-
reference
protected final com.broadleafcommerce.common.extension.data.DataRouteReference reference -
assetStorageUtils
-
-
Constructor Details
-
DefaultStorageService
public DefaultStorageService(AssetService<Asset> assetService, FolderService<Folder> folderService, jakarta.servlet.MultipartConfigElement multipartConfigElement, StorageProvider storageProvider, InternalAssetProperties internalAssetProperties, com.broadleafcommerce.common.extension.TypeFactory typeFactory, ImageOperationService imageOperationService, FileUploadStateService<FileUploadState> fileUploadStateService, jakarta.activation.FileTypeMap mimeFileTypeMap, AssetUrlGenerationHelper assetUrlGenerationHelper, com.broadleafcommerce.common.extension.data.DataRouteReference reference)
-
-
Method Details
-
uploadResource
public Asset uploadResource(org.springframework.web.multipart.MultipartFile file, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg) Description copied from interface:StorageService
Uploads a single file, creating anAsset
for it (optionally using details specified inassetRequest
if present).Validation includes:
- File size is within the size limits of `spring.servlet.multipart.max-file-size`
- File is of a supported mime type from `broadleaf.asset.storage.whitelisted-mime-type-formats`
- File path and name does not already exist on a asset within the system
- Specified by:
uploadResource
in interfaceStorageService
- Parameters:
file
- the file to be uploaded to the system.assetRequest
- (optional) asset from which to derive certain attributes when creating the finalAsset
for the file. Currently,Asset.tags
andAsset.locale
are used.contextInfo
- context information around sandboxing and multitenant stateoptimizeImg
- optimizes the image iftrue
- Returns:
- the created asset after the associated resource has been uploaded
-
validateFileAndCreateUrl
protected String validateFileAndCreateUrl(org.springframework.web.multipart.MultipartFile file, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Validates the uploaded file and creates a URL for it.Intended to be overridden if there is some different validation or custom business logic required. For example, if an asset with the same URL already exists, the current implementation increments the file name with an increasing integer, like filename-1.txt. An alternate implementation may want to simply throw
FileUploadBadRequestException
.- Parameters:
file
- the uploaded filecontextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- the created url
- Throws:
org.springframework.web.multipart.MaxUploadSizeExceededException
- if the file is too largeFileUploadBadRequestException
- if the mime type of the file is not supportedIllegalArgumentException
- if the filename is invalid
-
validateFileAndCreateUrl
protected String validateFileAndCreateUrl(org.springframework.web.multipart.MultipartFile file, @Nullable String folderName, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Validates the uploaded file and creates a URL for it.Intended to be overridden if there is some different validation or custom business logic required. For example, if an asset with the same URL already exists, the current implementation increments the file name with an increasing integer, like filename-1.txt. An alternate implementation may want to simply throw
FileUploadBadRequestException
.- Parameters:
file
- the uploaded filefolderName
- the folder name/path for the uploaded filecontextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- the created url
- Throws:
org.springframework.web.multipart.MaxUploadSizeExceededException
- if the file is too largeFileUploadBadRequestException
- if the mime type of the file is not supportedIllegalArgumentException
- if the filename is invalid
-
isWhitelistedMimeType
-
createUniqueUrlFromFilename
protected String createUniqueUrlFromFilename(String filename, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Creates a URL for the given filename. If the URL is found to be in use by another asset, it is suffixed with an incrementing integer value. For example, "/url.txt" becomes "/url-1.txt", and a subsequent creation would become "/url-2.txt".Delegates to
AssetUrlGenerationHelper.createUrl(String, String)
andAssetUrlGenerationHelper.applyIncrementingSuffix(String, ContextInfo)
.- Parameters:
filename
- the filename for which a URL should be created. Does not have to be cleaned/normalized - this method will do that.contextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- a unique URL for the given filename
- Throws:
IllegalArgumentException
- if the filename is invalid
-
createUniqueUrlFromFilename
protected String createUniqueUrlFromFilename(String filename, @Nullable String folderName, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Creates a URL for the given filename. If the URL is found to be in use by another asset, it is suffixed with an incrementing integer value. For example, "/url.txt" becomes "/url-1.txt", and a subsequent creation would become "/url-2.txt".Delegates to
AssetUrlGenerationHelper.createUrl(String, String)
andAssetUrlGenerationHelper.applyIncrementingSuffix(String, ContextInfo)
.- Parameters:
filename
- the filename for which a URL should be created. Does not have to be cleaned/normalized - this method will do that.folderName
- the folder name/path for which an asset's URL will be created withcontextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- a unique URL for the given filename
- Throws:
IllegalArgumentException
- if the filename is invalid
-
validateIndividualAssetSize
protected void validateIndividualAssetSize(long individualSizeInBytes) -
exceedsMaxIndividualAssetSize
protected boolean exceedsMaxIndividualAssetSize(long individualAssetSizeInBytes) -
validateZipFileSize
protected void validateZipFileSize(long zipSizeInBytes) -
exceedsMaxZipFileSize
protected boolean exceedsMaxZipFileSize(long zipSizeInBytes) -
getMimeType
-
getMimeType
-
generateAssetForUploadRequest
protected Asset generateAssetForUploadRequest(@Nullable Asset assetRequest, String mimeType, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Generates a newAsset
object for an upload using the mime type and optional properties provided inassetRequest
.- Parameters:
assetRequest
- (optional) an asset supplied in the original request containing properties that should be copied into the newly createdAsset
mimeType
- the mime type of the file corresponding to this assetcontextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- a new
Asset
object with its fields initialized based upon the given file andassetRequest
- See Also:
-
mapEligibleProperties
Ifsource
is present, will copy itsAsset.getTags()
,Asset.getFolderId()
andAsset.getLocale()
totargetAsset
.- Parameters:
targetAsset
- the asset whose properties should be setsource
- the asset from which properties should be derived
-
unzipAndUploadResourcesAsync
@Deprecated public void unzipAndUploadResourcesAsync(File sourceZipFile, String fileUploadStateId, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg) Deprecated.Description copied from interface:StorageService
Asynchronously upload the individual contents of a zip file to the storage provider, and create all necessaryFolders
andAssets
in the data store for them. This method updates theFileUploadState
with idfileUploadStateId
with the status of upload.Certain validations are done in a way that, if not satisfied, cause the entire contents of the zip to fail to upload. These include:
- The zip file size itself is within
InternalAssetProperties.getMaxZipFileSize()
- Size for every individual extracted file is within
InternalAssetProperties.getMaxIndividualAssetSize()
- Every individual extracted file is of a supported mime type as checked by
StorageProvider.isWhitelistedMimeType(String)
.
- Specified by:
unzipAndUploadResourcesAsync
in interfaceStorageService
- Parameters:
sourceZipFile
- a temporary zip file whose contents should be unzipped and uploaded to the storage provider. This file itself will be deleted following this operation. If the file passes validation andInternalAssetProperties.isStoreZipFileOnProvider()
is true, then a copy of the zip file will be uploaded to the provider.fileUploadStateId
- the context ID of the baseFileUploadState
for this operation. The results of this upload attempt will be updated on this entity.assetRequest
- (optional) asset from which to derive certain attributes when creating the finalAssets
for the files. Currently,Asset.tags
,Asset.locale
, andAsset.folderId
are used. If supplied,Asset.folderId
is used as the root folder under which all other folders/assets will be created.contextInfo
- request context information around sandbox and multitenant stateoptimizeImg
- whether or not to optimize the images
- The zip file size itself is within
-
unzipAndUploadResourcesAsync
@Async("uploadResourcesExecutor") public void unzipAndUploadResourcesAsync(File sourceZipFile, String fileUploadStateId, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg, boolean ignoreFolderName) Description copied from interface:StorageService
Asynchronously upload the individual contents of a zip file to the storage provider, and create all necessaryFolders
andAssets
in the data store for them. This method updates theFileUploadState
with idfileUploadStateId
with the status of upload.Certain validations are done in a way that, if not satisfied, cause the entire contents of the zip to fail to upload. These include:
- The zip file size itself is within
InternalAssetProperties.getMaxZipFileSize()
- Size for every individual extracted file is within
InternalAssetProperties.getMaxIndividualAssetSize()
- Every individual extracted file is of a supported mime type as checked by
StorageProvider.isWhitelistedMimeType(String)
.
- Specified by:
unzipAndUploadResourcesAsync
in interfaceStorageService
- Parameters:
sourceZipFile
- a temporary zip file whose contents should be unzipped and uploaded to the storage provider. This file itself will be deleted following this operation. If the file passes validation andInternalAssetProperties.isStoreZipFileOnProvider()
is true, then a copy of the zip file will be uploaded to the provider.fileUploadStateId
- the context ID of the baseFileUploadState
for this operation. The results of this upload attempt will be updated on this entity.assetRequest
- (optional) asset from which to derive certain attributes when creating the finalAssets
for the files. Currently,Asset.tags
,Asset.locale
, andAsset.folderId
are used. If supplied,Asset.folderId
is used as the root folder under which all other folders/assets will be created.contextInfo
- request context information around sandbox and multitenant stateoptimizeImg
- whether or not to optimize the imagesignoreFolderName
- whether or not to include the parent folder path in the URI resolution of the files within the zip
- The zip file size itself is within
-
validateZipAndReturnErrorMessage
Validates that the given file does not exceed theInternalAssetProperties.getMaxZipFileSize()
, and validates the individual files inside as described invalidateEntriesInZip(File)
.- Returns:
- the error message if there was a validation failure. Will be null if there was no validation failure.
- Throws:
IOException
- if there was an error reading the file
-
buildErrorMessage
protected String buildErrorMessage(@NonNull @NonNull List<DefaultStorageService.ZipEntryValidationError> errors) -
validateEntriesInZip
protected List<DefaultStorageService.ZipEntryValidationError> validateEntriesInZip(File sourceZipFile) throws IOException Reads and validates all of the non-directory (and non-ignored) entries in the given zip file.- Parameters:
sourceZipFile
- the zip file to read- Returns:
- a list of all validation errors that were encountered with entries. Will be empty if no errors were found.
- Throws:
IOException
- if there was an error reading the file- See Also:
-
validateEntryName
@Nullable protected DefaultStorageService.ZipEntryValidationError validateEntryName(String filename) Validates that the filename of the Zip entry does not contain any path traversals.- Parameters:
filename
- the file name of the Zip entry- Returns:
- the validation error if one was detected,
null
otherwise
-
validateEntry
@Nullable protected DefaultStorageService.ZipEntryValidationError validateEntry(ZipEntry entry, ZipInputStream zipInputStream) throws IOException Reads the entry and validates its mime type and size are acceptable.- Parameters:
entry
- basic information about the entry itself. This entry is guaranteed not to be a directory or a resource that should be ignored.zipInputStream
- a zip input stream already positioned at the start of a zip entry's data. Should not be closed by this method.- Returns:
- the validation error if one was detected,
null
otherwise - Throws:
IOException
- if there was an error reading the file
-
readEntryAndReturnIfSizeExceedsLimit
protected boolean readEntryAndReturnIfSizeExceedsLimit(ZipInputStream zipInputStream) throws IOException Reads and counts the byte size of the current entry in the zip input stream, reporting if the size exceeds theInternalAssetProperties.getMaxIndividualAssetSize()
.- Parameters:
zipInputStream
- a zip input stream already positioned at the start of a zip entry's data. Should not be closed by this method.- Returns:
- true if the entry's size exceeds the maximum limit, false otherwise
- Throws:
IOException
- if there was an error reading the file
-
getIndividualAssetTooLargeErrorMessage
-
getZipTooLargeErrorMessage
-
getMimeTypeNotSupportedErrorMessage
-
setUploadStatus
protected void setUploadStatus(FileUploadState uploadState, BulkAddResourcesResponse bulkAddResourcesResponse) -
handleExceptionWithZipFile
protected void handleExceptionWithZipFile(FileUploadState uploadState, String zipFileName, Exception e, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) -
handleFailedValidationWithZipFile
protected void handleFailedValidationWithZipFile(FileUploadState uploadState, String zipFileName, String errorMessage, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) -
validateZipResource
public void validateZipResource(@NonNull @NonNull org.springframework.web.multipart.MultipartFile file) Description copied from interface:StorageService
A simple method intended to be used to pre-validate aMultipartFile
received in an API request when expecting a zip file.While methods like
StorageService.unzipAndUploadResourcesAsync(File, String, Asset, ContextInfo, boolean)
do perform certain validations, this method is intended to allow immediate rejection of invalid requests before getting too far in the flow.Default validations:
- File has an `application/zip` mime type.
- File size is within
InternalAssetProperties.getMaxZipFileSize()
- Specified by:
validateZipResource
in interfaceStorageService
- Parameters:
file
- the file to validate
-
isZipType
-
processZipExtractionResult
@Deprecated protected void processZipExtractionResult(DefaultStorageService.ZipExtractionResult zipExtractionResult, FileUploadState uploadState, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg) Deprecated.Given aDefaultStorageService.ZipExtractionResult
, creates all of the necessaryFolders
in the data store, uploads the extracted files to the storage provider (after optimizing them if necessary), and createsAssets
in the data store for all successfully uploaded files.The
FileUploadState
will be updated in the data store to reflect the final status of the operation.This method guarantees that the
DefaultStorageService.ZipExtractionResult.temporaryDirectoryFilesWereExtractedTo
and all of its contents will be deleted regardless of success or failure.- Parameters:
zipExtractionResult
- an object containing the results of extracting a zip fileuploadState
- theFileUploadState
from the data store corresponding to this zip upload/extract operation. Will be updated and sent to the data store with the final status of this operation.assetRequest
- (optional) the caller-requested asset details from which to derive certain attributes when creating the final assets/folders for the filescontextInfo
- request context information around multitenant stateoptimizeImg
- iftrue
, the extracted files will be optimized before being uploaded to the storage provider
-
processZipExtractionResult
protected void processZipExtractionResult(DefaultStorageService.ZipExtractionResult zipExtractionResult, FileUploadState uploadState, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean optimizeImg, boolean ignoreFolderName) Given aDefaultStorageService.ZipExtractionResult
, creates all of the necessaryFolders
in the data store, uploads the extracted files to the storage provider (after optimizing them if necessary), and createsAssets
in the data store for all successfully uploaded files.The
FileUploadState
will be updated in the data store to reflect the final status of the operation.This method guarantees that the
DefaultStorageService.ZipExtractionResult.temporaryDirectoryFilesWereExtractedTo
and all of its contents will be deleted regardless of success or failure.- Parameters:
zipExtractionResult
- an object containing the results of extracting a zip fileuploadState
- theFileUploadState
from the data store corresponding to this zip upload/extract operation. Will be updated and sent to the data store with the final status of this operation.assetRequest
- (optional) the caller-requested asset details from which to derive certain attributes when creating the final assets/folders for the filescontextInfo
- request context information around multitenant stateoptimizeImg
- iftrue
, the extracted files will be optimized before being uploaded to the storage providerignoreFolderName
- iftrue
, the extracted files' URIs will not contain their parent folder paths
-
createAllFolders
protected Map<String,Folder> createAllFolders(Map<String, Folder> foldersToCreateByNormalizedPath, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, @Nullable Asset assetRequest) Creates all of the givenFolders
in the data store, and returns the created items.This method sets the
Folder.getParentFolderId()
on each folder as determined by the directory paths to mimic the same hierarchy. For top-level folders whose directory paths have no parent, theFolder.getParentFolderId()
will either benull
orAsset.getFolderId()
if provided in theassetRequest
.- Parameters:
foldersToCreateByNormalizedPath
- the map of normalized directory paths toFolder
objects that should be createdcontextInfo
- context information surrounding multitenant stateassetRequest
- the caller-requested asset details- Returns:
- a map from normalized folder names to created
Folder
objects
-
getParentFolderId
@Nullable protected String getParentFolderId(String normalizedPath, Map<String, Folder> createdFoldersByNormalizedPath, @Nullable Asset assetRequest) Gets the parent directory path fromnormalizedPath
, gets theFolder
for that parent directory path increatedFoldersByNormalizedPath
, and returns itsFolder.getId()
.Alternatively, if this path does not have a parent directory and
assetRequest
was supplied, theAsset.getFolderId()
from the request will be used instead. This way any "root level" items will have that folder ID as their parent.- Parameters:
normalizedPath
- the normalized path of the directory or file whose parent folder needs to be determinedcreatedFoldersByNormalizedPath
- a map from normalized directory names to createdFolders
. Used to find the correspondingFolder
for the parent directory path.assetRequest
- the caller-requested asset details- Returns:
- the
Folder.getId()
of theFolder
for the parent directory, ornull
if this item does not have a parent directory
-
getParentDirectoryPath
Gets the parent directory path from the given normalized path.- Parameters:
normalizedPath
- the normalized path of a file or directory. For example, "directory/" or "directory" or "directory/file.txt".- Returns:
- the path for this path's parent directory, or
null
if this path does not have a parent
-
batchOptimizeFiles
Delegates toImageOperationService
to optimize the given files as a batch. The optimization will write over the given files.- Parameters:
filesToOptimizeByNormalizedPath
- a map of normalized file paths to file objects
-
generateContextDiscriminatedUniqueUrls
@Deprecated protected Map<String,String> generateContextDiscriminatedUniqueUrls(Collection<String> filePaths, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Deprecated.Given a collection of file names, generates a unique URL for each with a context-discrimination prefix that's suitable for being supplied to the storage provider.- Parameters:
filePaths
- file names for which context discriminated unique URLs need to be created. Do not have to be cleaned/normalized - this method will do that.contextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- mappings from given file names to the unique urls that were generated for them
-
generateContextDiscriminatedUniqueUrls
protected Map<String,String> generateContextDiscriminatedUniqueUrls(Collection<String> filePaths, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, boolean ignoreFolderName) Given a collection of file names, generates a unique URL for each with a context-discrimination prefix that's suitable for being supplied to the storage provider.- Parameters:
filePaths
- file names for which context discriminated unique URLs need to be created. Do not have to be cleaned/normalized - this method will do that.contextInfo
- context information surrounding sandboxing and multitenant stateignoreFolderName
- iftrue
, the generated URIs for the given file paths will not include their parent folder paths- Returns:
- mappings from given file names to the unique urls that were generated for them
-
generateContextDiscriminatedUniqueUrl
protected String generateContextDiscriminatedUniqueUrl(String filePath, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Given a file path, generate a unique URL with a context-discrimination prefix that's suitable for being supplied to the storage provider.- Parameters:
filePath
- a file name for which a context discriminated unique URL needs to be created. Does not have to be cleaned/normalized - this method will do that.contextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- a unique context discriminated URL that was generated for the given path
-
generateContextDiscriminatedUniqueUrl
protected String generateContextDiscriminatedUniqueUrl(String filePath, @Nullable String folderName, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Given a file path, generate a unique URL with a context-discrimination prefix that's suitable for being supplied to the storage provider.- Parameters:
filePath
- a file name for which a context discriminated unique URL needs to be created. Does not have to be cleaned/normalized - this method will do that.folderName
- the folder name/path of the file used to create the unique URLcontextInfo
- context information surrounding sandboxing and multitenant state- Returns:
- a unique context discriminated URL that was generated for the given path
-
createAssetsForSuccessfullyUploadedFiles
protected List<Asset> createAssetsForSuccessfullyUploadedFiles(DefaultStorageService.ZipExtractionResult zipExtractionResult, Map<String, String> contextDiscriminatedUrlsByNormalizedPath, Map<String, Folder> createdFoldersByNormalizedPath, BulkAddResourcesResponse addResourcesResponse, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) CreatesAssets
in the data store for the files that were successfully uploaded to the storage provider. This method takesBulkAddResourcesResponse.getGivenFilenamesToSuccessfullyCreatedPaths()
, maps those back to the originally extracted files fromDefaultStorageService.ZipExtractionResult.getFilesByNormalizedPath()
, and then builds/inserts the assets in the data store.- Parameters:
zipExtractionResult
- an object containing the results of extracting the original zip filecontextDiscriminatedUrlsByNormalizedPath
- mappings from the original normalized path names of files to the unique urls that were generated for them. Keys should correspond to keys inDefaultStorageService.ZipExtractionResult.getFilesByNormalizedPath()
, and values should correspond to keys inBulkAddResourcesResponse.getGivenFilenamesToSuccessfullyCreatedPaths()
.createdFoldersByNormalizedPath
- a map from normalized directory names to createdFolders
. Used to find the correspondingFolder
for the parent directory path of a file's normalized path.addResourcesResponse
- the response returned by the storage provider describing which file uploads succeeded and which failedassetRequest
- (optional) the caller-requested asset details from which to derive certain attributes when creating the final assets for the files.contextInfo
- context information surrounding multitenant state- Returns:
- the list of all assets that were created in the data store. Will not be null, but may be empty if there were no successfully uploaded files.
-
generateAssetsForFiles
protected List<Asset> generateAssetsForFiles(Stream<Map.Entry<String, File>> filesByNormalizedPath, Map<String, String> contextDiscriminatedUrlsByNormalizedPath, Map<String, Folder> createdFoldersByNormalizedPath, @Nullable Asset assetRequest, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) -
getFailedNormalizedFilePaths
protected Set<String> getFailedNormalizedFilePaths(DefaultStorageService.ZipExtractionResult zipExtractionResult, BulkAddResourcesResponse addResourcesResponse, Map<String, String> contextDiscriminatedUrlsByNormalizedPath) -
storeMultipartFile
@Deprecated(since="2.0.1", forRemoval=true) protected File storeMultipartFile(String url, org.springframework.web.multipart.MultipartFile file, boolean optimizeImg) Deprecated, for removal: This API element is subject to removal in a future version. -
storeMultipartFileResource
protected ResourceWithMetadata storeMultipartFileResource(String url, org.springframework.web.multipart.MultipartFile file, boolean optimizeImg) -
storeFile
@Deprecated(since="2.0.1", forRemoval=true) protected File storeFile(String url, InputStream fileInputStream, String fileName) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofstoreResource(String, InputStream, String)
-
storeResource
-
removeFile
Deprecated, for removal: This API element is subject to removal in a future version.Description copied from interface:StorageService
Remove the provided file from the storage provider.- Specified by:
removeFile
in interfaceStorageService
- Parameters:
filename
- the name of the file to delete on the storage provider
-
removeFile
public void removeFile(String filename, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Description copied from interface:StorageService
Remove the provided file from the storage provider.- Specified by:
removeFile
in interfaceStorageService
- Parameters:
filename
- the name of the file to delete on the storage providercontextInfo
- context of the request: information around sandbox and multitenant state
-
extractZip
protected DefaultStorageService.ZipExtractionResult extractZip(File zipFile, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) throws IOException Extracts the contents of the zip file to a temporary directory, building anyFolder
objects for directories and creating temporaryfiles
for extracted files.This method guarantees that the temporary extraction directory and its contents will be wiped if an error is encountered.
- Parameters:
zipFile
- The zip file to extractcontextInfo
- context information surrounding multitenant state- Returns:
- details about the extracted folders and files
- Throws:
IOException
- if there was an IO problem extracting the file.
-
matchesAnyResourceNameToIgnore
-
buildFolderAndPutInMap
protected void buildFolderAndPutInMap(String directoryPath, Map<String, Folder> foldersByNormalizedPath, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo) Given a directory path that was found in a zip file, build aFolder
for it and put it in the givenfoldersByPath
map.The path of the directory is first cleaned and normalized. This is used as the key for
foldersByPath
.The last segment of the normalized path is then set as the
Folder.getName()
.This method does not initialize
Folder.getParentFolderId()
, as that is done in a later step increateAllFolders(Map, ContextInfo, Asset)
when the entities are created.- Parameters:
directoryPath
- the full name of the directory (with path information) as found in the zip entryfoldersByNormalizedPath
- a map of normalized folder names toFolder
objects (as described inDefaultStorageService.ZipExtractionResult.getFoldersByNormalizedPath()
) which the new folder should be placed incontextInfo
- context information surrounding multitenant state
-
extractToFileAndPutInMap
protected void extractToFileAndPutInMap(String entryPath, Path tempDirectoryForExtraction, ZipInputStream zipInputStream, Map<String, File> filesByNormalizedPath) throws IOExceptionCreates a new file inside oftempDirectoryForExtraction
, extracts the current zip entry's data to it viaextractCurrentEntryToFile(ZipInputStream, File)
, and then puts the appropriate mapping infilesByPath
.The path of the zip entry is first cleaned and normalized, and then used as the key for
filesByPath
.- Parameters:
entryPath
- the original name of the zip entrytempDirectoryForExtraction
- the temporary directory in which to write the extracted filezipInputStream
- a zip input stream already positioned at the start of a zip entry's data. Should not be closed by this method.filesByNormalizedPath
- a map of normalized file names toFile
objects (as described inDefaultStorageService.ZipExtractionResult.getFilesByNormalizedPath()
) which the extracted file should be placed in- Throws:
IOException
- if there was an error reading/writing data
-
extractCurrentEntryToFile
protected void extractCurrentEntryToFile(ZipInputStream zipInputStream, File extractionTarget) throws IOException Reads the current zip entry's data and writes it to theextractionTarget
.- Parameters:
zipInputStream
- a zip input stream already positioned at the start of a zip entry's data. Should not be closed by this method.extractionTarget
- the file to which the zip entry's data should be written- Throws:
IOException
- if there was an error reading/writing the data
-
addAttributesToAsset
Responsible for adding any attributes to the asset that are derived from the uploaded file.- Specified by:
addAttributesToAsset
in interfaceStorageService
- Parameters:
asset
- the asset to which to add attributesfile
- the file from which to derive attributes
-
addImageAttributes
-
addAttributesToAsset
public void addAttributesToAsset(@NonNull @NonNull Asset asset, @NonNull @NonNull ResourceWithMetadata resource) Responsible for adding any attributes to the asset that are derived from the uploadedResource
.- Specified by:
addAttributesToAsset
in interfaceStorageService
- Parameters:
asset
- the asset to which to add attributesresource
- theResourceWithMetadata
from which to derive attributes
-
getAssetDimensions
Gets dimensions for given asset file- Parameters:
assetFile
- asset file- Returns:
- dimensions of the asset, null if no dimensions found
- Since:
- 2.1.3
-
getAssetDimensions
protected Optional<Dimension> getAssetDimensions(@NonNull @NonNull ResourceWithMetadata videoResource) Gets dimensions for given assetResourceWithMetadata
- Parameters:
videoResource
- an assetResourceWithMetadata
- Returns:
- dimensions of the asset or
Optional.empty()
if no dimensions found - Since:
- 2.1.3
-
getImageDimensions
@Deprecated(since="2.1.3", forRemoval=true) protected Optional<Dimension> getImageDimensions(@NonNull @NonNull File assetFile) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofgetAssetDimensions(InputStream)
Gets image dimensions for given asset file- Parameters:
assetFile
- asset file- Returns:
- dimensions of image, null if not an image
-
getImageDimensions
@Deprecated(since="2.1.3", forRemoval=true) protected Optional<Dimension> getImageDimensions(@NonNull @NonNull ResourceWithMetadata imageResource) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofgetAssetDimensions(ResourceWithMetadata)
Gets image dimensions for given assetResourceWithMetadata
- Parameters:
imageResource
- an assetResourceWithMetadata
- Returns:
- dimensions of image or
Optional.empty()
if not an image
-
getImageDimensions
@Deprecated(since="2.1.3", forRemoval=true) protected Optional<Dimension> getImageDimensions(@NonNull @NonNull ImageInputStream imageInputStream) Deprecated, for removal: This API element is subject to removal in a future version.in favor ofgetAssetDimensions(InputStream)
Gets image dimensions for given assetImageInputStream
- Parameters:
imageInputStream
- an assetImageInputStream
- Returns:
- dimensions of image or
Optional.empty()
if not an image
-
getAssetDimensions
Gets dimensions for given assetInputStream
- Parameters:
fileInputStream
- an assetInputStream
- Returns:
- dimensions of the asset or
Optional.empty()
if no dimensions found - Since:
- 2.1.3
-
getMimeFileTypeMap
@NonNull protected jakarta.activation.FileTypeMap getMimeFileTypeMap() -
getAssetUrlGenerationHelper
-
getAssetStorageUtils
-
setAssetStorageUtils
-
getAssetDimensions(ResourceWithMetadata)