ECM Storage - Azure Blob¶
Implement ECM document-content storage against Azure Blob Storage.
Configure the container and one of the adapter credential modes, then select the Azure ECM adapter. Ensure the account/container exists and validate permissions for both reads and writes.
| Maven artifact | Packaging | Source project |
|---|---|---|
org.fireflyframework:fireflyframework-ecm-storage-azure |
jar |
modules/ecm-storage-azure |
Part of Domain and data.
In the onboarding service¶
Store an applicant's supporting document in Azure Blob Storage through the ECM content port. Provision the storage resource and credentials, and keep the application's document/access metadata under its own policy.
Add the component¶
Installation and version availability explains source builds and published releases.
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-ecm-storage-azure</artifactId>
<version>26.10.20-SNAPSHOT</version>
</dependency>
Quick start¶
The Java examples in this section are API fragments for application code. Use the stated imports and supply the application-owned collaborators described alongside them.
- Add the dependency (see Installation) and select this adapter via the
firefly.ecm.adapter-typeproperty:
firefly:
ecm:
enabled: true
adapter-type: azure-blob # selects this module
adapter:
azure-blob:
account-name: ${AZURE_ACCOUNT_NAME}
container-name: documents
connection-string: ${AZURE_CONNECTION_STRING} # or account-key / sas-token / managed-identity
- Inject the ECM
DocumentContentPort. The Azure adapter is wired in automatically; your code depends only on the core port:
import org.fireflyframework.ecm.port.document.DocumentContentPort;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.UUID;
@Service
public class DocumentService {
private final DocumentContentPort content;
public DocumentService(DocumentContentPort content) {
this.content = content; // AzureBlobDocumentContentAdapter at runtime
}
public Mono<String> upload(UUID documentId, byte[] bytes, String mimeType) {
// returns the storage path of the stored blob
return content.storeContent(documentId, bytes, mimeType);
}
public Mono<byte[]> download(UUID documentId) {
return content.getContent(documentId);
}
}
That is all. Switching to a different backend (e.g. Amazon S3) is a matter of swapping the dependency and setting firefly.ecm.adapter-type accordingly, with no change to DocumentService.
Configuration and wiring¶
The firefly.ecm.adapter.azure-blob namespace is bound by AzureBlobAdapterProperties.java. Nested configuration is declared in the linked class. Defaults are the field initializers.
| Setting | Java type | Source default |
|---|---|---|
firefly.ecm.adapter.azure-blob.account-name |
String |
not initialized |
firefly.ecm.adapter.azure-blob.container-name |
String |
not initialized |
firefly.ecm.adapter.azure-blob.account-key |
String |
not initialized |
firefly.ecm.adapter.azure-blob.connection-string |
String |
not initialized |
firefly.ecm.adapter.azure-blob.sas-token |
String |
not initialized |
firefly.ecm.adapter.azure-blob.managed-identity |
Boolean |
false |
firefly.ecm.adapter.azure-blob.endpoint |
String |
not initialized |
firefly.ecm.adapter.azure-blob.path-prefix |
String |
"documents/" |
firefly.ecm.adapter.azure-blob.enable-versioning |
Boolean |
true |
firefly.ecm.adapter.azure-blob.access-tier |
String |
"Hot" |
firefly.ecm.adapter.azure-blob.max-retries |
Integer |
3 |
firefly.ecm.adapter.azure-blob.timeout-seconds |
Integer |
30 |
firefly.ecm.adapter.azure-blob.block-size |
Long |
4194304L |
firefly.ecm.adapter.azure-blob.block-upload-threshold |
Long |
268435456L |
Property-based wiring conditions found in this module:
name = "firefly.ecm.adapter-type", havingValue = "azure-blob". AzureBlobAutoConfiguration.java.name = "firefly.ecm.adapter-type", havingValue = "azure-blob". AzureBlobDocumentContentAdapter.java.
Public API and extension points¶
| Type | Contract and responsibility |
|---|---|
AzureBlobDocumentContentAdapter |
Defines AzureBlobDocumentContentAdapter, storeContent, storeContentStream, deleteContent operations. |
AzureBlobAdapterProperties |
Configuration properties for the Microsoft Azure Blob Storage ECM adapter. |
AzureBlobAutoConfiguration |
Defines blobServiceClient, blobContainerClient, objectMapper, azureBlobCircuitBreaker operations. |
Related components¶
| Related component | Why it belongs nearby |
|---|---|
| Enterprise Content Management Library | Define content-management ports, adapter selection, document contracts, and resilience/observability support. |
Build and test¶
Use Java 25. From the repository root, build this component with its required dependencies:
git clone https://github.com/fireflyframework/fireflyframework-jafly.git
cd fireflyframework-jafly
./mvnw -pl :fireflyframework-ecm-storage-azure -am verify
./mvnw -pl :fireflyframework-ecm-storage-azure -am install
verify runs the selected projects' tests. install makes the current build available in your local Maven repository.
Representative test sources:
Mock, local-container, and application-context tests do not establish acceptance against a live provider account. Validate the intended provider deployment and credentials separately.
API reference excerpt¶
Contract excerpt from AzureBlobDocumentContentAdapter.java. This fragment needs the full type and its imports.
public class AzureBlobDocumentContentAdapter implements DocumentContentPort {
private final BlobContainerClient containerClient;
private final AzureBlobAdapterProperties properties;
private final DataBufferFactory dataBufferFactory;
private final CircuitBreaker circuitBreaker;
private final Retry retry;
public AzureBlobDocumentContentAdapter(BlobContainerClient containerClient,
AzureBlobAdapterProperties properties,
this.containerClient = containerClient;
this.properties = properties;
this.dataBufferFactory = new DefaultDataBufferFactory();
this.circuitBreaker = circuitBreaker;
this.retry = retry;
log.info("AzureBlobDocumentContentAdapter initialized with container: {}, prefix: {}, resilience enabled",
properties.getContainerName(), properties.getPathPrefix());
}
public Flux<DataBuffer> getContentStream(UUID documentId) {
return Mono.fromCallable(() -> {
String blobName = buildContentBlobName(documentId);
BlobClient blobClient = containerClient.getBlobClient(blobName);
if (!blobClient.exists()) {
throw new RuntimeException("Content not found for document: " + documentId);
}
return blobClient.openInputStream();
Detailed reference¶
Configuration¶
All properties live under the firefly.ecm.adapter.azure-blob prefix and are bound by AzureBlobAdapterProperties. The adapter activates only when firefly.ecm.adapter-type=azure-blob.
firefly:
ecm:
enabled: true
adapter-type: azure-blob
adapter:
azure-blob:
account-name: ${AZURE_ACCOUNT_NAME} # required
container-name: documents # required
# --- one authentication option ---
account-key: ${AZURE_ACCOUNT_KEY} # account name + key
connection-string: ${AZURE_CONNECTION_STRING} # full connection string
sas-token: ${AZURE_SAS_TOKEN} # shared access signature
managed-identity: false # use Azure AD / DefaultAzureCredential
# --- endpoint & layout ---
endpoint: # custom/sovereign cloud endpoint (default: https://<account>.blob.core.windows.net)
path-prefix: documents/ # blob key prefix
# --- upload tuning ---
block-size: 4194304 # 4 MB stream buffer / block size
block-upload-threshold: 268435456 # 256 MB: switch to block-blob upload above this
# --- resilience ---
max-retries: 3 # 0..10, drives the Resilience4j Retry
timeout-seconds: 30 # 1..300
# --- storage policy (account/container-level intent) ---
access-tier: Hot # Hot | Cool | Archive
enable-versioning: true
enable-encryption: true
encryption-key-url: # customer-managed key (Key Vault) URL
enable-soft-delete: true
soft-delete-retention-days: 7 # 1..365
Key properties:
| Property | Default | Description |
|---|---|---|
account-name |
(required) | Azure Storage account name. |
container-name |
(required) | Blob container for document content; auto-created if missing. |
connection-string / account-key / sas-token / managed-identity |
, /, /, / false |
Authentication options, tried in this order; at least one must be supplied. |
endpoint |
https://<account>.blob.core.windows.net |
Override for sovereign/custom endpoints. |
path-prefix |
documents/ |
Prefix for blob names; final key is {path-prefix}{documentId}.content. |
block-size |
4194304 (4 MB) |
Buffer/block size used for streaming reads and writes. Min 1024. |
block-upload-threshold |
268435456 (256 MB) |
Content larger than this is uploaded via block blobs. Min 1024. |
max-retries |
3 |
Retry attempts for the azureBlobRetry Resilience4j instance. Range 0-10. |
timeout-seconds |
30 |
Operation timeout hint. Range 1-300. |
access-tier |
Hot |
Intended blob access tier. |
enable-versioning / enable-soft-delete / soft-delete-retention-days |
true / true / 7 |
Data-protection intent; soft-delete retention range 1-365 days. |
enable-encryption / encryption-key-url |
true /, |
Encryption-at-rest intent and optional customer-managed key URL. |
A ready-to-copy profile is bundled at src/main/resources/application-azure-blob.yml.
Continue the application¶
Use the Enterprise Content Management guide for the next part of this integration. The runnable submission/query service is in Getting started.