or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async.mdcore-rpc.mdindex.mdplugins.mdprotocols.mdstats.mdtransports.md

protocols.mddocs/

0

# Protocol Implementations

1

2

Apache Avro IPC provides three distinct protocol implementations to support different Java object models and development workflows: Generic (no code generation), Specific (generated classes), and Reflect (existing interfaces).

3

4

## Capabilities

5

6

### Generic Protocol

7

8

Generic protocol implementation works with Avro's `GenericData` model, requiring no code generation. Uses `GenericRecord` and other generic types for data representation.

9

10

#### Generic Requestor

11

12

```java { .api }

13

public class GenericRequestor extends Requestor {

14

// Constructors

15

public GenericRequestor(Protocol protocol, Transceiver transceiver) throws IOException;

16

public GenericRequestor(Protocol protocol, Transceiver transceiver, GenericData data) throws IOException;

17

18

// Data model access

19

public GenericData getGenericData();

20

21

// Inherited from Requestor

22

public Object request(String messageName, Object request) throws Exception;

23

public <T> void request(String messageName, Object request, Callback<T> callback) throws Exception;

24

}

25

```

26

27

#### Generic Responder

28

29

```java { .api }

30

public abstract class GenericResponder extends Responder {

31

// Constructors

32

public GenericResponder(Protocol local);

33

public GenericResponder(Protocol local, GenericData data);

34

35

// Data model access

36

public GenericData getGenericData();

37

38

// Abstract method - implement your business logic

39

public abstract Object respond(Message message, Object request) throws Exception;

40

41

// Protected methods for customization

42

protected DatumWriter<Object> getDatumWriter(Schema schema);

43

protected DatumReader<Object> getDatumReader(Schema actual, Schema expected);

44

}

45

```

46

47

#### Usage Examples

48

49

```java

50

// Generic client setup

51

Protocol protocol = Protocol.parse(protocolJson);

52

HttpTransceiver transceiver = new HttpTransceiver(serverUrl);

53

GenericRequestor requestor = new GenericRequestor(protocol, transceiver);

54

55

// Create generic request data

56

GenericData.Record request = new GenericData.Record(requestSchema);

57

request.put("message", "Hello World");

58

request.put("timestamp", System.currentTimeMillis());

59

60

// Make RPC call

61

Object response = requestor.request("echo", request);

62

if (response instanceof GenericData.Record) {

63

GenericData.Record record = (GenericData.Record) response;

64

System.out.println("Response: " + record.get("result"));

65

}

66

67

// Generic server implementation

68

public class MyGenericResponder extends GenericResponder {

69

public MyGenericResponder(Protocol protocol) {

70

super(protocol);

71

}

72

73

@Override

74

public Object respond(Message message, Object request) throws Exception {

75

String messageName = message.getName();

76

GenericData.Record requestRecord = (GenericData.Record) request;

77

78

switch (messageName) {

79

case "echo":

80

return handleEcho(requestRecord);

81

case "getData":

82

return handleGetData(requestRecord);

83

default:

84

throw new AvroRuntimeException("Unknown message: " + messageName);

85

}

86

}

87

88

private Object handleEcho(GenericData.Record request) {

89

GenericData.Record response = new GenericData.Record(responseSchema);

90

response.put("result", request.get("message"));

91

return response;

92

}

93

}

94

```

95

96

### Specific Protocol

97

98

Specific protocol implementation works with Java classes generated from Avro schemas or IDL files. Provides type-safe, compile-time checked RPC interfaces.

99

100

#### Specific Requestor

101

102

```java { .api }

103

public class SpecificRequestor extends Requestor implements InvocationHandler {

104

// Constructors

105

public SpecificRequestor(Class<?> iface, Transceiver transceiver) throws IOException;

106

public SpecificRequestor(Class<?> iface, Transceiver transceiver, SpecificData data) throws IOException;

107

public SpecificRequestor(Protocol protocol, Transceiver transceiver, SpecificData data) throws IOException;

108

protected SpecificRequestor(Protocol protocol, Transceiver transceiver) throws IOException;

109

110

// Data model access

111

public SpecificData getSpecificData();

112

113

// InvocationHandler for proxy clients

114

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

115

116

// Static factory methods for proxy clients

117

public static <T> T getClient(Class<T> iface, Transceiver transceiver) throws IOException;

118

public static <T> T getClient(Class<T> iface, Transceiver transceiver, SpecificData data) throws IOException;

119

public static <T> T getClient(Class<T> iface, SpecificRequestor requestor);

120

121

// Utility methods

122

public static Protocol getRemote(Object proxy);

123

124

// Protected methods for customization

125

protected DatumWriter<Object> getDatumWriter(Schema schema);

126

protected DatumReader<Object> getDatumReader(Schema writer, Schema reader);

127

}

128

```

129

130

#### Specific Responder

131

132

```java { .api }

133

public class SpecificResponder extends GenericResponder {

134

// Constructors

135

public SpecificResponder(Class iface, Object impl);

136

public SpecificResponder(Protocol protocol, Object impl);

137

public SpecificResponder(Class iface, Object impl, SpecificData data);

138

public SpecificResponder(Protocol protocol, Object impl, SpecificData data);

139

140

// Data model access

141

public SpecificData getSpecificData();

142

143

// Inherited abstract method - automatically implemented via reflection

144

public Object respond(Message message, Object request) throws Exception;

145

146

// Protected methods for customization

147

protected DatumWriter<Object> getDatumWriter(Schema schema);

148

protected DatumReader<Object> getDatumReader(Schema actual, Schema expected);

149

}

150

```

151

152

#### Usage Examples

153

154

```java

155

// Assuming generated interface from Avro IDL:

156

// interface MyService {

157

// string echo(string message);

158

// UserRecord getUser(long userId);

159

// }

160

161

// Specific client with proxy interface

162

HttpTransceiver transceiver = new HttpTransceiver(serverUrl);

163

MyService client = SpecificRequestor.getClient(MyService.class, transceiver);

164

165

// Type-safe RPC calls

166

String response = client.echo("Hello World");

167

UserRecord user = client.getUser(12345L);

168

169

// Alternative: Direct SpecificRequestor usage

170

SpecificRequestor requestor = new SpecificRequestor(MyService.class, transceiver);

171

String response = (String) requestor.request("echo", "Hello World");

172

173

// Specific server implementation

174

public class MyServiceImpl implements MyService {

175

@Override

176

public String echo(String message) {

177

return "Echo: " + message;

178

}

179

180

@Override

181

public UserRecord getUser(long userId) {

182

UserRecord user = new UserRecord();

183

user.setId(userId);

184

user.setName("User " + userId);

185

return user;

186

}

187

}

188

189

// Server setup

190

MyServiceImpl implementation = new MyServiceImpl();

191

SpecificResponder responder = new SpecificResponder(MyService.class, implementation);

192

SaslSocketServer server = new SaslSocketServer(responder, new InetSocketAddress(8080));

193

server.start();

194

```

195

196

### Reflect Protocol

197

198

Reflect protocol implementation works with existing Java interfaces using reflection, without requiring code generation from Avro schemas.

199

200

#### Reflect Requestor

201

202

```java { .api }

203

public class ReflectRequestor extends SpecificRequestor {

204

// Constructors

205

public ReflectRequestor(Class<?> iface, Transceiver transceiver) throws IOException;

206

public ReflectRequestor(Class<?> iface, Transceiver transceiver, ReflectData data) throws IOException;

207

public ReflectRequestor(Protocol protocol, Transceiver transceiver, ReflectData data) throws IOException;

208

protected ReflectRequestor(Protocol protocol, Transceiver transceiver) throws IOException;

209

210

// Data model access

211

public ReflectData getReflectData();

212

213

// Static factory methods for proxy clients

214

public static <T> T getClient(Class<T> iface, Transceiver transceiver) throws IOException;

215

public static <T> T getClient(Class<T> iface, Transceiver transceiver, ReflectData reflectData) throws IOException;

216

public static <T> T getClient(Class<T> iface, ReflectRequestor rreq);

217

218

// Protected methods for customization

219

protected DatumWriter<Object> getDatumWriter(Schema schema);

220

protected DatumReader<Object> getDatumReader(Schema writer, Schema reader);

221

}

222

```

223

224

#### Reflect Responder

225

226

```java { .api }

227

public class ReflectResponder extends SpecificResponder {

228

// Constructors

229

public ReflectResponder(Class iface, Object impl);

230

public ReflectResponder(Protocol protocol, Object impl);

231

public ReflectResponder(Class iface, Object impl, ReflectData data);

232

public ReflectResponder(Protocol protocol, Object impl, ReflectData data);

233

234

// Data model access

235

public ReflectData getReflectData();

236

237

// Inherited methods from SpecificResponder

238

public Object respond(Message message, Object request) throws Exception;

239

240

// Protected methods for customization

241

protected DatumWriter<Object> getDatumWriter(Schema schema);

242

protected DatumReader<Object> getDatumReader(Schema actual, Schema expected);

243

}

244

```

245

246

#### Usage Examples

247

248

```java

249

// Existing Java interface (no Avro generation needed)

250

public interface Calculator {

251

double add(double a, double b);

252

double subtract(double a, double b);

253

Complex multiply(Complex a, Complex b);

254

}

255

256

public class Complex {

257

private double real;

258

private double imaginary;

259

260

// Constructors, getters, setters

261

public Complex() {}

262

public Complex(double real, double imaginary) {

263

this.real = real;

264

this.imaginary = imaginary;

265

}

266

// ... getters and setters

267

}

268

269

// Reflect client

270

HttpTransceiver transceiver = new HttpTransceiver(serverUrl);

271

Calculator client = ReflectRequestor.getClient(Calculator.class, transceiver);

272

273

// Type-safe calls using existing interface

274

double sum = client.add(3.14, 2.86);

275

Complex result = client.multiply(new Complex(1, 2), new Complex(3, 4));

276

277

// Reflect server implementation

278

public class CalculatorImpl implements Calculator {

279

@Override

280

public double add(double a, double b) {

281

return a + b;

282

}

283

284

@Override

285

public double subtract(double a, double b) {

286

return a - b;

287

}

288

289

@Override

290

public Complex multiply(Complex a, Complex b) {

291

double real = a.getReal() * b.getReal() - a.getImaginary() * b.getImaginary();

292

double imaginary = a.getReal() * b.getImaginary() + a.getImaginary() * b.getReal();

293

return new Complex(real, imaginary);

294

}

295

}

296

297

// Server setup

298

CalculatorImpl implementation = new CalculatorImpl();

299

ReflectResponder responder = new ReflectResponder(Calculator.class, implementation);

300

SaslSocketServer server = new SaslSocketServer(responder, new InetSocketAddress(8080));

301

server.start();

302

```

303

304

## Protocol Selection Guidelines

305

306

### Generic Protocol

307

- **Use when**: Maximum flexibility needed, dynamic schema handling, no code generation desired

308

- **Pros**: No code generation, dynamic schemas, schema evolution flexibility

309

- **Cons**: No compile-time type safety, verbose data construction, runtime type checking

310

- **Best for**: Schema registries, generic proxy services, administrative tools

311

312

### Specific Protocol

313

- **Use when**: Strong typing desired, performance important, schemas are stable

314

- **Pros**: Compile-time type safety, best performance, clean API

315

- **Cons**: Requires code generation, schema changes need recompilation

316

- **Best for**: Production services, well-defined APIs, high-performance applications

317

318

### Reflect Protocol

319

- **Use when**: Existing interfaces, no schema/IDL files, rapid prototyping

320

- **Pros**: Works with existing code, no IDL files needed, quick setup

321

- **Cons**: Limited schema evolution, reflection overhead, less optimized

322

- **Best for**: Legacy integration, prototyping, existing Java interfaces

323

324

## Advanced Usage

325

326

### Custom Data Models

327

328

Each protocol implementation allows custom data models for specialized serialization:

329

330

```java

331

// Custom SpecificData with custom serialization

332

SpecificData customData = new SpecificData() {

333

@Override

334

protected Schema createSchema(Type type, Map<String, Schema> names) {

335

// Custom schema creation logic

336

return super.createSchema(type, names);

337

}

338

};

339

340

SpecificRequestor requestor = new SpecificRequestor(MyService.class, transceiver, customData);

341

```

342

343

### Protocol Evolution

344

345

Handle schema evolution gracefully:

346

347

```java

348

// Server supporting multiple protocol versions

349

public class VersionedResponder extends SpecificResponder {

350

public VersionedResponder(Class iface, Object impl) {

351

super(iface, impl);

352

}

353

354

@Override

355

public Object respond(Message message, Object request) throws Exception {

356

Protocol remote = getRemote();

357

String version = remote.getProp("version");

358

359

if ("1.0".equals(version)) {

360

return handleV1Request(message, request);

361

} else if ("2.0".equals(version)) {

362

return handleV2Request(message, request);

363

}

364

365

return super.respond(message, request);

366

}

367

}

368

```

369

370

### Error Handling

371

372

Each protocol implementation provides consistent error handling:

373

374

```java

375

try {

376

String result = client.processData(data);

377

} catch (AvroRemoteException e) {

378

// Application-level exception thrown by remote method

379

if (e.getValue() instanceof ValidationError) {

380

ValidationError validationError = (ValidationError) e.getValue();

381

System.err.println("Validation failed: " + validationError.getMessage());

382

}

383

} catch (IOException e) {

384

// Transport or serialization error

385

System.err.println("Communication error: " + e.getMessage());

386

}

387

```

388

389

### Asynchronous Usage

390

391

All protocol implementations support asynchronous operations:

392

393

```java

394

// Asynchronous call with callback

395

requestor.request("processLargeData", data, new Callback<ProcessingResult>() {

396

@Override

397

public void handleResult(ProcessingResult result) {

398

System.out.println("Processing completed: " + result.getStatus());

399

}

400

401

@Override

402

public void handleError(Throwable error) {

403

System.err.println("Processing failed: " + error.getMessage());

404

}

405

});

406

```

407

408

## Performance Considerations

409

410

### Protocol Performance Characteristics

411

412

1. **Specific Protocol**: Fastest due to optimized serialization and no reflection

413

2. **Generic Protocol**: Moderate performance, schema-based optimizations

414

3. **Reflect Protocol**: Slowest due to reflection overhead

415

416

### Optimization Tips

417

418

```java

419

// Reuse requestor instances

420

SpecificRequestor requestor = new SpecificRequestor(MyService.class, transceiver);

421

// Use same requestor for multiple calls

422

423

// Pre-warm reflection for ReflectRequestor

424

ReflectData reflectData = ReflectData.get();

425

reflectData.getSchema(MyClass.class); // Pre-compute schema

426

427

// Configure data model for performance

428

SpecificData.get().addLogicalTypeConversion(new MyCustomConversion());

429

```