or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-extension.mdindex.mdxml-configuration.mdxml-generation.mdxml-parser.md

configuration-extension.mddocs/

0

# Configuration Extension and Customization

1

2

Extensible configuration processing system supporting custom configuration formats and processors. The library provides service provider interfaces that allow alternative configuration formats (e.g., Spring XML, YAML, JSON) to be plugged in instead of or alongside the default Jetty XML format.

3

4

## Capabilities

5

6

### ConfigurationProcessor Interface

7

8

Interface for implementing custom configuration processors that can handle alternative configuration formats.

9

10

```java { .api }

11

/**

12

* Interface for alternative configuration processors

13

* Allows non-XML configuration formats to be used instead of Jetty XML

14

*/

15

interface ConfigurationProcessor {

16

/**

17

* Initialize processor with configuration context

18

* @param resource configuration resource being processed

19

* @param root root node of parsed document (may be null for non-XML formats)

20

* @param configuration XmlConfiguration instance for context

21

* @throws Exception if initialization fails

22

*/

23

void init(Resource resource, XmlParser.Node root, XmlConfiguration configuration) throws Exception;

24

25

/**

26

* Configure existing object

27

* @param obj object to configure

28

* @return configured object

29

* @throws Exception if configuration fails

30

*/

31

Object configure(Object obj) throws Exception;

32

33

/**

34

* Create and configure new object

35

* @return configured object instance

36

* @throws Exception if configuration fails

37

*/

38

Object configure() throws Exception;

39

}

40

```

41

42

### ConfigurationProcessorFactory Interface

43

44

Service provider interface for creating configuration processors based on document characteristics.

45

46

```java { .api }

47

/**

48

* Factory interface for creating configuration processors

49

* Implementations are discovered via ServiceLoader

50

*/

51

interface ConfigurationProcessorFactory {

52

/**

53

* Get processor for specific DTD and root tag combination

54

* @param dtd DTD identifier (may be null if validation disabled)

55

* @param tag root element tag name

56

* @return configuration processor instance, or null if not supported

57

*/

58

ConfigurationProcessor getConfigurationProcessor(String dtd, String tag);

59

}

60

```

61

62

### BaseClassCatalog Class

63

64

Custom XML catalog implementation that supports runtime determination of base URI for entity resolution.

65

66

```java { .api }

67

/**

68

* XML catalog where xml:base is defined externally

69

* Allows runtime determination of base URI for entity resolution

70

*/

71

class BaseClassCatalog implements Catalog, EntityResolver {

72

/**

73

* Factory method to load catalog from XML file

74

* @param uriToCatalogXml URI to catalog XML file

75

* @param baseClass base class for relative URI resolution

76

* @return loaded catalog instance

77

* @throws IllegalArgumentException if catalog cannot be loaded

78

*/

79

static BaseClassCatalog load(URI uriToCatalogXml, Class<?> baseClass);

80

}

81

```

82

83

### Catalog Interface Implementation

84

85

Standard XML catalog operations for entity resolution.

86

87

```java { .api }

88

/**

89

* Return stream of alternative catalogs (always empty for BaseClassCatalog)

90

* @return empty stream

91

*/

92

Stream<Catalog> catalogs();

93

94

/**

95

* Match public ID to system URI

96

* @param publicId public identifier to match

97

* @return system URI or null if no match

98

*/

99

String matchPublic(String publicId);

100

101

/**

102

* Match system ID to URI

103

* @param systemId system identifier to match

104

* @return resolved URI or null if no match

105

*/

106

String matchSystem(String systemId);

107

108

/**

109

* Match URI to identifier

110

* @param uri URI to match

111

* @return matched identifier or null if no match

112

*/

113

String matchURI(String uri);

114

```

115

116

### EntityResolver Implementation

117

118

SAX EntityResolver implementation for custom entity resolution.

119

120

```java { .api }

121

/**

122

* Resolve external entity references

123

* @param publicId public identifier

124

* @param systemId system identifier

125

* @return InputSource for resolved entity, or null for default behavior

126

* @throws SAXException if resolution fails

127

* @throws IOException if I/O error occurs

128

*/

129

InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException;

130

```

131

132

### EnvironmentBuilder Class

133

134

Builder for creating isolated runtime environments with custom classpaths and module paths.

135

136

```java { .api }

137

/**

138

* Builder for Environment instances used in XML configuration

139

* Supports custom classpaths and module paths

140

*/

141

class EnvironmentBuilder {

142

/**

143

* Create builder with environment name

144

* @param name environment name

145

*/

146

EnvironmentBuilder(@Name("name") String name);

147

}

148

```

149

150

### Environment Configuration

151

152

Configure environment with custom paths and modules.

153

154

```java { .api }

155

/**

156

* Add paths to classpath

157

* @param classPaths classpath entries to add

158

*/

159

void addClassPath(String... classPaths);

160

161

/**

162

* Add path to module path

163

* @param modulePath module path entry to add

164

*/

165

void addModulePath(String modulePath);

166

167

/**

168

* Create configured Environment instance

169

* @return built environment

170

*/

171

Environment build();

172

```

173

174

## Usage Examples

175

176

### Custom Configuration Processor

177

178

```java

179

import org.eclipse.jetty.xml.ConfigurationProcessor;

180

import org.eclipse.jetty.xml.XmlConfiguration;

181

import org.eclipse.jetty.xml.XmlParser;

182

import org.eclipse.jetty.util.resource.Resource;

183

184

public class JsonConfigurationProcessor implements ConfigurationProcessor {

185

private Resource resource;

186

private XmlConfiguration xmlConfig;

187

private JsonNode configRoot;

188

189

@Override

190

public void init(Resource resource, XmlParser.Node root, XmlConfiguration configuration)

191

throws Exception {

192

this.resource = resource;

193

this.xmlConfig = configuration;

194

195

// Parse JSON configuration

196

ObjectMapper mapper = new ObjectMapper();

197

try (InputStream in = resource.newInputStream()) {

198

this.configRoot = mapper.readTree(in);

199

}

200

}

201

202

@Override

203

public Object configure() throws Exception {

204

// Create object from JSON configuration

205

String className = configRoot.get("class").asText();

206

Class<?> clazz = Class.forName(className);

207

Object instance = clazz.getDeclaredConstructor().newInstance();

208

209

return configure(instance);

210

}

211

212

@Override

213

public Object configure(Object obj) throws Exception {

214

// Apply JSON configuration to object

215

JsonNode properties = configRoot.get("properties");

216

if (properties != null) {

217

properties.fields().forEachRemaining(entry -> {

218

try {

219

String name = entry.getKey();

220

String value = entry.getValue().asText();

221

222

// Use reflection to set property

223

setProperty(obj, name, value);

224

} catch (Exception e) {

225

throw new RuntimeException("Failed to set property: " + entry.getKey(), e);

226

}

227

});

228

}

229

230

return obj;

231

}

232

233

private void setProperty(Object obj, String name, String value) throws Exception {

234

// Reflection-based property setting logic

235

String setterName = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);

236

Method setter = obj.getClass().getMethod(setterName, String.class);

237

setter.invoke(obj, value);

238

}

239

}

240

```

241

242

### Configuration Processor Factory

243

244

```java

245

import org.eclipse.jetty.xml.ConfigurationProcessorFactory;

246

import org.eclipse.jetty.xml.ConfigurationProcessor;

247

248

public class JsonConfigurationProcessorFactory implements ConfigurationProcessorFactory {

249

250

@Override

251

public ConfigurationProcessor getConfigurationProcessor(String dtd, String tag) {

252

// Support JSON configuration files

253

if (tag != null && tag.equals("json-config")) {

254

return new JsonConfigurationProcessor();

255

}

256

257

// Support Spring-style XML

258

if (dtd != null && dtd.contains("springframework")) {

259

return new SpringConfigurationProcessor();

260

}

261

262

return null; // Not supported

263

}

264

}

265

```

266

267

### Service Provider Registration

268

269

Create `META-INF/services/org.eclipse.jetty.xml.ConfigurationProcessorFactory` file:

270

271

```

272

com.example.JsonConfigurationProcessorFactory

273

com.example.SpringConfigurationProcessorFactory

274

```

275

276

### Using Custom Catalog

277

278

```java

279

import org.eclipse.jetty.xml.BaseClassCatalog;

280

import org.eclipse.jetty.xml.XmlParser;

281

import java.net.URI;

282

283

// Load custom catalog

284

BaseClassCatalog catalog = BaseClassCatalog.load(

285

URI.create("file:///path/to/custom-catalog.xml"),

286

MyClass.class

287

);

288

289

// Use catalog with parser

290

XmlParser parser = new XmlParser();

291

parser.addCatalog(catalog.getURI(), MyClass.class);

292

293

// Parse with custom entity resolution

294

XmlParser.Node root = parser.parse("config-with-entities.xml");

295

```

296

297

### Environment Builder Usage

298

299

```java

300

import org.eclipse.jetty.xml.EnvironmentBuilder;

301

import org.eclipse.jetty.util.component.Environment;

302

303

// Create isolated environment

304

EnvironmentBuilder builder = new EnvironmentBuilder("test-env");

305

builder.addClassPath("/path/to/additional/classes");

306

builder.addClassPath("/path/to/lib/*.jar");

307

builder.addModulePath("/path/to/modules");

308

309

Environment env = builder.build();

310

311

// Use environment for configuration

312

// (Environment usage depends on broader Jetty context)

313

```

314

315

### XML Configuration with Custom Processor

316

317

Example JSON configuration file (`server.json`):

318

319

```json

320

{

321

"class": "com.example.Server",

322

"properties": {

323

"port": "8080",

324

"host": "localhost",

325

"maxThreads": "200"

326

},

327

"handlers": [

328

{

329

"class": "com.example.WebAppHandler",

330

"properties": {

331

"contextPath": "/",

332

"resourceBase": "./webapps"

333

}

334

}

335

]

336

}

337

```

338

339

XML wrapper to invoke JSON processor:

340

341

```xml

342

<?xml version="1.0" encoding="UTF-8"?>

343

<json-config file="server.json"/>

344

```

345

346

### Catalog XML Example

347

348

Custom catalog file (`custom-catalog.xml`):

349

350

```xml

351

<?xml version="1.0" encoding="UTF-8"?>

352

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">

353

<public publicId="-//MyCompany//DTD Config//EN"

354

uri="config.dtd"/>

355

<system systemId="http://example.com/schemas/config.xsd"

356

uri="schemas/config.xsd"/>

357

</catalog>

358

```

359

360

## Extension Points

361

362

### 1. Configuration Formats

363

364

Support alternative configuration formats by implementing:

365

- `ConfigurationProcessor` for format-specific processing logic

366

- `ConfigurationProcessorFactory` for format detection and processor creation

367

368

### 2. Entity Resolution

369

370

Customize XML entity resolution by:

371

- Creating custom `Catalog` implementations

372

- Using `BaseClassCatalog` for runtime base URI determination

373

- Adding catalogs to `XmlParser` instances

374

375

### 3. Environment Isolation

376

377

Create isolated runtime environments by:

378

- Using `EnvironmentBuilder` to configure custom classpaths

379

- Adding module path entries for Java 9+ module system support

380

- Building environments for sandboxed configuration processing

381

382

## Service Discovery

383

384

The extension system uses Java's ServiceLoader mechanism:

385

386

1. Implement `ConfigurationProcessorFactory`

387

2. Create service file in `META-INF/services/`

388

3. List implementation classes in the service file

389

4. Ensure classes are on classpath at runtime

390

391

The `XmlConfiguration` class automatically discovers and uses registered processors based on DTD and root element matching.

392

393

## Best Practices

394

395

1. **DTD/Tag Matching**: Use specific DTD or root tag patterns for processor selection

396

2. **Error Handling**: Provide clear error messages for configuration failures

397

3. **Resource Management**: Properly close resources in processor implementations

398

4. **Thread Safety**: Ensure processor implementations are thread-safe if needed

399

5. **Fallback Behavior**: Return null from factory if format is not supported

400

6. **Documentation**: Document supported configuration formats and syntax