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