Velocity:
DataProviderAPI api = proxyServer.getPluginManager()
.getPlugin("dataprovider")
.flatMap(container -> container.getInstance()
.filter(DataProviderApiSupplier.class::isInstance)
.map(DataProviderApiSupplier.class::cast)
.map(DataProviderApiSupplier::dataProviderApi))
.orElseThrow(() -> new IllegalStateException("DataProvider is unavailable."));Bukkit/Paper:
RegisteredServiceProvider<DataProviderAPI> registration =
Bukkit.getServicesManager().getRegistration(DataProviderAPI.class);
if (registration == null) {
throw new IllegalStateException("DataProvider is unavailable.");
}
DataProviderAPI api = registration.getProvider();Caller identity is resolved automatically from the plugin runtime context.
Treat DataProviderAPI as runtime-scoped, not permanent.
- Acquire the API during your plugin enable/start phase.
- Do not keep API references across plugin reloads or disable/enable cycles.
- After DataProvider shuts down, old API handles throw
IllegalStateException; reacquire a fresh API after DataProvider is enabled again.
DataProvider ships with runtime diagnostics commands for Bukkit/Paper and Velocity:
/dataprovider status [summary|connections] [unhealthy] [plugin <name>] [type <databaseType>]/dataprovider config/dataprovider reload
Permission nodes:
dataprovider.command.statusdataprovider.command.configdataprovider.command.reload
Basic:
DatabaseProvider provider = api.registerDatabase(DatabaseType.MYSQL, "example");
if (provider == null || !provider.isConnected()) {
// handle unavailable database
}Optional style:
Optional<DatabaseProvider> provider = api.registerDatabaseOptional(DatabaseType.MYSQL, "example");Typed provider style:
Optional<RelationalDatabaseProvider> relational = api.registerDatabaseAs(
DatabaseType.MYSQL,
"example",
RelationalDatabaseProvider.class
);Typed data access style:
Optional<MessagingDataAccess> redisBus = api.registerDataAccess(
DatabaseType.REDIS_MESSAGING,
"default",
MessagingDataAccess.class
);Identifier guidance:
- Prefer
defaultfor single-connection setups. - Use explicit names like
examplefor relational read/write paths.
DatabaseProvider is a read-only handle. Connection lifecycle stays owned by DataProviderAPI,
so acquire and release connections through registerDatabase* / unregisterDatabase*.
DatabaseProvider has helper methods to avoid raw casts:
Optional<MessagingDataAccess> bus = provider.getDataAccessOptional(MessagingDataAccess.class);
Optional<DataSource> dataSource = provider.getDataSourceOptional();Release a specific connection:
api.unregisterDatabase(DatabaseType.MYSQL, "example");Release all connections for your default plugin/software scope:
api.unregisterAllDatabases();For full plugin/software shutdown when registrations may come from multiple classes/scopes:
api.unregisterAllDatabasesForPlugin();Optional advanced scoped ownership is documented in docs/SCOPED_LIFECYCLE.md.
For relational providers:
ORMContext orm = new ORMContext(
"my-plugin",
dataSource,
loggerAdapter,
"validate",
PlayerEntity.class
);