or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bundles.mdcli.mdcore-application.mdenvironment-setup.mdindex.mdserver-config.md

bundles.mddocs/

0

# Bundle System

1

2

Dropwizard's bundle system provides reusable application components that can be registered during bootstrap to add functionality like SSL certificate reloading, asset serving, database migrations, and more.

3

4

## Capabilities

5

6

### ConfiguredBundle Interface

7

8

Base interface for creating reusable application components that can access configuration and modify the application environment.

9

10

```java { .api }

11

/**

12

* A reusable bundle of functionality, used to define blocks of application behavior

13

* that are conditional on configuration parameters.

14

* @param <T> the required configuration interface

15

*/

16

public interface ConfiguredBundle<T> {

17

/**

18

* Initializes the environment.

19

* @param configuration the configuration object

20

* @param environment the application's Environment

21

* @throws Exception if something goes wrong

22

*/

23

default void run(T configuration, Environment environment) throws Exception;

24

25

/**

26

* Initializes the application bootstrap.

27

* @param bootstrap the application bootstrap

28

*/

29

default void initialize(Bootstrap<?> bootstrap);

30

}

31

```

32

33

**Usage Examples:**

34

35

```java

36

public class DatabaseBundle implements ConfiguredBundle<MyConfiguration> {

37

@Override

38

public void initialize(Bootstrap<?> bootstrap) {

39

// Configure object mapper for database-specific serialization

40

bootstrap.getObjectMapper().registerModule(new JavaTimeModule());

41

}

42

43

@Override

44

public void run(MyConfiguration configuration, Environment environment) throws Exception {

45

// Set up database connection pool

46

final DataSource dataSource = configuration.getDataSourceFactory()

47

.build(environment.metrics(), "database");

48

49

// Register health check

50

environment.healthChecks().register("database",

51

new DatabaseHealthCheck(dataSource));

52

53

// Register managed object for connection pool lifecycle

54

environment.lifecycle().manage(new DataSourceManager(dataSource));

55

}

56

}

57

58

// Register in Application.initialize()

59

@Override

60

public void initialize(Bootstrap<MyConfiguration> bootstrap) {

61

bootstrap.addBundle(new DatabaseBundle());

62

}

63

```

64

65

### SslReloadBundle

66

67

Built-in bundle that provides SSL certificate reloading capability via an admin task, useful for certificate rotation without application restart.

68

69

```java { .api }

70

/**

71

* Bundle that gathers all the ssl connectors and registers an admin task that will

72

* refresh ssl configuration on request.

73

*/

74

public class SslReloadBundle implements ConfiguredBundle<Configuration> {

75

/**

76

* Creates a new SSL reload bundle.

77

*/

78

public SslReloadBundle();

79

80

@Override

81

public void run(Configuration configuration, Environment environment) throws Exception;

82

83

@Override

84

public void initialize(Bootstrap<?> bootstrap);

85

}

86

```

87

88

The SSL reload bundle automatically:

89

- Discovers all SSL connectors in the server configuration

90

- Registers an admin task at `/tasks/ssl-reload` for triggering certificate reloads

91

- Provides logging for reload operations

92

93

**Usage Examples:**

94

95

```java

96

@Override

97

public void initialize(Bootstrap<MyConfiguration> bootstrap) {

98

// Add SSL reload capability

99

bootstrap.addBundle(new SslReloadBundle());

100

}

101

```

102

103

After adding this bundle, you can reload SSL certificates by sending a POST request to the admin interface:

104

105

```bash

106

curl -X POST http://localhost:8081/tasks/ssl-reload

107

```

108

109

### SslReloadTask

110

111

The admin task that performs the actual SSL certificate reloading operation.

112

113

```java { .api }

114

/**

115

* Admin task for reloading SSL certificates.

116

*/

117

public class SslReloadTask extends Task {

118

/**

119

* Creates a new SSL reload task.

120

*/

121

public SslReloadTask();

122

123

@Override

124

public void execute(Map<String, List<String>> parameters, PrintWriter output) throws Exception;

125

}

126

```

127

128

This task is automatically registered by SslReloadBundle and can also be manually registered:

129

130

```java

131

environment.admin().addTask(new SslReloadTask());

132

```

133

134

## Creating Custom Bundles

135

136

### Simple Bundle Example

137

138

```java

139

public class MetricsBundle implements ConfiguredBundle<Configuration> {

140

@Override

141

public void initialize(Bootstrap<?> bootstrap) {

142

// Configure metrics registry during bootstrap

143

final MetricRegistry metrics = bootstrap.getMetricRegistry();

144

metrics.register("jvm.uptime", new UptimeGauge());

145

}

146

147

@Override

148

public void run(Configuration configuration, Environment environment) throws Exception {

149

// Set up metrics reporters

150

final ConsoleReporter reporter = ConsoleReporter.forRegistry(environment.metrics())

151

.convertRatesTo(TimeUnit.SECONDS)

152

.convertDurationsTo(TimeUnit.MILLISECONDS)

153

.build();

154

155

// Start reporting every 60 seconds

156

reporter.start(60, TimeUnit.SECONDS);

157

158

// Register as managed object to stop when application shuts down

159

environment.lifecycle().manage(new Managed() {

160

@Override

161

public void start() throws Exception {

162

// Already started above

163

}

164

165

@Override

166

public void stop() throws Exception {

167

reporter.stop();

168

}

169

});

170

}

171

}

172

```

173

174

### Parameterized Bundle Example

175

176

```java

177

public class CorsBundle<T extends Configuration> implements ConfiguredBundle<T> {

178

private final Function<T, CorsConfiguration> configExtractor;

179

180

public CorsBundle(Function<T, CorsConfiguration> configExtractor) {

181

this.configExtractor = configExtractor;

182

}

183

184

@Override

185

public void run(T configuration, Environment environment) throws Exception {

186

final CorsConfiguration corsConfig = configExtractor.apply(configuration);

187

188

if (corsConfig.isEnabled()) {

189

final FilterRegistration.Dynamic cors = environment.servlets()

190

.addFilter("CORS", CrossOriginFilter.class);

191

192

cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");

193

cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM,

194

String.join(",", corsConfig.getAllowedOrigins()));

195

cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM,

196

String.join(",", corsConfig.getAllowedHeaders()));

197

cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM,

198

String.join(",", corsConfig.getAllowedMethods()));

199

}

200

}

201

}

202

203

// Usage

204

@Override

205

public void initialize(Bootstrap<MyConfiguration> bootstrap) {

206

bootstrap.addBundle(new CorsBundle<>(MyConfiguration::getCorsConfiguration));

207

}

208

```

209

210

### Asset Bundle Example

211

212

```java

213

public class AssetsBundle implements ConfiguredBundle<Configuration> {

214

private final String resourcePath;

215

private final String uriPath;

216

private final String indexFile;

217

218

public AssetsBundle(String resourcePath, String uriPath, String indexFile) {

219

this.resourcePath = resourcePath;

220

this.uriPath = uriPath;

221

this.indexFile = indexFile;

222

}

223

224

@Override

225

public void run(Configuration configuration, Environment environment) throws Exception {

226

// Register servlet for serving static assets

227

final ServletRegistration.Dynamic servlet = environment.servlets()

228

.addServlet("assets", new AssetServlet(resourcePath, uriPath, indexFile));

229

230

servlet.addMapping(uriPath + "*");

231

servlet.setInitParameter("dirAllowed", "false");

232

servlet.setInitParameter("etags", "true");

233

}

234

}

235

236

// Usage

237

@Override

238

public void initialize(Bootstrap<MyConfiguration> bootstrap) {

239

// Serve static assets from /assets/ directory at /ui/ path

240

bootstrap.addBundle(new AssetsBundle("/assets/", "/ui/", "index.html"));

241

}

242

```

243

244

### Migration Bundle Example

245

246

```java

247

public abstract class MigrationsBundle<T extends Configuration> implements ConfiguredBundle<T> {

248

@Override

249

public void initialize(Bootstrap<?> bootstrap) {

250

// Add migration command to CLI

251

bootstrap.addCommand(new DbMigrateCommand<>("db migrate", this));

252

bootstrap.addCommand(new DbStatusCommand<>("db status", this));

253

}

254

255

@Override

256

public void run(T configuration, Environment environment) throws Exception {

257

// Register health check for database connectivity

258

final DataSource dataSource = getDataSourceFactory(configuration)

259

.build(environment.metrics(), "migrations");

260

261

environment.healthChecks().register("database",

262

new DatabaseHealthCheck(dataSource));

263

}

264

265

/**

266

* Override this method to provide the data source factory from your configuration.

267

*/

268

public abstract DataSourceFactory getDataSourceFactory(T configuration);

269

}

270

271

// Usage

272

@Override

273

public void initialize(Bootstrap<MyConfiguration> bootstrap) {

274

bootstrap.addBundle(new MigrationsBundle<MyConfiguration>() {

275

@Override

276

public DataSourceFactory getDataSourceFactory(MyConfiguration configuration) {

277

return configuration.getDataSourceFactory();

278

}

279

});

280

}

281

```

282

283

## Bundle Registration Order

284

285

Bundles are initialized and run in the order they are registered:

286

287

```java

288

@Override

289

public void initialize(Bootstrap<MyConfiguration> bootstrap) {

290

// These bundles will be initialized in this order

291

bootstrap.addBundle(new DatabaseBundle()); // 1st

292

bootstrap.addBundle(new SecurityBundle()); // 2nd

293

bootstrap.addBundle(new AssetsBundle()); // 3rd

294

bootstrap.addBundle(new SslReloadBundle()); // 4th

295

}

296

```

297

298

During application startup:

299

1. All bundles' `initialize()` methods are called in registration order

300

2. Configuration is parsed and validated

301

3. All bundles' `run()` methods are called in registration order

302

4. Application's `run()` method is called

303

304

## Bundle Best Practices

305

306

### Configuration Integration

307

308

```java

309

public class MyBundle implements ConfiguredBundle<MyConfiguration> {

310

@Override

311

public void run(MyConfiguration configuration, Environment environment) throws Exception {

312

// Access bundle-specific configuration

313

MyBundleConfig bundleConfig = configuration.getMyBundleConfig();

314

315

if (bundleConfig.isEnabled()) {

316

// Only configure if enabled

317

}

318

}

319

}

320

```

321

322

### Resource Management

323

324

```java

325

public class ResourceBundle implements ConfiguredBundle<Configuration> {

326

@Override

327

public void run(Configuration configuration, Environment environment) throws Exception {

328

final ExpensiveResource resource = new ExpensiveResource();

329

330

// Register as managed object for proper lifecycle

331

environment.lifecycle().manage(new Managed() {

332

@Override

333

public void start() throws Exception {

334

resource.start();

335

}

336

337

@Override

338

public void stop() throws Exception {

339

resource.close();

340

}

341

});

342

}

343

}

344

```

345

346

### Error Handling

347

348

```java

349

public class SafeBundle implements ConfiguredBundle<Configuration> {

350

@Override

351

public void run(Configuration configuration, Environment environment) throws Exception {

352

try {

353

// Bundle initialization logic

354

} catch (Exception e) {

355

// Log error and optionally rethrow

356

LOGGER.error("Failed to initialize SafeBundle", e);

357

throw new RuntimeException("SafeBundle initialization failed", e);

358

}

359

}

360

}

361

```

362

363

## Types

364

365

```java { .api }

366

// Task base class for admin interface

367

public abstract class Task {

368

protected Task(String name);

369

public abstract void execute(Map<String, List<String>> parameters, PrintWriter output) throws Exception;

370

}

371

372

// Managed interface for lifecycle management

373

public interface Managed {

374

void start() throws Exception;

375

void stop() throws Exception;

376

}

377

378

// Common configuration interfaces

379

public interface DataSourceFactory {

380

DataSource build(MetricRegistry metricRegistry, String name);

381

}

382

383

// SSL reload interfaces

384

public interface SslReload {

385

void reload() throws Exception;

386

}

387

```