1 /* 2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.fs; 27 28 import java.nio.file.*; 29 import java.util.concurrent.*; 30 import java.io.IOException; 31 32 /** 33 * Base implementation class for watch services. 34 */ 35 36 abstract class AbstractWatchService implements WatchService { 37 38 // signaled keys waiting to be dequeued 39 private final LinkedBlockingDeque<WatchKey> pendingKeys = 40 new LinkedBlockingDeque<WatchKey>(); 41 42 // special key to indicate that watch service is closed 43 private final WatchKey CLOSE_KEY = 44 new AbstractWatchKey(null, null) { 45 @Override 46 public boolean isValid() { 47 return true; 48 } 49 50 @Override 51 public void cancel() { 52 } 53 }; 54 55 // used when closing watch service 56 private volatile boolean closed; 57 private final Object closeLock = new Object(); 58 AbstractWatchService()59 protected AbstractWatchService() { 60 } 61 62 /** 63 * Register the given object with this watch service 64 */ register(Path path, WatchEvent.Kind<?>[] events, WatchEvent.Modifier... modifers)65 abstract WatchKey register(Path path, 66 WatchEvent.Kind<?>[] events, 67 WatchEvent.Modifier... modifers) 68 throws IOException; 69 70 // used by AbstractWatchKey to enqueue key enqueueKey(WatchKey key)71 final void enqueueKey(WatchKey key) { 72 pendingKeys.offer(key); 73 } 74 75 /** 76 * Throws ClosedWatchServiceException if watch service is closed 77 */ checkOpen()78 private void checkOpen() { 79 if (closed) 80 throw new ClosedWatchServiceException(); 81 } 82 83 /** 84 * Checks the key isn't the special CLOSE_KEY used to unblock threads when 85 * the watch service is closed. 86 */ checkKey(WatchKey key)87 private void checkKey(WatchKey key) { 88 if (key == CLOSE_KEY) { 89 // re-queue in case there are other threads blocked in take/poll 90 enqueueKey(key); 91 } 92 checkOpen(); 93 } 94 95 @Override poll()96 public final WatchKey poll() { 97 checkOpen(); 98 WatchKey key = pendingKeys.poll(); 99 checkKey(key); 100 return key; 101 } 102 103 @Override poll(long timeout, TimeUnit unit)104 public final WatchKey poll(long timeout, TimeUnit unit) 105 throws InterruptedException 106 { 107 checkOpen(); 108 WatchKey key = pendingKeys.poll(timeout, unit); 109 checkKey(key); 110 return key; 111 } 112 113 @Override take()114 public final WatchKey take() 115 throws InterruptedException 116 { 117 checkOpen(); 118 WatchKey key = pendingKeys.take(); 119 checkKey(key); 120 return key; 121 } 122 123 /** 124 * Tells whether or not this watch service is open. 125 */ isOpen()126 final boolean isOpen() { 127 return !closed; 128 } 129 130 /** 131 * Retrieves the object upon which the close method synchronizes. 132 */ closeLock()133 final Object closeLock() { 134 return closeLock; 135 } 136 137 /** 138 * Closes this watch service. This method is invoked by the close 139 * method to perform the actual work of closing the watch service. 140 */ implClose()141 abstract void implClose() throws IOException; 142 143 @Override close()144 public final void close() 145 throws IOException 146 { 147 synchronized (closeLock) { 148 // nothing to do if already closed 149 if (closed) 150 return; 151 closed = true; 152 153 implClose(); 154 155 // clear pending keys and queue special key to ensure that any 156 // threads blocked in take/poll wakeup 157 pendingKeys.clear(); 158 pendingKeys.offer(CLOSE_KEY); 159 } 160 } 161 } 162