0
# Service Programs
1
2
Service programs in CDAP provide long-running services including HTTP APIs, custom protocols, and background processing services with built-in lifecycle management and resource allocation.
3
4
## Core Service Interfaces
5
6
### Service
7
8
```java { .api }
9
public interface Service extends ProgramLifecycle<ServiceContext> {
10
void configure(ServiceConfigurer configurer);
11
}
12
```
13
14
Base interface for service programs providing configuration and lifecycle hooks.
15
16
### AbstractService
17
18
```java { .api }
19
public abstract class AbstractService implements Service {
20
public abstract void configure(ServiceConfigurer configurer);
21
22
@Override
23
public void initialize(ServiceContext context) throws Exception {
24
// Optional initialization logic
25
}
26
27
@Override
28
public void destroy() {
29
// Optional cleanup logic
30
}
31
}
32
```
33
34
Base implementation class for service programs.
35
36
### BasicService
37
38
```java { .api }
39
public class BasicService extends AbstractService {
40
private final HttpServiceHandler[] handlers;
41
42
public BasicService(HttpServiceHandler... handlers);
43
public BasicService(String name, HttpServiceHandler... handlers);
44
45
@Override
46
public void configure(ServiceConfigurer configurer);
47
}
48
```
49
50
Simple service implementation for HTTP handlers.
51
52
## HTTP Services
53
54
### HttpServiceHandler
55
56
```java { .api }
57
public interface HttpServiceHandler {
58
void initialize(HttpServiceContext context) throws Exception;
59
void destroy();
60
}
61
```
62
63
Base interface for HTTP request handlers.
64
65
### AbstractHttpServiceHandler
66
67
```java { .api }
68
public abstract class AbstractHttpServiceHandler implements HttpServiceHandler {
69
@Override
70
public void initialize(HttpServiceContext context) throws Exception {
71
// Optional initialization
72
}
73
74
@Override
75
public void destroy() {
76
// Optional cleanup
77
}
78
}
79
```
80
81
Base implementation for HTTP service handlers with annotation-based request mapping.
82
83
### HTTP Request and Response
84
85
```java { .api }
86
public class HttpServiceRequest {
87
public String getMethod();
88
public String getUri();
89
public Map<String, List<String>> getAllHeaders();
90
public String getHeader(String name);
91
public Map<String, String> getHeaders();
92
93
public ByteBuffer getContent();
94
public String getContentAsString();
95
public <T> T getContent(Type type);
96
}
97
98
public interface HttpServiceResponder {
99
void sendJson(int status, Object object);
100
void sendJson(Object object);
101
void sendString(int status, String data, Charset charset);
102
void sendString(String data);
103
void sendStatus(int status);
104
void sendError(int status, String errorMessage);
105
106
void send(int status, ByteBuffer content, String contentType);
107
void send(ByteBuffer content, String contentType);
108
109
ChunkResponder sendChunkStart(int status, Map<String, String> headers);
110
}
111
```
112
113
HTTP request and response handling interfaces.
114
115
### Content Handling
116
117
```java { .api }
118
public interface HttpContentConsumer {
119
void onReceived(ByteBuffer chunk, Transactional transactional) throws Exception;
120
void onFinish(HttpServiceResponder responder) throws Exception;
121
void onError(HttpServiceResponder responder, Throwable failureCause);
122
}
123
124
public interface HttpContentProducer {
125
ByteBuffer nextChunk(Transactional transactional) throws Exception;
126
void onFinish() throws Exception;
127
void onError(Throwable failureCause);
128
}
129
```
130
131
Interfaces for handling large request/response bodies with streaming support.
132
133
## Service Configuration
134
135
### ServiceConfigurer
136
137
```java { .api }
138
public interface ServiceConfigurer extends ProgramConfigurer, DatasetConfigurer, PluginConfigurer {
139
void addHandler(HttpServiceHandler handler);
140
void setInstances(int instances);
141
void setResources(Resources resources);
142
}
143
```
144
145
Interface for configuring service programs.
146
147
### HttpServiceConfigurer
148
149
```java { .api }
150
public interface HttpServiceConfigurer {
151
void setName(String name);
152
void setDescription(String description);
153
void setProperties(Map<String, String> properties);
154
void setResources(Resources resources);
155
}
156
```
157
158
Configuration interface for HTTP service handlers.
159
160
## Service Context
161
162
### ServiceContext
163
164
```java { .api }
165
public interface ServiceContext extends RuntimeContext, DatasetContext, ServiceDiscoverer {
166
int getInstanceCount();
167
int getInstanceId();
168
Map<String, String> getRuntimeArguments();
169
170
PluginContext getPluginContext();
171
Metrics getMetrics();
172
Admin getAdmin();
173
}
174
```
175
176
Runtime context for service programs.
177
178
### HttpServiceContext
179
180
```java { .api }
181
public interface HttpServiceContext extends ServiceContext {
182
HttpServiceHandlerSpecification getSpecification();
183
int getInstanceCount();
184
int getInstanceId();
185
}
186
```
187
188
HTTP-specific service context providing handler metadata.
189
190
## Usage Examples
191
192
### Basic HTTP Service
193
194
```java
195
public class UserService extends AbstractService {
196
197
@Override
198
public void configure(ServiceConfigurer configurer) {
199
configurer.setName("UserService");
200
configurer.setDescription("REST API for user management");
201
configurer.addHandler(new UserHandler());
202
configurer.setInstances(2);
203
configurer.setResources(new Resources(1024)); // 1GB memory
204
configurer.useDataset("users");
205
}
206
}
207
208
public class UserHandler extends AbstractHttpServiceHandler {
209
210
@UseDataSet("users")
211
private ObjectStore<User> userStore;
212
213
@GET
214
@Path("/users/{id}")
215
public void getUser(HttpServiceRequest request, HttpServiceResponder responder,
216
@PathParam("id") String userId) {
217
218
try {
219
User user = userStore.read(userId);
220
if (user != null) {
221
responder.sendJson(user);
222
} else {
223
responder.sendError(404, "User not found");
224
}
225
} catch (Exception e) {
226
responder.sendError(500, "Internal server error");
227
}
228
}
229
230
@POST
231
@Path("/users")
232
public void createUser(HttpServiceRequest request, HttpServiceResponder responder) {
233
234
try {
235
User user = request.getContent(User.class);
236
userStore.write(user.getId(), user);
237
responder.sendJson(201, user);
238
} catch (Exception e) {
239
responder.sendError(400, "Invalid user data");
240
}
241
}
242
243
@PUT
244
@Path("/users/{id}")
245
public void updateUser(HttpServiceRequest request, HttpServiceResponder responder,
246
@PathParam("id") String userId) {
247
248
try {
249
User existingUser = userStore.read(userId);
250
if (existingUser == null) {
251
responder.sendError(404, "User not found");
252
return;
253
}
254
255
User updatedUser = request.getContent(User.class);
256
updatedUser.setId(userId);
257
userStore.write(userId, updatedUser);
258
responder.sendJson(updatedUser);
259
} catch (Exception e) {
260
responder.sendError(500, "Update failed");
261
}
262
}
263
264
@DELETE
265
@Path("/users/{id}")
266
public void deleteUser(HttpServiceRequest request, HttpServiceResponder responder,
267
@PathParam("id") String userId) {
268
269
try {
270
User user = userStore.read(userId);
271
if (user != null) {
272
userStore.delete(userId);
273
responder.sendStatus(204);
274
} else {
275
responder.sendError(404, "User not found");
276
}
277
} catch (Exception e) {
278
responder.sendError(500, "Delete failed");
279
}
280
}
281
}
282
```
283
284
### Service with Large Content Handling
285
286
```java
287
public class FileUploadHandler extends AbstractHttpServiceHandler {
288
289
@UseDataSet("files")
290
private FileSet fileStorage;
291
292
@POST
293
@Path("/upload/{filename}")
294
public HttpContentConsumer upload(@PathParam("filename") String filename) {
295
296
return new HttpContentConsumer() {
297
private OutputStream outputStream;
298
private Location fileLocation;
299
300
@Override
301
public void onReceived(ByteBuffer chunk, Transactional transactional) throws Exception {
302
if (outputStream == null) {
303
fileLocation = fileStorage.getLocation(filename);
304
outputStream = fileLocation.getOutputStream();
305
}
306
307
byte[] bytes = new byte[chunk.remaining()];
308
chunk.get(bytes);
309
outputStream.write(bytes);
310
}
311
312
@Override
313
public void onFinish(HttpServiceResponder responder) throws Exception {
314
if (outputStream != null) {
315
outputStream.close();
316
}
317
318
responder.sendJson(200, Collections.singletonMap("status", "uploaded"));
319
}
320
321
@Override
322
public void onError(HttpServiceResponder responder, Throwable failureCause) {
323
try {
324
if (outputStream != null) {
325
outputStream.close();
326
}
327
if (fileLocation != null) {
328
fileLocation.delete();
329
}
330
} catch (IOException e) {
331
// Log error
332
}
333
334
responder.sendError(500, "Upload failed: " + failureCause.getMessage());
335
}
336
};
337
}
338
339
@GET
340
@Path("/download/{filename}")
341
public HttpContentProducer download(@PathParam("filename") String filename,
342
HttpServiceResponder responder) throws IOException {
343
344
Location fileLocation = fileStorage.getLocation(filename);
345
if (!fileLocation.exists()) {
346
responder.sendError(404, "File not found");
347
return null;
348
}
349
350
return new HttpContentProducer() {
351
private InputStream inputStream = fileLocation.getInputStream();
352
private final byte[] buffer = new byte[8192];
353
354
@Override
355
public ByteBuffer nextChunk(Transactional transactional) throws Exception {
356
int bytesRead = inputStream.read(buffer);
357
if (bytesRead == -1) {
358
return null; // End of file
359
}
360
361
return ByteBuffer.wrap(buffer, 0, bytesRead);
362
}
363
364
@Override
365
public void onFinish() throws Exception {
366
inputStream.close();
367
}
368
369
@Override
370
public void onError(Throwable failureCause) {
371
try {
372
inputStream.close();
373
} catch (IOException e) {
374
// Log error
375
}
376
}
377
};
378
}
379
}
380
```
381
382
### Service with Plugin Integration
383
384
```java
385
public class ProcessingService extends AbstractService {
386
387
@Override
388
public void configure(ServiceConfigurer configurer) {
389
configurer.setName("ProcessingService");
390
configurer.addHandler(new ProcessingHandler());
391
392
// Use transformation plugin
393
configurer.usePlugin("transform", "dataTransform", "transformer",
394
PluginProperties.builder()
395
.add("operation", "normalize")
396
.build());
397
}
398
}
399
400
public class ProcessingHandler extends AbstractHttpServiceHandler {
401
402
@UseDataSet("inputData")
403
private ObjectStore<DataRecord> inputStore;
404
405
@UseDataSet("outputData")
406
private ObjectStore<DataRecord> outputStore;
407
408
private DataTransformer transformer;
409
410
@Override
411
public void initialize(HttpServiceContext context) throws Exception {
412
super.initialize(context);
413
transformer = context.getPluginContext().newPluginInstance("transformer");
414
}
415
416
@POST
417
@Path("/process/{recordId}")
418
public void processRecord(HttpServiceRequest request, HttpServiceResponder responder,
419
@PathParam("recordId") String recordId) {
420
421
try {
422
DataRecord input = inputStore.read(recordId);
423
if (input == null) {
424
responder.sendError(404, "Record not found");
425
return;
426
}
427
428
DataRecord processed = transformer.transform(input);
429
outputStore.write(recordId, processed);
430
431
responder.sendJson(Collections.singletonMap("status", "processed"));
432
} catch (Exception e) {
433
responder.sendError(500, "Processing failed: " + e.getMessage());
434
}
435
}
436
}
437
```
438
439
### Multi-Handler Service
440
441
```java
442
public class APIGatewayService extends AbstractService {
443
444
@Override
445
public void configure(ServiceConfigurer configurer) {
446
configurer.setName("APIGateway");
447
configurer.setDescription("Unified API gateway service");
448
449
// Add multiple handlers for different API areas
450
configurer.addHandler(new UserHandler());
451
configurer.addHandler(new ProductHandler());
452
configurer.addHandler(new OrderHandler());
453
configurer.addHandler(new AuthHandler());
454
455
configurer.setInstances(3);
456
configurer.setResources(new Resources(2048, 2)); // 2GB, 2 cores
457
458
// Use common datasets
459
configurer.useDataset("users");
460
configurer.useDataset("products");
461
configurer.useDataset("orders");
462
configurer.useDataset("sessions");
463
}
464
}
465
```
466
467
Service programs provide the foundation for building REST APIs, real-time data processing endpoints, and custom protocol handlers within the CDAP platform.