0
# Extension Points
1
2
The Selenium Grid server provides comprehensive extension points through public interfaces and abstract classes, enabling customization of Grid behavior for enterprise requirements.
3
4
## Capabilities
5
6
### Core Extension Interfaces
7
8
#### DriverProvider Interface
9
10
Interface for providing custom WebDriver implementations that can be discovered and used by the Grid server.
11
12
```java { .api }
13
package org.openqa.selenium.remote.server;
14
15
import org.openqa.selenium.Capabilities;
16
import org.openqa.selenium.WebDriver;
17
18
interface DriverProvider {
19
/**
20
* Get capabilities provided by this driver
21
* @return Capabilities that this provider can handle
22
*/
23
Capabilities getProvidedCapabilities();
24
25
/**
26
* Check if provider can create driver for given capabilities
27
* @param capabilities Desired capabilities to check
28
* @return true if provider supports these capabilities
29
*/
30
boolean canCreateDriverInstanceFor(Capabilities capabilities);
31
32
/**
33
* Create new WebDriver instance
34
* @param capabilities Capabilities for driver creation
35
* @return New WebDriver instance
36
*/
37
WebDriver newInstance(Capabilities capabilities);
38
}
39
```
40
41
**Usage Example:**
42
```java
43
public class CustomDriverProvider implements DriverProvider {
44
@Override
45
public Capabilities getProvidedCapabilities() {
46
return new ImmutableCapabilities("browserName", "customBrowser");
47
}
48
49
@Override
50
public boolean canCreateDriverInstanceFor(Capabilities capabilities) {
51
return "customBrowser".equals(capabilities.getBrowserName());
52
}
53
54
@Override
55
public WebDriver newInstance(Capabilities capabilities) {
56
return new CustomWebDriver(capabilities);
57
}
58
}
59
```
60
61
#### CommandHandler Interface
62
63
Fundamental interface for handling HTTP requests in the Grid server architecture.
64
65
```java { .api }
66
@FunctionalInterface
67
interface CommandHandler {
68
/**
69
* Execute HTTP request and generate response
70
* @param req HTTP request to process
71
* @param resp HTTP response to populate
72
* @throws IOException if request processing fails
73
*/
74
void execute(HttpRequest req, HttpResponse resp) throws IOException;
75
}
76
```
77
78
**Usage Example:**
79
```java
80
public class CustomCommandHandler implements CommandHandler {
81
@Override
82
public void execute(HttpRequest req, HttpResponse resp) throws IOException {
83
// Custom request processing logic
84
resp.setStatus(200);
85
resp.setContent(asJson(ImmutableMap.of("status", "custom response")));
86
}
87
}
88
```
89
90
#### SessionFactory Interface
91
92
Interface for creating new WebDriver sessions with custom logic and browser support.
93
94
```java { .api }
95
interface SessionFactory {
96
/**
97
* Check if this factory can create sessions for given capabilities
98
* @param capabilities Desired browser capabilities
99
* @return true if factory supports these capabilities
100
*/
101
boolean isSupporting(Capabilities capabilities);
102
103
/**
104
* Create new active session instance
105
* @param downstreamDialects WebDriver protocol dialects supported
106
* @param capabilities Desired browser capabilities
107
* @return ActiveSession if creation successful, empty otherwise
108
*/
109
Optional<ActiveSession> apply(Set<Dialect> downstreamDialects, Capabilities capabilities);
110
}
111
```
112
113
**Usage Example:**
114
```java
115
public class CustomSessionFactory implements SessionFactory {
116
@Override
117
public boolean isSupporting(Capabilities capabilities) {
118
return "customBrowser".equals(capabilities.getBrowserName());
119
}
120
121
@Override
122
public Optional<ActiveSession> apply(Set<Dialect> downstreamDialects, Capabilities capabilities) {
123
// Create custom session implementation
124
return Optional.of(new CustomActiveSession(capabilities));
125
}
126
}
127
```
128
129
#### ActiveSession Interface
130
131
Interface representing an active WebDriver session that can handle commands and provide driver access.
132
133
```java { .api }
134
interface ActiveSession extends CommandHandler, WrapsDriver {
135
/**
136
* Get unique session identifier
137
* @return SessionId for this session
138
*/
139
SessionId getId();
140
141
/**
142
* Get session capabilities
143
* @return Capabilities used to create this session
144
*/
145
Capabilities getCapabilities();
146
147
/**
148
* Get session creation timestamp
149
* @return Instant when session was created
150
*/
151
Instant getStartTime();
152
153
/**
154
* Get underlying WebDriver instance
155
* @return WebDriver instance for this session
156
*/
157
WebDriver getWrappedDriver();
158
}
159
```
160
161
#### CliCommand Interface
162
163
Interface for creating custom CLI commands that integrate with the Grid server's command system.
164
165
```java { .api }
166
interface CliCommand {
167
/**
168
* Get command name used in CLI
169
* @return Command name string
170
*/
171
String getName();
172
173
/**
174
* Get command description for help
175
* @return Human-readable description
176
*/
177
String getDescription();
178
179
/**
180
* Configure command with arguments and return executable
181
* @param args Command line arguments
182
* @return Executable that can be run
183
*/
184
Executable configure(String... args);
185
186
/**
187
* Executable interface for running configured commands
188
*/
189
interface Executable {
190
void run();
191
}
192
}
193
```
194
195
**Usage Example:**
196
```java
197
@AutoService(CliCommand.class)
198
public class CustomCommand implements CliCommand {
199
@Override
200
public String getName() {
201
return "custom";
202
}
203
204
@Override
205
public String getDescription() {
206
return "Custom Grid command for specialized functionality";
207
}
208
209
@Override
210
public Executable configure(String... args) {
211
return () -> {
212
// Custom command logic
213
System.out.println("Executing custom command");
214
};
215
}
216
}
217
```
218
219
### Abstract Base Classes
220
221
#### SessionMap Abstract Class
222
223
Base class for implementing custom session mapping strategies.
224
225
```java { .api }
226
abstract class SessionMap implements Predicate<HttpRequest>, CommandHandler {
227
/**
228
* Add session to the session map
229
* @param session Session to add
230
* @return true if session was added successfully
231
*/
232
public abstract boolean add(Session session);
233
234
/**
235
* Retrieve session by ID
236
* @param id Session identifier
237
* @return Session instance
238
* @throws NoSuchSessionException if session not found
239
*/
240
public abstract Session get(SessionId id) throws NoSuchSessionException;
241
242
/**
243
* Remove session from map
244
* @param id Session identifier to remove
245
*/
246
public abstract void remove(SessionId id);
247
248
/**
249
* Check if request should be handled by this session map
250
* @param req HTTP request
251
* @return true if this session map should handle the request
252
*/
253
@Override
254
public abstract boolean test(HttpRequest req);
255
}
256
```
257
258
#### Distributor Abstract Class
259
260
Base class for implementing custom session distribution strategies.
261
262
```java { .api }
263
abstract class Distributor implements Predicate<HttpRequest>, CommandHandler {
264
/**
265
* Create new session using available nodes
266
* @param payload New session request payload
267
* @return Created session
268
* @throws SessionNotCreatedException if session cannot be created
269
*/
270
public abstract Session newSession(NewSessionPayload payload) throws SessionNotCreatedException;
271
272
/**
273
* Register node with distributor
274
* @param node Node to add to available nodes
275
*/
276
public abstract void add(Node node);
277
278
/**
279
* Remove node from distributor
280
* @param nodeId Unique identifier of node to remove
281
*/
282
public abstract void remove(UUID nodeId);
283
284
/**
285
* Get current distributor status
286
* @return DistributorStatus with current state information
287
*/
288
public abstract DistributorStatus getStatus();
289
}
290
```
291
292
#### Node Abstract Class
293
294
Base class for implementing custom node behavior and session management.
295
296
```java { .api }
297
abstract class Node implements Predicate<HttpRequest>, CommandHandler {
298
/**
299
* Create new session on this node
300
* @param capabilities Desired browser capabilities
301
* @return Session if created successfully, empty otherwise
302
*/
303
public abstract Optional<Session> newSession(Capabilities capabilities);
304
305
/**
306
* Execute WebDriver command for existing session
307
* @param req HTTP request containing WebDriver command
308
* @param resp HTTP response to populate
309
*/
310
public abstract void executeWebDriverCommand(HttpRequest req, HttpResponse resp);
311
312
/**
313
* Get existing session by ID
314
* @param id Session identifier
315
* @return Session instance
316
* @throws NoSuchSessionException if session not found on this node
317
*/
318
public abstract Session getSession(SessionId id) throws NoSuchSessionException;
319
320
/**
321
* Stop session and clean up resources
322
* @param id Session identifier to stop
323
* @throws NoSuchSessionException if session not found
324
*/
325
public abstract void stop(SessionId id) throws NoSuchSessionException;
326
327
/**
328
* Check if this node owns the specified session
329
* @param id Session identifier to check
330
* @return true if this node owns the session
331
*/
332
protected abstract boolean isSessionOwner(SessionId id);
333
334
/**
335
* Check if node supports given capabilities
336
* @param capabilities Browser capabilities to check
337
* @return true if node can handle these capabilities
338
*/
339
public abstract boolean isSupporting(Capabilities capabilities);
340
341
/**
342
* Get current node status including capacity and active sessions
343
* @return NodeStatus with current state
344
*/
345
public abstract NodeStatus getStatus();
346
}
347
```
348
349
### Service Discovery
350
351
The Grid server uses Java ServiceLoader for automatic discovery of extensions.
352
353
#### AutoService Registration
354
355
Use Google AutoService annotation for automatic service registration:
356
357
```java { .api }
358
// Automatic service registration
359
@AutoService(CliCommand.class)
360
public class CustomCommand implements CliCommand { ... }
361
362
@AutoService(SessionFactory.class)
363
public class CustomSessionFactory implements SessionFactory { ... }
364
```
365
366
#### ServiceLoader Discovery
367
368
The Grid server automatically discovers registered services:
369
370
```java { .api }
371
// CLI command discovery (in Main.java)
372
Set<CliCommand> commands = new TreeSet<>(comparing(CliCommand::getName));
373
ServiceLoader.load(CliCommand.class).forEach(commands::add);
374
375
// Session factory discovery
376
ServiceLoader<SessionFactory> factories = ServiceLoader.load(SessionFactory.class);
377
```
378
379
### Extension Examples
380
381
#### Custom Browser Support
382
383
Add support for a custom browser by implementing SessionFactory:
384
385
```java
386
@AutoService(SessionFactory.class)
387
public class CustomBrowserFactory implements SessionFactory {
388
@Override
389
public boolean isSupporting(Capabilities capabilities) {
390
return "myCustomBrowser".equals(capabilities.getBrowserName());
391
}
392
393
@Override
394
public Optional<ActiveSession> apply(Set<Dialect> downstreamDialects, Capabilities capabilities) {
395
WebDriver driver = new CustomBrowserDriver(capabilities);
396
return Optional.of(new CustomActiveSession(driver, capabilities));
397
}
398
}
399
```
400
401
#### Custom Session Distribution
402
403
Implement custom session distribution logic:
404
405
```java
406
public class LoadBalancedDistributor extends Distributor {
407
@Override
408
public Session newSession(NewSessionPayload payload) throws SessionNotCreatedException {
409
Node selectedNode = selectNodeByLoad(payload.getDesiredCapabilities());
410
return selectedNode.newSession(payload.getDesiredCapabilities())
411
.orElseThrow(() -> new SessionNotCreatedException("No capacity available"));
412
}
413
414
private Node selectNodeByLoad(Capabilities capabilities) {
415
// Custom load balancing logic
416
return nodes.stream()
417
.filter(node -> node.isSupporting(capabilities))
418
.min(Comparator.comparing(this::getCurrentLoad))
419
.orElse(null);
420
}
421
}
422
```
423
424
#### Administrative Commands
425
426
Add custom administrative commands:
427
428
```java
429
@AutoService(CliCommand.class)
430
public class HealthCheckCommand implements CliCommand {
431
@Override
432
public String getName() {
433
return "healthcheck";
434
}
435
436
@Override
437
public String getDescription() {
438
return "Perform health check on Grid components";
439
}
440
441
@Override
442
public Executable configure(String... args) {
443
return () -> {
444
// Health check implementation
445
performHealthCheck();
446
};
447
}
448
}
449
```
450
451
### Extension Configuration
452
453
Extensions can access the same configuration system as core components:
454
455
```java { .api }
456
// Access configuration in extensions
457
Config config = new CompoundConfig(
458
new EnvConfig(),
459
new SystemPropertyConfig(),
460
new DefaultConfig()
461
);
462
463
String customValue = config.get("custom", "setting");
464
int customPort = config.getInt("custom", "port");
465
boolean customFlag = config.getBool("custom", "enabled");
466
```