1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.spi.lifecycle;
|
---|
3 |
|
---|
4 | import java.util.List;
|
---|
5 | import java.util.Objects;
|
---|
6 | import java.util.concurrent.ExecutionException;
|
---|
7 | import java.util.concurrent.ExecutorService;
|
---|
8 | import java.util.concurrent.Executors;
|
---|
9 | import java.util.concurrent.Future;
|
---|
10 |
|
---|
11 | import org.openstreetmap.josm.tools.JosmRuntimeException;
|
---|
12 | import org.openstreetmap.josm.tools.Logging;
|
---|
13 | import org.openstreetmap.josm.tools.Utils;
|
---|
14 | import org.openstreetmap.josm.tools.bugreport.BugReport;
|
---|
15 |
|
---|
16 | /**
|
---|
17 | * JOSM lifecycle.
|
---|
18 | * @since 14125
|
---|
19 | */
|
---|
20 | public final class Lifecycle {
|
---|
21 |
|
---|
22 | private static volatile InitStatusListener initStatusListener;
|
---|
23 |
|
---|
24 | private static volatile Runnable shutdownSequence;
|
---|
25 |
|
---|
26 | private Lifecycle() {
|
---|
27 | // Hide constructor
|
---|
28 | }
|
---|
29 |
|
---|
30 | /**
|
---|
31 | * Gets initialization task listener.
|
---|
32 | * @return initialization task listener
|
---|
33 | */
|
---|
34 | public static InitStatusListener getInitStatusListener() {
|
---|
35 | return initStatusListener;
|
---|
36 | }
|
---|
37 |
|
---|
38 | /**
|
---|
39 | * Sets initialization task listener.
|
---|
40 | * @param listener initialization task listener. Must not be null
|
---|
41 | */
|
---|
42 | public static void setInitStatusListener(InitStatusListener listener) {
|
---|
43 | initStatusListener = Objects.requireNonNull(listener);
|
---|
44 | }
|
---|
45 |
|
---|
46 | /**
|
---|
47 | * Gets shutdown sequence.
|
---|
48 | * @return shutdown sequence
|
---|
49 | * @since 14140
|
---|
50 | */
|
---|
51 | public static Runnable getShutdownSequence() {
|
---|
52 | return shutdownSequence;
|
---|
53 | }
|
---|
54 |
|
---|
55 | /**
|
---|
56 | * Sets shutdown sequence.
|
---|
57 | * @param sequence shutdown sequence. Must not be null
|
---|
58 | * @since 14140
|
---|
59 | */
|
---|
60 | public static void setShutdownSequence(Runnable sequence) {
|
---|
61 | shutdownSequence = Objects.requireNonNull(sequence);
|
---|
62 | }
|
---|
63 |
|
---|
64 | /**
|
---|
65 | * Initializes the main object. A lot of global variables are initialized here.
|
---|
66 | * @param initSequence Initialization sequence
|
---|
67 | * @since 14139
|
---|
68 | */
|
---|
69 | public static void initialize(InitializationSequence initSequence) {
|
---|
70 | // Initializes tasks that must be run before parallel tasks
|
---|
71 | runInitializationTasks(initSequence.beforeInitializationTasks());
|
---|
72 |
|
---|
73 | // Initializes tasks to be executed (in parallel) by a ExecutorService
|
---|
74 | try {
|
---|
75 | ExecutorService service = Executors.newFixedThreadPool(
|
---|
76 | Runtime.getRuntime().availableProcessors(), Utils.newThreadFactory("main-init-%d", Thread.NORM_PRIORITY));
|
---|
77 | for (Future<Void> i : service.invokeAll(initSequence.parallelInitializationTasks())) {
|
---|
78 | i.get();
|
---|
79 | }
|
---|
80 | // asynchronous initializations to be completed eventually
|
---|
81 | initSequence.asynchronousRunnableTasks().forEach(service::submit);
|
---|
82 | initSequence.asynchronousCallableTasks().forEach(service::submit);
|
---|
83 | try {
|
---|
84 | service.shutdown();
|
---|
85 | } catch (SecurityException e) {
|
---|
86 | Logging.log(Logging.LEVEL_ERROR, "Unable to shutdown executor service", e);
|
---|
87 | }
|
---|
88 | } catch (InterruptedException | ExecutionException ex) {
|
---|
89 | throw new JosmRuntimeException(ex);
|
---|
90 | }
|
---|
91 |
|
---|
92 | // Initializes tasks that must be run after parallel tasks
|
---|
93 | runInitializationTasks(initSequence.afterInitializationTasks());
|
---|
94 | }
|
---|
95 |
|
---|
96 | private static void runInitializationTasks(List<InitializationTask> tasks) {
|
---|
97 | for (InitializationTask task : tasks) {
|
---|
98 | try {
|
---|
99 | task.call();
|
---|
100 | } catch (JosmRuntimeException e) {
|
---|
101 | // Can happen if the current projection needs NTV2 grid which is not available
|
---|
102 | // In this case we want the user be able to change his projection
|
---|
103 | BugReport.intercept(e).warn();
|
---|
104 | }
|
---|
105 | }
|
---|
106 | }
|
---|
107 |
|
---|
108 | /**
|
---|
109 | * Closes JOSM and optionally terminates the Java Virtual Machine (JVM).
|
---|
110 | * @param exit If {@code true}, the JVM is terminated by running {@link System#exit} with a given return code.
|
---|
111 | * @param exitCode The return code
|
---|
112 | * @return {@code true}
|
---|
113 | * @since 14140
|
---|
114 | */
|
---|
115 | public static boolean exitJosm(boolean exit, int exitCode) {
|
---|
116 | if (shutdownSequence != null) {
|
---|
117 | shutdownSequence.run();
|
---|
118 | }
|
---|
119 |
|
---|
120 | if (exit) {
|
---|
121 | System.exit(exitCode);
|
---|
122 | }
|
---|
123 | return true;
|
---|
124 | }
|
---|
125 | }
|
---|