or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-factory.mdcore-operations.mdevents-state.mdindex.mdschema-validation.mdtransactions.mdwatchers.md

schema-validation.mddocs/

0

# Schema Validation

1

2

Optional schema validation system for enforcing data structure and path constraints on ZooKeeper nodes, providing data integrity and consistency guarantees in distributed applications.

3

4

## Capabilities

5

6

### SchemaSet Management

7

8

Collection and management of schemas for comprehensive validation across ZooKeeper paths.

9

10

```java { .api }

11

/**

12

* Return this instance's schema set

13

* @return schema set

14

*/

15

SchemaSet getSchemaSet();

16

17

/**

18

* Collection of schemas for validation

19

*/

20

public class SchemaSet {

21

/**

22

* Get the default schema set (allows everything)

23

* @return default schema set

24

*/

25

public static SchemaSet getDefaultSchemaSet();

26

27

/**

28

* Create a new schema set builder

29

* @return builder

30

*/

31

public static Builder builder();

32

33

/**

34

* Get schema for a specific path

35

* @param path the path to check

36

* @return matching schema or null

37

*/

38

public Schema getSchema(String path);

39

40

/**

41

* Get schema by name

42

* @param name schema name

43

* @return named schema or null

44

*/

45

public Schema getNamedSchema(String name);

46

47

/**

48

* Get all schemas in this set

49

* @return collection of schemas

50

*/

51

public Collection<Schema> getSchemas();

52

53

/**

54

* Generate documentation for this schema set

55

* @return documentation string

56

*/

57

public String toDocumentation();

58

59

/**

60

* Check if schemas are enforced

61

* @return true if enforced

62

*/

63

public boolean isEnforced();

64

65

/**

66

* Builder for creating schema sets

67

*/

68

public static class Builder {

69

/**

70

* Add a schema to the set

71

* @param schema schema to add

72

* @return this builder

73

*/

74

public Builder schema(Schema schema);

75

76

/**

77

* Set whether schemas should be enforced

78

* @param enforced true to enforce

79

* @return this builder

80

*/

81

public Builder enforced(boolean enforced);

82

83

/**

84

* Build the schema set

85

* @return schema set

86

*/

87

public SchemaSet build();

88

}

89

}

90

```

91

92

**Usage Examples:**

93

94

```java

95

// Create custom schema set

96

SchemaSet customSchemas = SchemaSet.builder()

97

.schema(Schema.builder()

98

.name("UserConfig")

99

.path("/config/users")

100

.dataValidator(new JsonSchemaValidator())

101

.build())

102

.schema(Schema.builder()

103

.name("ServiceRegistry")

104

.pathRegex("/services/[^/]+")

105

.dataValidator(new ServiceConfigValidator())

106

.build())

107

.enforced(true)

108

.build();

109

110

// Create client with schema validation

111

CuratorFramework clientWithSchemas = CuratorFrameworkFactory.builder()

112

.connectString("localhost:2181")

113

.retryPolicy(new ExponentialBackoffRetry(1000, 3))

114

.schemaSet(customSchemas)

115

.build();

116

117

// Get current schema set

118

SchemaSet currentSchemas = client.getSchemaSet();

119

System.out.println("Schema enforcement: " + currentSchemas.isEnforced());

120

121

// List all schemas

122

for (Schema schema : currentSchemas.getSchemas()) {

123

System.out.println("Schema: " + schema.getName() + " -> " + schema.getPath());

124

}

125

126

// Generate documentation

127

String docs = currentSchemas.toDocumentation();

128

System.out.println("Schema Documentation:\n" + docs);

129

```

130

131

### Schema Definition

132

133

Individual schema definitions for specific paths or path patterns with custom validation rules.

134

135

```java { .api }

136

/**

137

* Defines validation rules for ZNode paths

138

*/

139

public class Schema {

140

/**

141

* Create a new schema builder

142

* @return builder

143

*/

144

public static SchemaBuilder builder();

145

146

/**

147

* Get the schema name

148

* @return name

149

*/

150

public String getName();

151

152

/**

153

* Get the exact path (if specified)

154

* @return exact path or null

155

*/

156

public String getPath();

157

158

/**

159

* Get the path regex pattern (if specified)

160

* @return regex pattern or null

161

*/

162

public Pattern getPathRegex();

163

164

/**

165

* Get the schema validator

166

* @return validator

167

*/

168

public SchemaValidator getSchemaValidator();

169

170

/**

171

* Get the documentation for this schema

172

* @return documentation string

173

*/

174

public String getDocumentation();

175

176

/**

177

* Generate documentation for this schema

178

* @return formatted documentation

179

*/

180

public String toDocumentation();

181

182

/**

183

* Check if this schema matches the given path

184

* @param path path to check

185

* @return true if matches

186

*/

187

public boolean matches(String path);

188

}

189

190

/**

191

* Builder for creating Schema instances

192

*/

193

public class SchemaBuilder {

194

/**

195

* Set the schema name

196

* @param name schema name

197

* @return this builder

198

*/

199

public SchemaBuilder name(String name);

200

201

/**

202

* Set an exact path for this schema

203

* @param path exact path

204

* @return this builder

205

*/

206

public SchemaBuilder path(String path);

207

208

/**

209

* Set a regex pattern for matching paths

210

* @param pathRegex regex pattern

211

* @return this builder

212

*/

213

public SchemaBuilder pathRegex(String pathRegex);

214

215

/**

216

* Set the data validator

217

* @param validator schema validator

218

* @return this builder

219

*/

220

public SchemaBuilder dataValidator(SchemaValidator validator);

221

222

/**

223

* Set documentation for this schema

224

* @param documentation documentation string

225

* @return this builder

226

*/

227

public SchemaBuilder documentation(String documentation);

228

229

/**

230

* Build the schema

231

* @return schema instance

232

*/

233

public Schema build();

234

}

235

```

236

237

**Usage Examples:**

238

239

```java

240

// Exact path schema

241

Schema configSchema = Schema.builder()

242

.name("ApplicationConfig")

243

.path("/app/config")

244

.dataValidator(new JsonSchemaValidator("{\"type\": \"object\"}"))

245

.documentation("Application configuration in JSON format")

246

.build();

247

248

// Regex path schema for service registry

249

Schema serviceSchema = Schema.builder()

250

.name("ServiceEndpoints")

251

.pathRegex("/services/[a-zA-Z0-9-]+/endpoints")

252

.dataValidator(new ServiceEndpointValidator())

253

.documentation("Service endpoint configurations")

254

.build();

255

256

// Schema for ephemeral nodes

257

Schema ephemeralSchema = Schema.builder()

258

.name("Sessions")

259

.pathRegex("/sessions/.*")

260

.dataValidator(new SessionDataValidator())

261

.documentation("User session data (ephemeral nodes)")

262

.build();

263

264

// Check path matching

265

System.out.println("Matches config: " + configSchema.matches("/app/config"));

266

System.out.println("Matches service: " + serviceSchema.matches("/services/user-service/endpoints"));

267

268

// Get schema details

269

System.out.println("Schema name: " + configSchema.getName());

270

System.out.println("Schema path: " + configSchema.getPath());

271

System.out.println("Schema docs: " + configSchema.getDocumentation());

272

```

273

274

### Schema Validation

275

276

Validator interfaces and implementations for enforcing data constraints and structure validation.

277

278

```java { .api }

279

/**

280

* Validates ZNode data

281

*/

282

public interface SchemaValidator {

283

/**

284

* Validate the data for a given path and stat

285

* @param path the path

286

* @param data the data to validate

287

* @param stat the stat information

288

* @return true if valid

289

* @throws SchemaViolation if validation fails

290

*/

291

boolean isValid(String path, byte[] data, Stat stat) throws SchemaViolation;

292

}

293

294

/**

295

* Default validator that allows everything

296

*/

297

public class DefaultSchemaValidator implements SchemaValidator {

298

@Override

299

public boolean isValid(String path, byte[] data, Stat stat) {

300

return true; // Always valid

301

}

302

}

303

304

/**

305

* Exception for schema validation violations

306

*/

307

public class SchemaViolation extends IllegalArgumentException {

308

/**

309

* Create schema violation with message

310

* @param message violation message

311

*/

312

public SchemaViolation(String message);

313

314

/**

315

* Create schema violation with message and cause

316

* @param message violation message

317

* @param cause underlying cause

318

*/

319

public SchemaViolation(String message, Throwable cause);

320

321

/**

322

* Get the path that caused the violation

323

* @return path

324

*/

325

public String getPath();

326

327

/**

328

* Get the schema that was violated

329

* @return schema

330

*/

331

public Schema getSchema();

332

}

333

```

334

335

**Custom Validator Examples:**

336

337

```java

338

// JSON Schema Validator

339

public class JsonSchemaValidator implements SchemaValidator {

340

private final String jsonSchema;

341

342

public JsonSchemaValidator(String jsonSchema) {

343

this.jsonSchema = jsonSchema;

344

}

345

346

@Override

347

public boolean isValid(String path, byte[] data, Stat stat) throws SchemaViolation {

348

if (data == null || data.length == 0) {

349

throw new SchemaViolation("JSON data cannot be empty for path: " + path);

350

}

351

352

try {

353

String jsonData = new String(data, StandardCharsets.UTF_8);

354

ObjectMapper mapper = new ObjectMapper();

355

mapper.readTree(jsonData); // Parse to validate JSON

356

357

// Here you would validate against the JSON schema

358

// Using a library like json-schema-validator

359

return true;

360

} catch (Exception e) {

361

throw new SchemaViolation("Invalid JSON data for path: " + path, e);

362

}

363

}

364

}

365

366

// Size-based Validator

367

public class SizeValidator implements SchemaValidator {

368

private final int maxSize;

369

private final int minSize;

370

371

public SizeValidator(int minSize, int maxSize) {

372

this.minSize = minSize;

373

this.maxSize = maxSize;

374

}

375

376

@Override

377

public boolean isValid(String path, byte[] data, Stat stat) throws SchemaViolation {

378

int size = data != null ? data.length : 0;

379

380

if (size < minSize) {

381

throw new SchemaViolation(

382

String.format("Data size %d is below minimum %d for path: %s", size, minSize, path)

383

);

384

}

385

386

if (size > maxSize) {

387

throw new SchemaViolation(

388

String.format("Data size %d exceeds maximum %d for path: %s", size, maxSize, path)

389

);

390

}

391

392

return true;

393

}

394

}

395

396

// Service Configuration Validator

397

public class ServiceConfigValidator implements SchemaValidator {

398

@Override

399

public boolean isValid(String path, byte[] data, Stat stat) throws SchemaViolation {

400

if (data == null || data.length == 0) {

401

throw new SchemaViolation("Service configuration cannot be empty: " + path);

402

}

403

404

try {

405

String config = new String(data, StandardCharsets.UTF_8);

406

Properties props = new Properties();

407

props.load(new StringReader(config));

408

409

// Validate required properties

410

if (!props.containsKey("service.name")) {

411

throw new SchemaViolation("Missing required property 'service.name' in: " + path);

412

}

413

414

if (!props.containsKey("service.port")) {

415

throw new SchemaViolation("Missing required property 'service.port' in: " + path);

416

}

417

418

// Validate port range

419

String portStr = props.getProperty("service.port");

420

int port = Integer.parseInt(portStr);

421

if (port < 1024 || port > 65535) {

422

throw new SchemaViolation("Invalid port range for: " + path);

423

}

424

425

return true;

426

} catch (Exception e) {

427

throw new SchemaViolation("Invalid service configuration for: " + path, e);

428

}

429

}

430

}

431

432

// Usage examples

433

Schema jsonConfigSchema = Schema.builder()

434

.name("JsonConfig")

435

.pathRegex("/config/.*\\.json")

436

.dataValidator(new JsonSchemaValidator("{\"type\": \"object\"}"))

437

.build();

438

439

Schema sizeConstrainedSchema = Schema.builder()

440

.name("SmallData")

441

.pathRegex("/cache/.*")

442

.dataValidator(new SizeValidator(1, 1024)) // 1 byte to 1KB

443

.build();

444

445

Schema serviceConfigSchema = Schema.builder()

446

.name("ServiceConfig")

447

.pathRegex("/services/.*/config")

448

.dataValidator(new ServiceConfigValidator())

449

.build();

450

```

451

452

### Schema Loading and Configuration

453

454

Utility classes for loading schemas from external configuration sources.

455

456

```java { .api }

457

/**

458

* Utility for loading schema sets from configuration

459

*/

460

public class SchemaSetLoader {

461

/**

462

* Load schema set from JSON configuration

463

* @param jsonConfig JSON configuration string

464

* @return schema set

465

* @throws Exception if loading fails

466

*/

467

public static SchemaSet loadFromJson(String jsonConfig) throws Exception;

468

469

/**

470

* Load schema set from properties file

471

* @param properties properties configuration

472

* @return schema set

473

* @throws Exception if loading fails

474

*/

475

public static SchemaSet loadFromProperties(Properties properties) throws Exception;

476

477

/**

478

* Load schema set from resource file

479

* @param resourcePath path to resource file

480

* @return schema set

481

* @throws Exception if loading fails

482

*/

483

public static SchemaSet loadFromResource(String resourcePath) throws Exception;

484

}

485

```

486

487

**Configuration Examples:**

488

489

```java

490

// Load schemas from JSON configuration

491

String jsonConfig = """

492

{

493

"enforced": true,

494

"schemas": [

495

{

496

"name": "UserProfiles",

497

"path": "/users",

498

"validator": "json",

499

"config": {"type": "object", "required": ["id", "name"]}

500

},

501

{

502

"name": "ServiceRegistry",

503

"pathRegex": "/services/[^/]+",

504

"validator": "size",

505

"config": {"minSize": 10, "maxSize": 1024}

506

}

507

]

508

}

509

""";

510

511

SchemaSet loadedSchemas = SchemaSetLoader.loadFromJson(jsonConfig);

512

513

// Load schemas from properties

514

Properties props = new Properties();

515

props.setProperty("schemas.enforced", "true");

516

props.setProperty("schemas.user.name", "UserData");

517

props.setProperty("schemas.user.path", "/users/*");

518

props.setProperty("schemas.user.validator", "json");

519

520

SchemaSet propsSchemas = SchemaSetLoader.loadFromProperties(props);

521

522

// Load from resource file

523

SchemaSet resourceSchemas = SchemaSetLoader.loadFromResource("/schemas/zk-schemas.json");

524

525

// Apply loaded schemas to client

526

CuratorFramework schemaClient = CuratorFrameworkFactory.builder()

527

.connectString("localhost:2181")

528

.retryPolicy(new ExponentialBackoffRetry(1000, 3))

529

.schemaSet(loadedSchemas)

530

.build();

531

```

532

533

### Schema Enforcement and Error Handling

534

535

How schema validation is applied during ZooKeeper operations and error handling strategies.

536

537

**Usage Examples:**

538

539

```java

540

// Schema violations during operations

541

try {

542

// This will trigger schema validation

543

client.create()

544

.forPath("/config/app.json", "invalid json data".getBytes());

545

546

} catch (SchemaViolation e) {

547

System.err.println("Schema violation: " + e.getMessage());

548

System.err.println("Path: " + e.getPath());

549

System.err.println("Schema: " + e.getSchema().getName());

550

551

// Handle validation error appropriately

552

// Maybe try with corrected data or use default values

553

}

554

555

// Check schema before operation

556

SchemaSet schemas = client.getSchemaSet();

557

Schema pathSchema = schemas.getSchema("/config/database.json");

558

559

if (pathSchema != null) {

560

try {

561

// Validate data before sending

562

String jsonData = "{\"host\": \"localhost\", \"port\": 5432}";

563

pathSchema.getSchemaValidator().isValid("/config/database.json",

564

jsonData.getBytes(), null);

565

566

// If validation passes, proceed with operation

567

client.create()

568

.forPath("/config/database.json", jsonData.getBytes());

569

570

} catch (SchemaViolation e) {

571

System.err.println("Pre-validation failed: " + e.getMessage());

572

// Handle validation failure

573

}

574

}

575

576

// Disable schema enforcement temporarily

577

SchemaSet permissiveSchemas = SchemaSet.builder()

578

.enforced(false) // Validation warnings only, no exceptions

579

.build();

580

581

CuratorFramework permissiveClient = client.usingNamespace("temp")

582

.// Note: Can't change schema set on existing client

583

// Would need new client instance

584

```