1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.service.daemon;
35
36 import java.util.Collection;
37 import java.util.HashMap;
38 import java.util.Map;
39 import java.util.Random;
40 import java.util.concurrent.TimeUnit;
41
42 import fr.paris.lutece.portal.service.datastore.DatastoreService;
43 import fr.paris.lutece.portal.service.init.LuteceInitException;
44 import fr.paris.lutece.portal.service.spring.SpringContextService;
45 import fr.paris.lutece.portal.service.util.AppLogService;
46 import fr.paris.lutece.portal.service.util.AppPropertiesService;
47
48
49
50
51 public final class AppDaemonService
52 {
53 private static final String PROPERTY_MAX_INITIAL_START_DELAY = "daemon.maxInitialStartDelay";
54 private static final String PROPERTY_DAEMON_ON_STARTUP = ".onStartUp";
55 private static final String PROPERTY_DAEMON_INTERVAL = ".interval";
56 private static final String KEY_DAEMON = "daemon.";
57 private static final String KEY_DAEMON_PREFIX = "core." + KEY_DAEMON;
58 private static final Map<String, DaemonEntry> _mapDaemonEntries = new HashMap<>( );
59 private static final Random _random = new Random( );
60 private static boolean _bInit;
61 private static IDaemonScheduler _executor;
62
63
64 private AppDaemonService( )
65 {
66 }
67
68
69
70
71
72
73
74 public static synchronized void init( )
75 {
76
77 if ( _bInit )
78 {
79 return;
80 }
81
82 _executor = SpringContextService.getBean( IDaemonScheduler.BEAN_NAME );
83
84 if ( _mapDaemonEntries.size( ) > 0 )
85 {
86
87 int nInitialDaemon = 0;
88
89 for ( DaemonEntry entry : _mapDaemonEntries.values( ) )
90 {
91 if ( entry.onStartup( ) )
92 {
93 nInitialDaemon++;
94 }
95 }
96
97 int nDelay = AppPropertiesService.getPropertyInt( PROPERTY_MAX_INITIAL_START_DELAY, 30 );
98
99 if ( nInitialDaemon > 0 )
100 {
101 nDelay = nDelay / nInitialDaemon;
102 }
103
104 int nInitialDelay = 0;
105
106
107 for ( DaemonEntry entry : _mapDaemonEntries.values( ) )
108 {
109
110 if ( entry.onStartup( ) )
111 {
112 nInitialDelay += nDelay;
113
114 scheduleThread( entry, nInitialDelay );
115 }
116 }
117 }
118
119 _bInit = true;
120 }
121
122
123
124
125
126
127
128
129
130 public static void registerDaemon( DaemonEntry entry ) throws LuteceInitException
131 {
132 if ( _mapDaemonEntries.containsKey( entry.getId( ) ) )
133 {
134 AppLogService.error( "Ignoring attempt to register already registered daemon {}", entry.getId( ) );
135 return;
136 }
137 String strIntervalKey = getIntervalKey( entry.getId( ) );
138 String strIntervalKeyDefaultValue = null;
139
140
141 if ( !DatastoreService.existsInstanceKey( strIntervalKey ) )
142 {
143 strIntervalKeyDefaultValue = AppPropertiesService.getProperty( KEY_DAEMON + entry.getId( ) + PROPERTY_DAEMON_INTERVAL, "10" );
144 DatastoreService.setInstanceDataValue( strIntervalKey, strIntervalKeyDefaultValue );
145 }
146
147 String strIntervalKeyValue = DatastoreService.getInstanceDataValue( strIntervalKey, strIntervalKeyDefaultValue );
148
149 long lInterval = Long.parseLong( strIntervalKeyValue );
150
151 String strOnStartupKey = getOnStartupKey( entry.getId( ) );
152 String strOnStartupDefaultValue = null;
153
154
155 if ( !DatastoreService.existsInstanceKey( strOnStartupKey ) )
156 {
157 strOnStartupDefaultValue = AppPropertiesService.getProperty( KEY_DAEMON + entry.getId( ) + ".onstartup", "0" ).equals( "1" )
158 ? DatastoreService.VALUE_TRUE
159 : DatastoreService.VALUE_FALSE;
160 DatastoreService.setInstanceDataValue( strOnStartupKey, strOnStartupDefaultValue );
161 }
162
163 String strOnStarupvalue = DatastoreService.getInstanceDataValue( strOnStartupKey, strOnStartupDefaultValue );
164 boolean bOnStartup = Boolean.parseBoolean( strOnStarupvalue );
165
166 entry.setInterval( lInterval );
167 entry.setOnStartUp( bOnStartup );
168
169 try
170 {
171 entry.loadDaemon( );
172 }
173 catch( IllegalAccessException | InstantiationException | ClassNotFoundException e )
174 {
175 throw new LuteceInitException( "Couldn't instantiate daemon: " + entry.getId( ), e );
176 }
177
178
179 if ( entry.getPluginName( ) != null )
180 {
181 entry.getDaemon( ).setPluginName( entry.getPluginName( ) );
182 }
183
184 _mapDaemonEntries.put( entry.getId( ), entry );
185
186 AppLogService.info( "New Daemon registered : {} ", entry.getId( ) );
187 }
188
189
190
191
192
193
194
195 public static void unregisterDaemon( String strDaemonKey )
196 {
197 unScheduleThread( _mapDaemonEntries.get( strDaemonKey ) );
198 _mapDaemonEntries.remove( strDaemonKey );
199 }
200
201
202
203
204
205
206
207 public static void startDaemon( String strDaemonKey )
208 {
209 scheduleThread( _mapDaemonEntries.get( strDaemonKey ) );
210 }
211
212
213
214
215
216
217
218 public static void stopDaemon( String strDaemonKey )
219 {
220 unScheduleThread( _mapDaemonEntries.get( strDaemonKey ) );
221 }
222
223
224
225
226
227
228
229
230
231
232
233 public static boolean signalDaemon( String strDaemonKey )
234 {
235 return signalDaemon( strDaemonKey, 0L, TimeUnit.MILLISECONDS );
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 public static boolean signalDaemon( String strDaemonKey, long nDelay, TimeUnit unit )
253 {
254 return _executor.enqueue( _mapDaemonEntries.get( strDaemonKey ), nDelay, unit );
255 }
256
257
258
259
260
261
262
263
264
265 public static void modifyDaemonInterval( String strDaemonKey, String strDaemonInterval )
266 {
267 DaemonEntry entry = _mapDaemonEntries.get( strDaemonKey );
268
269 if ( entry != null )
270 {
271 entry.setInterval( Long.valueOf( strDaemonInterval ) );
272 DatastoreService.setInstanceDataValue( getIntervalKey( entry.getId( ) ), strDaemonInterval );
273 }
274 }
275
276
277
278
279
280
281
282 private static void scheduleThread( DaemonEntry entry )
283 {
284 scheduleThread( entry, _random.nextInt( AppPropertiesService.getPropertyInt( PROPERTY_MAX_INITIAL_START_DELAY, 30 ) ) );
285 }
286
287
288
289
290
291
292
293
294
295 private static void scheduleThread( DaemonEntry entry, int nInitialDelay )
296 {
297 AppLogService.info( "Scheduling daemon {} ; first run in {} seconds", entry.getId( ), nInitialDelay );
298 entry.setIsRunning( true );
299 _executor.schedule( entry, nInitialDelay, TimeUnit.SECONDS );
300
301 DatastoreService.setInstanceDataValue( getOnStartupKey( entry.getId( ) ), DatastoreService.VALUE_TRUE );
302 }
303
304
305
306
307
308
309
310 private static void unScheduleThread( DaemonEntry entry )
311 {
312 cancelScheduledThread( entry.getId( ) );
313 entry.setIsRunning( false );
314
315 DatastoreService.setInstanceDataValue( getOnStartupKey( entry.getId( ) ), DatastoreService.VALUE_FALSE );
316 AppLogService.info( "Stopping daemon '{}'", entry.getId( ) );
317 }
318
319
320
321
322
323
324
325 protected static void cancelScheduledThread( String strEntryId )
326 {
327 _executor.unSchedule( _mapDaemonEntries.get( strEntryId ) );
328 }
329
330
331
332
333
334
335 public static Collection<DaemonEntry> getDaemonEntries( )
336 {
337 return _mapDaemonEntries.values( );
338 }
339
340
341
342
343 public static void shutdown( )
344 {
345 _executor.shutdown( );
346 }
347
348
349
350
351
352
353
354
355 public static Daemon getDaemon( String strDaemonKey )
356 {
357 DaemonEntry entry = _mapDaemonEntries.get( strDaemonKey );
358
359 return entry.getDaemon( );
360 }
361
362
363
364
365
366
367
368
369 private static String getOnStartupKey( String strDaemonKey )
370 {
371 return KEY_DAEMON_PREFIX + strDaemonKey + PROPERTY_DAEMON_ON_STARTUP;
372 }
373
374
375
376
377
378
379
380
381 private static String getIntervalKey( String strDaemonKey )
382 {
383 return KEY_DAEMON_PREFIX + strDaemonKey + PROPERTY_DAEMON_INTERVAL;
384 }
385 }