xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/WatchDogService.java (revision c6f0939b1c668e9f8e1e276424439c3106b3a029)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
22  */
23 package org.opengrok.indexer.configuration;
24 
25 import org.opengrok.indexer.logger.LoggerFactory;
26 
27 import java.io.File;
28 import java.io.IOException;
29 import java.nio.file.ClosedWatchServiceException;
30 import java.nio.file.FileSystems;
31 import java.nio.file.FileVisitResult;
32 import java.nio.file.Files;
33 import java.nio.file.Path;
34 import java.nio.file.Paths;
35 import java.nio.file.SimpleFileVisitor;
36 import java.nio.file.WatchEvent;
37 import java.nio.file.WatchKey;
38 import java.nio.file.WatchService;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
41 
42 import static java.nio.file.FileVisitResult.CONTINUE;
43 import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
44 import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
45 import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
46 
47 public class WatchDogService {
48     private static final Logger LOGGER = LoggerFactory.getLogger(WatchDogService.class);
49 
50     private Thread watchDogThread;
51     private WatchService watchDogWatcher;
52     public static final int THREAD_SLEEP_TIME = 2000;
53 
WatchDogService()54     WatchDogService() {
55 
56     }
57 
58     /**
59      * Starts a watch dog service for a directory. It automatically reloads the
60      * AuthorizationFramework if there was a change in <b>real-time</b>.
61      * Suitable for plugin development.
62      *
63      * You can control start of this service by a configuration parameter
64      * {@link Configuration#authorizationWatchdogEnabled}
65      *
66      * @param directory root directory for plugins
67      */
start(File directory)68     public void start(File directory) {
69         stop();
70 
71         if (directory == null || !directory.isDirectory() || !directory.canRead()) {
72             LOGGER.log(Level.INFO, "Watch dog cannot be started - invalid directory: {0}", directory);
73             return;
74         }
75         LOGGER.log(Level.INFO, "Starting watchdog in: {0}", directory);
76         watchDogThread = new Thread(() -> {
77             try {
78                 watchDogWatcher = FileSystems.getDefault().newWatchService();
79                 Path dir = Paths.get(directory.getAbsolutePath());
80 
81                 Files.walkFileTree(dir, new SimpleFileVisitor<>() {
82                     @Override
83                     public FileVisitResult postVisitDirectory(Path d, IOException exc) throws IOException {
84                         // attach monitor
85                         LOGGER.log(Level.FINEST, "Watchdog registering {0}", d);
86                         d.register(watchDogWatcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
87                         return CONTINUE;
88                     }
89                 });
90 
91                 LOGGER.log(Level.INFO, "Watch dog started {0}", directory);
92                 while (!Thread.currentThread().isInterrupted()) {
93                     final WatchKey key;
94                     try {
95                         key = watchDogWatcher.take();
96                     } catch (ClosedWatchServiceException x) {
97                         break;
98                     }
99                     boolean reload = false;
100                     for (WatchEvent<?> event : key.pollEvents()) {
101                         final WatchEvent.Kind<?> kind = event.kind();
102 
103                         if (kind == ENTRY_CREATE || kind == ENTRY_DELETE || kind == ENTRY_MODIFY) {
104                             reload = true;
105                         }
106                     }
107                     if (reload) {
108                         Thread.sleep(THREAD_SLEEP_TIME); // experimental wait if file is being written right now
109                         RuntimeEnvironment.getInstance().getAuthorizationFramework().reload();
110                     }
111                     if (!key.reset()) {
112                         break;
113                     }
114                 }
115             } catch (InterruptedException | IOException ex) {
116                 LOGGER.log(Level.FINEST, "Watchdog finishing (exiting)", ex);
117                 Thread.currentThread().interrupt();
118             }
119             LOGGER.log(Level.FINER, "Watchdog finishing (exiting)");
120         }, "watchDogService");
121         watchDogThread.start();
122     }
123 
124     /**
125      * Stops the watch dog service.
126      */
stop()127     public void stop() {
128         if (watchDogWatcher != null) {
129             try {
130                 watchDogWatcher.close();
131             } catch (IOException ex) {
132                 LOGGER.log(Level.WARNING, "Cannot close WatchDogService: ", ex);
133             }
134         }
135         if (watchDogThread != null) {
136             watchDogThread.interrupt();
137             try {
138                 watchDogThread.join();
139             } catch (InterruptedException ex) {
140                 LOGGER.log(Level.WARNING, "Cannot join WatchDogService thread: ", ex);
141             }
142         }
143         LOGGER.log(Level.INFO, "Watchdog stopped");
144     }
145 }
146