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
```