@@ -35,103 +35,36 @@ various open source licenses (www.opensource.org).
3535package org.berndpruenster.netlayer.tor
3636
3737import java.io.File
38- import java.nio.file.*
38+ import java.security.MessageDigest
3939import java.util.concurrent.TimeUnit
4040
4141/* *
4242 * Watches to see if a particular file is changed
4343 */
4444class NativeWatchObserver (private val fileToWatch : File ) : WriteObserver {
45- private val watchService: WatchService
46- private val key: WatchKey
47- private val lastModified: Long
48- private val length: Long
45+ private var lastDigest: ByteArray
46+
47+ private var messageDigestCreator: MessageDigest
4948
5049 init {
5150 if (! fileToWatch.exists()) {
5251 throw RuntimeException (" $fileToWatch does not exist" )
5352 }
5453
55- lastModified = fileToWatch.lastModified()
56- length = fileToWatch.length()
57-
58- watchService = FileSystems .getDefault().newWatchService()
59- // Note that poll depends on us only registering events that are of current
60- // path
61- if (OsType .current != OsType .MACOS ) {
62- key = fileToWatch.parentFile.toPath().register(watchService,
63- StandardWatchEventKinds .ENTRY_CREATE ,
64- StandardWatchEventKinds .ENTRY_DELETE ,
65- StandardWatchEventKinds .ENTRY_MODIFY )
66- } else {
67- // Unfortunately the default watch service on MACOS is broken, it uses a
68- // separate thread and really slow polling to detect file changes
69- // rather than integrating with the OS. There is a hack to make it poll
70- // faster which we can use for now. See
71- // http://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-else
72- key = fileToWatch.parentFile.toPath().register(watchService,
73- arrayOf(StandardWatchEventKinds .ENTRY_CREATE ,
74- StandardWatchEventKinds .ENTRY_DELETE ,
75- StandardWatchEventKinds .ENTRY_MODIFY ))
76- }
54+ messageDigestCreator = MessageDigest .getInstance(" SHA-256" )
55+ lastDigest = messageDigestCreator.digest(fileToWatch.readBytes())
7756 }
7857
7958 override fun poll (timeout : Long , unit : TimeUnit ): Boolean {
8059 var result = false
81- try {
82- var remainingTimeoutInNanos = unit.toNanos(timeout)
83- while (remainingTimeoutInNanos > 0 ) {
84- val startTimeInNanos = System .nanoTime()
85- val receivedKey = watchService.poll(remainingTimeoutInNanos, TimeUnit .NANOSECONDS )
86- val timeWaitedInNanos = System .nanoTime() - startTimeInNanos
87-
88- if (receivedKey != null ) {
89- if (receivedKey != key) {
90- throw RuntimeException (" This really shouldn't have happened. EEK!" + receivedKey.toString())
91- }
92-
93- for (event in receivedKey.pollEvents()) {
94- val kind = event.kind()
95-
96- if (kind == StandardWatchEventKinds .OVERFLOW ) {
97- logger?.error(" We got an overflow, there shouldn't have been enough activity to make that happen." )
98- }
99-
100- val changedEntry = event.context() as Path
101- if (fileToWatch.toPath().endsWith(changedEntry)) {
102- result = true
103- return result
104- }
105- }
106-
107- // In case we haven't yet gotten the event we are looking for we have
108- // to reset in order to
109- // receive any further notifications.
110- if (! key.reset()) {
111- logger?.error(" The key became invalid which should not have happened." )
112- }
113- }
114-
115- if (timeWaitedInNanos >= remainingTimeoutInNanos) {
116- break
117- }
118-
119- remainingTimeoutInNanos - = timeWaitedInNanos
120- }
121-
122- // Even with the high sensitivity setting above for the MACOS the polling
123- // still misses changes so I've added
124- // a last modified check as a backup. Except I personally witnessed last
125- // modified not returning a new value
126- // value even when I saw the file change!!!! So I'm also adding in a
127- // length check. Java really seems to
128- // have an issue with the OS/X file system.
129- result = (fileToWatch.lastModified() != lastModified) || (fileToWatch.length() != length)
130- return result
131- } finally {
132- if (result) {
133- watchService.close()
134- }
60+ var remaining = unit.toMillis(timeout)
61+ while (remaining > 0 && ! result) {
62+ Thread .sleep(250 )
63+ result = ! lastDigest.contentEquals(messageDigestCreator.digest(fileToWatch.readBytes()))
64+
65+ remaining - = 250
13566 }
67+
68+ return result
13669 }
13770}
0 commit comments