0
# JAR Location and Executor Services
1
2
Utilities for JAR metadata extraction and direct task execution capabilities.
3
4
## JarLocation Class
5
6
The `JarLocation` class encapsulates the location on the local filesystem of the JAR file in which code is executing and provides access to JAR metadata.
7
8
### Constructor
9
10
```java { .api }
11
public JarLocation(Class<?> klass);
12
```
13
14
Constructs a new JarLocation object to access the code source for the specified class.
15
16
**Parameters:**
17
- `klass` - The class to access the code source from
18
19
### Version Information
20
21
```java { .api }
22
public Optional<String> getVersion();
23
```
24
25
Returns the version of the JAR file containing the provided class.
26
27
**Returns:** An `Optional<String>` containing the implementation version from the JAR manifest, or empty if not available
28
29
**Implementation Details:**
30
- Retrieves version from `Package.getImplementationVersion()`
31
- Returns empty Optional if package information is not available
32
- Version information comes from JAR manifest `Implementation-Version` attribute
33
34
### JAR File Name
35
36
```java { .api }
37
public String toString();
38
```
39
40
Returns the name of the JAR file containing the class.
41
42
**Returns:**
43
- The JAR file name if the class is loaded from a JAR file
44
- `"project.jar"` as a fallback if the JAR name cannot be determined or if running from non-JAR sources (e.g., IDE, exploded directories)
45
46
### Usage Examples
47
48
#### Basic JAR Information
49
50
```java
51
import io.dropwizard.util.JarLocation;
52
import java.util.Optional;
53
54
// Get information about the current application's JAR
55
JarLocation appLocation = new JarLocation(MyApplication.class);
56
String jarName = appLocation.toString();
57
Optional<String> version = appLocation.getVersion();
58
59
System.out.println("Running from JAR: " + jarName);
60
if (version.isPresent()) {
61
System.out.println("Version: " + version.get());
62
} else {
63
System.out.println("Version information not available");
64
}
65
```
66
67
#### Application Startup Information
68
69
```java
70
public class ApplicationInfo {
71
private final JarLocation location;
72
private final String applicationName;
73
74
public ApplicationInfo(Class<?> mainClass, String applicationName) {
75
this.location = new JarLocation(mainClass);
76
this.applicationName = applicationName;
77
}
78
79
public void printStartupInfo() {
80
System.out.println("=== " + applicationName + " ===");
81
System.out.println("JAR: " + location.toString());
82
83
Optional<String> version = location.getVersion();
84
if (version.isPresent()) {
85
System.out.println("Version: " + version.get());
86
} else {
87
System.out.println("Version: Development");
88
}
89
90
System.out.println("Java: " + System.getProperty("java.version"));
91
System.out.println("Started at: " + new java.util.Date());
92
}
93
}
94
95
// Usage in main method
96
public class MyApplication {
97
public static void main(String[] args) {
98
ApplicationInfo info = new ApplicationInfo(MyApplication.class, "My Service");
99
info.printStartupInfo();
100
101
// Continue with application startup...
102
}
103
}
104
```
105
106
#### Health Check Integration
107
108
```java
109
public class ApplicationHealthCheck {
110
private final JarLocation jarLocation;
111
112
public ApplicationHealthCheck(Class<?> applicationClass) {
113
this.jarLocation = new JarLocation(applicationClass);
114
}
115
116
public Map<String, Object> getHealthInfo() {
117
Map<String, Object> health = new HashMap<>();
118
health.put("status", "UP");
119
health.put("jar", jarLocation.toString());
120
121
Optional<String> version = jarLocation.getVersion();
122
health.put("version", version.orElse("unknown"));
123
124
return health;
125
}
126
}
127
```
128
129
#### Logging and Monitoring
130
131
```java
132
public class ApplicationMetrics {
133
private static final Logger logger = LoggerFactory.getLogger(ApplicationMetrics.class);
134
135
public static void logApplicationStart(Class<?> mainClass) {
136
JarLocation location = new JarLocation(mainClass);
137
138
logger.info("Application starting - JAR: {}, Version: {}",
139
location.toString(),
140
location.getVersion().orElse("development"));
141
142
// Send metrics to monitoring system
143
sendMetric("app.start", Map.of(
144
"jar", location.toString(),
145
"version", location.getVersion().orElse("dev")
146
));
147
}
148
}
149
```
150
151
## DirectExecutorService Class
152
153
The `DirectExecutorService` is an implementation of `ExecutorService` that directly executes tasks on the calling thread if the service has not been shut down.
154
155
### Constructor
156
157
```java { .api }
158
public DirectExecutorService();
159
```
160
161
Creates a new DirectExecutorService instance.
162
163
### Execution Methods
164
165
```java { .api }
166
public void execute(Runnable command);
167
```
168
169
Executes the given command directly on the calling thread.
170
171
**Parameters:**
172
- `command` - The runnable task to execute
173
174
**Throws:**
175
- `RejectedExecutionException` - If the executor has been shut down
176
177
**Behavior:**
178
- Executes the task immediately on the calling thread
179
- Tracks running tasks for proper shutdown behavior
180
- Rejects new tasks if the executor has been shut down
181
182
### Lifecycle Methods
183
184
```java { .api }
185
public void shutdown();
186
public List<Runnable> shutdownNow();
187
public boolean isShutdown();
188
public boolean isTerminated();
189
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
190
```
191
192
**shutdown()**: Initiates an orderly shutdown where previously submitted tasks continue to execute, but no new tasks are accepted.
193
194
**shutdownNow()**: Attempts to stop all actively executing tasks and returns an empty list (since tasks execute immediately, there are no queued tasks to return).
195
196
**isShutdown()**: Returns `true` if this executor has been shut down.
197
198
**isTerminated()**: Returns `true` if all tasks have completed following shut down and no tasks are currently running.
199
200
**awaitTermination()**: Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted.
201
202
### Usage Examples
203
204
#### Basic Task Execution
205
206
```java
207
import io.dropwizard.util.DirectExecutorService;
208
import java.util.concurrent.ExecutorService;
209
210
// Create executor
211
ExecutorService executor = new DirectExecutorService();
212
213
// Execute tasks (runs immediately on calling thread)
214
executor.execute(() -> System.out.println("Task 1 executed"));
215
executor.execute(() -> System.out.println("Task 2 executed"));
216
executor.execute(() -> {
217
System.out.println("Task 3 starting");
218
// Some work...
219
System.out.println("Task 3 completed");
220
});
221
222
// Output appears immediately as tasks execute on calling thread
223
// Shutdown when done
224
executor.shutdown();
225
```
226
227
#### Testing and Synchronous Execution
228
229
```java
230
public class TaskProcessor {
231
private final ExecutorService executor;
232
233
public TaskProcessor(ExecutorService executor) {
234
this.executor = executor;
235
}
236
237
public void processItems(List<String> items) {
238
for (String item : items) {
239
executor.execute(() -> processItem(item));
240
}
241
}
242
243
private void processItem(String item) {
244
// Process the item
245
System.out.println("Processing: " + item);
246
}
247
}
248
249
// In tests, use DirectExecutorService for synchronous execution
250
@Test
251
public void testProcessItems() {
252
DirectExecutorService directExecutor = new DirectExecutorService();
253
TaskProcessor processor = new TaskProcessor(directExecutor);
254
255
List<String> items = Arrays.asList("item1", "item2", "item3");
256
processor.processItems(items);
257
258
// All tasks have completed synchronously by this point
259
// No need to wait for async completion in tests
260
261
directExecutor.shutdown();
262
}
263
264
// In production, use a proper thread pool
265
@Component
266
public class ProductionTaskProcessor {
267
@Bean
268
public TaskProcessor taskProcessor() {
269
ExecutorService threadPool = Executors.newFixedThreadPool(10);
270
return new TaskProcessor(threadPool);
271
}
272
}
273
```
274
275
#### Configuration-Driven Executor Selection
276
277
```java
278
public class ExecutorFactory {
279
public enum ExecutionMode {
280
DIRECT, // Use DirectExecutorService
281
ASYNC, // Use thread pool
282
FORK_JOIN // Use ForkJoinPool
283
}
284
285
public ExecutorService createExecutor(ExecutionMode mode, int threadCount) {
286
switch (mode) {
287
case DIRECT:
288
return new DirectExecutorService();
289
case ASYNC:
290
return Executors.newFixedThreadPool(threadCount);
291
case FORK_JOIN:
292
return new ForkJoinPool(threadCount);
293
default:
294
throw new IllegalArgumentException("Unknown execution mode: " + mode);
295
}
296
}
297
}
298
299
// Usage in configuration
300
public class ServiceConfiguration {
301
private ExecutionMode executionMode = ExecutionMode.ASYNC;
302
private int threadCount = 10;
303
304
public ExecutorService createExecutor() {
305
ExecutorFactory factory = new ExecutorFactory();
306
return factory.createExecutor(executionMode, threadCount);
307
}
308
}
309
```
310
311
#### Graceful Shutdown
312
313
```java
314
public class ManagedExecutorService {
315
private final DirectExecutorService executor;
316
private volatile boolean shutdownRequested = false;
317
318
public ManagedExecutorService() {
319
this.executor = new DirectExecutorService();
320
}
321
322
public void executeTask(Runnable task) {
323
if (shutdownRequested) {
324
throw new IllegalStateException("Service is shutting down");
325
}
326
327
executor.execute(task);
328
}
329
330
public void shutdown() {
331
shutdownRequested = true;
332
executor.shutdown();
333
}
334
335
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
336
return executor.awaitTermination(timeout, unit);
337
}
338
339
public void shutdownAndWait(long timeoutSeconds) {
340
shutdown();
341
342
try {
343
boolean terminated = awaitTermination(timeoutSeconds, TimeUnit.SECONDS);
344
if (!terminated) {
345
System.err.println("Executor did not terminate within " + timeoutSeconds + " seconds");
346
executor.shutdownNow();
347
}
348
} catch (InterruptedException e) {
349
Thread.currentThread().interrupt();
350
executor.shutdownNow();
351
}
352
}
353
}
354
```
355
356
#### Development vs Production Patterns
357
358
```java
359
public class ServiceManager {
360
private final ExecutorService executor;
361
private final boolean isDevelopment;
362
363
public ServiceManager(boolean isDevelopment) {
364
this.isDevelopment = isDevelopment;
365
366
if (isDevelopment) {
367
// Use DirectExecutorService for easier debugging
368
this.executor = new DirectExecutorService();
369
} else {
370
// Use proper thread pool for production
371
this.executor = Executors.newCachedThreadPool();
372
}
373
}
374
375
public void submitTask(Runnable task) {
376
executor.execute(task);
377
}
378
379
public void shutdown() {
380
executor.shutdown();
381
382
if (!isDevelopment) {
383
// Only need to wait for async executors
384
try {
385
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
386
executor.shutdownNow();
387
}
388
} catch (InterruptedException e) {
389
executor.shutdownNow();
390
Thread.currentThread().interrupt();
391
}
392
}
393
}
394
}
395
```
396
397
## Integration Patterns
398
399
### JAR Location in Dropwizard Applications
400
401
```java
402
public class DropwizardApplication extends Application<MyConfiguration> {
403
404
@Override
405
public void run(MyConfiguration configuration, Environment environment) throws Exception {
406
// Log application info at startup
407
JarLocation location = new JarLocation(getClass());
408
log.info("Starting {} from JAR: {}, Version: {}",
409
getName(),
410
location.toString(),
411
location.getVersion().orElse("development"));
412
413
// Add version info to health checks
414
environment.healthChecks().register("version", new HealthCheck() {
415
@Override
416
protected Result check() throws Exception {
417
return Result.healthy("Version: " + location.getVersion().orElse("dev"));
418
}
419
});
420
421
// Add version endpoint
422
environment.jersey().register(new VersionResource(location));
423
}
424
}
425
426
@Path("/version")
427
public class VersionResource {
428
private final JarLocation jarLocation;
429
430
public VersionResource(JarLocation jarLocation) {
431
this.jarLocation = jarLocation;
432
}
433
434
@GET
435
public Map<String, String> getVersion() {
436
return Map.of(
437
"jar", jarLocation.toString(),
438
"version", jarLocation.getVersion().orElse("development")
439
);
440
}
441
}
442
```
443
444
### DirectExecutorService in Testing Framework
445
446
```java
447
public class TestExecutorExtension implements BeforeEachCallback, AfterEachCallback {
448
private DirectExecutorService executor;
449
450
@Override
451
public void beforeEach(ExtensionContext context) {
452
executor = new DirectExecutorService();
453
// Store in test context for injection
454
context.getStore(ExtensionContext.Namespace.GLOBAL)
455
.put("executor", executor);
456
}
457
458
@Override
459
public void afterEach(ExtensionContext context) {
460
if (executor != null) {
461
executor.shutdown();
462
}
463
}
464
465
public static DirectExecutorService getExecutor(ExtensionContext context) {
466
return context.getStore(ExtensionContext.Namespace.GLOBAL)
467
.get("executor", DirectExecutorService.class);
468
}
469
}
470
```