Plugin Lifecycle Management
TrustWeave lets your own integrations implement PluginLifecycle when they need explicit startup/shutdown hooks (connections, background work, etc.).
Important: The
TrustWeavefacade does not exposeinitialize()/start()/stop()/cleanup(). Normal apps useTrustWeave.build { }/TrustWeave.quickStart()and handle errors via sealed results and domain exceptions. The sections below describePluginLifecycleon custom components, not methods onTrustWeave.
Overview
Plugins that implement PluginLifecycle can be initialized, started, stopped, and cleaned up by your application (or a host container). This is useful for components that need to:
- Initialize connections or resources
- Start background processes
- Clean up resources on shutdown
- Manage plugin state
When Do You Need Lifecycle Methods?
You typically DON’T need lifecycle methods for:
- In-memory implementations (
InMemoryKeyManagementService, in-memory wallets, etc.) - Simple test scenarios and quick starts
- Most default
TrustWeave.quickStart()/TrustWeave.buildsetups
You DO need lifecycle methods when:
- Database-backed services (connection pools, migrations)
- Remote services (opening clients before first use)
- File-based storage (creating directories, locks)
- Long-lived blockchain or KMS adapters that need explicit connect/disconnect
- Any component that must release resources on shutdown
Example - When Lifecycle is Needed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Database-backed wallet factory needs initialization
class DatabaseWalletFactory : WalletFactory, PluginLifecycle {
private var connection: Connection? = null
override suspend fun initialize(config: Map<String, Any?>): Boolean {
val url = config["databaseUrl"] as? String ?: return false
connection = DriverManager.getConnection(url)
return true
}
override suspend fun start(): Boolean {
// Start connection pool, background threads, etc.
return connection != null
}
override suspend fun stop(): Boolean {
// Stop background processes
return true
}
override suspend fun cleanup() {
connection?.close()
connection = null
}
// ... implement WalletFactory methods ...
}
Example - When Lifecycle is NOT Needed:
1
2
3
// In-memory TrustWeave — no PluginLifecycle calls required
val trustWeave = TrustWeave.quickStart()
val did = trustWeave.createDid { }.getOrThrowDid()
Plugin Lifecycle Interface
1
2
3
4
5
6
interface PluginLifecycle {
suspend fun initialize(config: Map<String, Any?>): Boolean
suspend fun start(): Boolean
suspend fun stop(): Boolean
suspend fun cleanup()
}
Lifecycle Methods
Initialize (on your PluginLifecycle component)
Call initialize on your plugin instance (wallet factory, remote adapter, etc.), not on TrustWeave:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val config = mapOf(
"database" to mapOf(
"url" to "jdbc:postgresql://localhost/TrustWeave",
"username" to "TrustWeave",
"password" to "secret"
),
"cache" to mapOf(
"enabled" to true,
"ttl" to 3600
)
)
if (!myDatabaseBackedPlugin.initialize(config)) {
error("Plugin failed to initialize")
}
Start / stop / cleanup
Likewise, invoke start(), stop(), and cleanup() on implementations that need them (e.g. long-lived connections). The stock TrustWeave facade has no global TrustWeave.start() API.
Complete lifecycle example (custom plugin + facade)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.trustweave.testkit.services.*
import org.trustweave.trust.TrustWeave
import org.trustweave.trust.dsl.credential.*
import org.trustweave.trust.types.getOrThrowDid
suspend fun main() {
val dbPlugin = MyDatabaseBackedPlugin() // implements PluginLifecycle
dbPlugin.initialize(mapOf("databaseUrl" to "jdbc:postgresql://localhost/app"))
dbPlugin.start()
try {
val trustWeave = TrustWeave.build {
keys { provider(IN_MEMORY); algorithm(ED25519) }
did { method(KEY) { algorithm(ED25519) } }
}
val did = trustWeave.createDid { }.getOrThrowDid()
println("Created DID: ${did.value}")
} finally {
dbPlugin.stop()
dbPlugin.cleanup()
}
}
Implementing PluginLifecycle
To implement lifecycle management in your plugin:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import org.trustweave.core.plugin.PluginLifecycle
class MyBlockchainClient : BlockchainAnchorClient, PluginLifecycle {
private var initialized = false
private var started = false
private var connection: Connection? = null
override suspend fun initialize(config: Map<String, Any?>): Boolean {
return try {
val url = config["url"] as? String ?: return false
connection = createConnection(url)
initialized = true
true
} catch (e: Exception) {
false
}
}
override suspend fun start(): Boolean {
return if (initialized && connection != null) {
connection?.connect()
started = true
true
} else {
false
}
}
override suspend fun stop(): Boolean {
return try {
connection?.disconnect()
started = false
true
} catch (e: Exception) {
false
}
}
override suspend fun cleanup() {
connection?.close()
connection = null
initialized = false
}
// ... implement BlockchainAnchorClient methods ...
}
Automatic Plugin Discovery
TrustWeave automatically discovers plugins that implement PluginLifecycle from:
- Key Management Services (KMS)
- Wallet Factories
- DID Methods
- Blockchain Clients
- Credential Services
- Proof Generators
Plugins are initialized in the order they are registered, and stopped in reverse order.
Error Handling
Lifecycle methods return Result<Unit> for error handling:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val result = TrustWeave.initialize()
result.fold(
onSuccess = {
println("Initialization successful")
},
onFailure = { error ->
when (error) {
is PluginException.InitializationFailed -> {
println("Plugin ${error.pluginId} failed: ${error.reason}")
// Handle specific plugin failure
}
else -> {
println("Initialization error: ${error.message}")
}
}
}
)
Best Practices
1. Initialize your PluginLifecycle components before use
1
2
3
val plugin = MyRemoteAnchorClient()
check(plugin.initialize(configMap)) { "plugin init failed" }
plugin.start()
2. Use try/finally for cleanup
1
2
3
4
5
6
7
8
9
10
val plugin = MyRemoteAnchorClient()
plugin.initialize(emptyMap())
plugin.start()
try {
val trustWeave = TrustWeave.build { /* uses plugin via registry if registered */ }
// ...
} finally {
plugin.stop()
plugin.cleanup()
}
3. Surface failures clearly
Return false or throw PluginException.InitializationFailed from registration paths so callers do not proceed with half-initialized dependencies.
4. Implement lifecycle methods safely
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
override suspend fun initialize(config: Map<String, Any?>): Boolean {
return try {
// Initialize resources
// Return true on success, false on failure
true
} catch (e: Exception) {
false
}
}
override suspend fun start(): Boolean {
// Start services
// Return true on success, false on failure
return true
}
override suspend fun stop(): Boolean {
// Stop services
// Return true on success, false on failure
return true
}
override suspend fun cleanup() {
// Cleanup resources
// Don't throw exceptions
}
Related Documentation
- Error Handling](error-handling.md)
- Service Provider Interface](spi.md)
- API Reference](../api-reference/)