Plugin Lifecycle Management

TrustWeave lets your own integrations implement PluginLifecycle when they need explicit startup/shutdown hooks (connections, background work, etc.).

Important: The TrustWeave facade does not expose initialize() / start() / stop() / cleanup(). Normal apps use TrustWeave.build { } / TrustWeave.quickStart() and handle errors via sealed results and domain exceptions. The sections below describe PluginLifecycle on custom components, not methods on TrustWeave.

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.build setups

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
}
  • Error Handling](error-handling.md)
  • Service Provider Interface](spi.md)
  • API Reference](../api-reference/)

This site uses Just the Docs, a documentation theme for Jekyll.