kevdoran commented on PR #10909:
URL: https://github.com/apache/nifi/pull/10909#issuecomment-3922819219

   Thanks for the feedback @bbende @markap14. Here is a revised approach that 
makes the complexity of asset synchronization and internal/external asset id 
mapping the responsibility of the provider rather than the nifi framework.
   
   ## Summary
   
   Extends the `ConnectorConfigurationProvider` extension point to support 
externally managed connector assets (binary files such as JDBC drivers and SSL 
certificates).
   
   ### Design Principle
   
   The provider owns everything: asset storage, the mapping between NiFi asset 
UUIDs and external identifiers, digest tracking for change detection, and 
rollback on failure. The framework's `StandardConnectorRepository` operates 
exclusively in NiFi UUID space and never knows what an external identifier is.
   
   ### Architecture
   
   ```mermaid
   graph TB
       subgraph rest[REST / DAO Layer]
           DAO["StandardConnectorDAO"]
       end
   
       subgraph repo[Repository Layer]
           REPO["StandardConnectorRepository\n(no ID translation)"]
       end
   
       subgraph local[Local Asset Storage]
           CAM["StandardConnectorAssetManager\n(ID-based paths, random UUIDs)"]
       end
   
       subgraph provider[Provider Extension]
           CCP["ConnectorConfigurationProvider\n(owns external ID mapping + 
digests)"]
           EXT["External Store"]
       end
   
       DAO -->|"storeAsset / getAsset\ndeleteAssets / syncAssetsFromProvider"| 
REPO
       REPO -->|"storeAsset(nifiUuid)\ndeleteAsset(nifiUuid)\nsyncAssets() / 
load()"| CCP
       REPO --> CAM
       CCP --> EXT
       CCP -->|"createAsset / saveAsset"| CAM
   ```
   
   ### Asset Upload Flow
   
   ```mermaid
   sequenceDiagram
       participant DAO as StandardConnectorDAO
       participant REPO as StandardConnectorRepository
       participant CCP as ConnectorConfigurationProvider
       participant CAM as StandardConnectorAssetManager
   
       DAO->>REPO: storeAsset(connectorId, nifiUuid, name, stream)
       REPO->>CCP: storeAsset(connectorId, nifiUuid, name, stream)
       CCP->>CAM: saveAsset(connectorId, nifiUuid, name, stream)
       Note over CAM: Streams to disk at\n{connectorId}/{nifiUuid}/{name}
       CCP->>CCP: open FileInputStream from saved file
       CCP->>EXT: upload stream to external store
       CCP->>CCP: persist nifiUuid ↔ externalId mapping\nto local state file
       REPO->>CAM: getAsset(nifiUuid)
       CAM-->>REPO: Asset
       REPO-->>DAO: Asset
   ```
   
   ### On-Demand Asset Sync (applyUpdate / verifyConfigurationStep)
   
   ```mermaid
   sequenceDiagram
       participant REPO as StandardConnectorRepository
       participant CCP as ConnectorConfigurationProvider
       participant CAM as StandardConnectorAssetManager
       participant EXT as External Store
   
       REPO->>CCP: syncAssets(connectorId)
       CCP->>EXT: LIST assets/ → current digests
       loop for each asset in local mapping
           alt digest changed or file missing
               CCP->>EXT: stream binary from external store
               CCP->>CAM: createAsset(connectorId, name, stream) → new UUID
               CCP->>CAM: deleteAsset(oldUuid)
               CCP->>CCP: update local mapping\n(new UUID + new digest)
           end
       end
       REPO->>CCP: load(connectorId)
       Note over CCP: Translates external IDs → NiFi UUIDs\nusing updated local 
mapping
       CCP-->>REPO: ConnectorWorkingConfiguration\n(NiFi UUIDs in assetIds)
       REPO->>REPO: apply updated config\nto working context
   ```
   
   ### Changes
   
   **`nifi-framework-api`**
   - `ConnectorConfigurationProvider` — three new abstract methods: 
`storeAsset(connectorId, nifiUuid, name, content)`, `deleteAsset(connectorId, 
nifiUuid)`, `syncAssets(connectorId)`
   - `ConnectorConfigurationProviderInitializationContext` — adds 
`getAssetManager()` so providers can perform local asset I/O
   - `ConnectorWorkingConfiguration` — stays as `name` + 
`workingFlowConfiguration` only; asset ID mapping is a provider-internal concern
   
   **`nifi-framework-core`**
   - `StandardConnectorRepository` — asset methods delegate to the provider; 
`syncAssetsFromProvider()` calls `provider.syncAssets()` then reloads via 
`provider.load()`; `applyUpdate()` syncs assets before transitioning state; all 
ID translation maps and methods removed
   - `ConnectorAssetRepository` / `StandardConnectorAssetRepository` — 
**deleted**; `StandardConnectorRepository` holds `AssetManager` directly
   - `StandardConnectorConfigurationProviderInitializationContext` — wires in 
the `AssetManager`
   - `FlowController` — passes `connectorAssetManager` to the provider 
initialization context
   
   **`nifi-web-api`**
   - `StandardConnectorDAO` — asset operations route through 
`ConnectorRepository`; `syncAssetsFromProvider` called before 
`verifyConfigurationStep`
   - `DtoFactory` / `WebApplicationConfiguration` — use `ConnectorRepository` 
directly for asset name lookup
   
   ### Key Invariant
   
   > **No steady-state code path overwrites an existing asset UUID's file.** 
`StandardConnectorAssetManager` uses ID-based file paths 
(`{storageDir}/{connectorId}/{assetId}/{name}`) with random UUIDs, so active 
and working contexts can reference the same logical asset (same filename) as 
separate files under different UUIDs without collision.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to