or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdconfiguration.mdextensions.mdindex.mdrest-api.md

extensions.mddocs/

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

```