jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java
changeset 2057 3acf8e5e2ca0
child 4667 dd65a1df2231
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.util.*;
+
+/**
+ * Base implementation class for watch keys.
+ */
+
+abstract class AbstractWatchKey extends WatchKey {
+
+    /**
+     * Maximum size of event list (in the future this may be tunable)
+     */
+    static final int MAX_EVENT_LIST_SIZE    = 512;
+
+    /**
+     * Special event to signal overflow
+     */
+    static final Event<Void> OVERFLOW_EVENT =
+        new Event<Void>(StandardWatchEventKind.OVERFLOW, null);
+
+    /**
+     * Possible key states
+     */
+    private static enum State { READY, SIGNALLED };
+
+    // reference to watcher
+    private final AbstractWatchService watcher;
+
+    // key state
+    private State state;
+
+    // pending events
+    private List<WatchEvent<?>> events;
+
+    protected AbstractWatchKey(AbstractWatchService watcher) {
+        this.watcher = watcher;
+        this.state = State.READY;
+        this.events = new ArrayList<WatchEvent<?>>();
+    }
+
+    final AbstractWatchService watcher() {
+        return watcher;
+    }
+
+    /**
+     * Enqueues this key to the watch service
+     */
+    final void signal() {
+        synchronized (this) {
+            if (state == State.READY) {
+                state = State.SIGNALLED;
+                watcher.enqueueKey(this);
+            }
+        }
+    }
+
+    /**
+     * Adds the event to this key and signals it.
+     */
+    @SuppressWarnings("unchecked")
+    final void signalEvent(WatchEvent.Kind<?> kind, Object context) {
+        synchronized (this) {
+            int size = events.size();
+            if (size > 1) {
+                // don't let list get too big
+                if (size >= MAX_EVENT_LIST_SIZE) {
+                    kind = StandardWatchEventKind.OVERFLOW;
+                    context = null;
+                }
+
+                // repeated event
+                WatchEvent<?> prev = events.get(size-1);
+                if (kind == prev.kind()) {
+                    boolean isRepeat;
+                    if (context == null) {
+                        isRepeat = (prev.context() == null);
+                    } else {
+                        isRepeat = context.equals(prev.context());
+                    }
+                    if (isRepeat) {
+                        ((Event<?>)prev).increment();
+                        return;
+                    }
+                }
+            }
+
+            // non-repeated event
+            events.add(new Event<Object>((WatchEvent.Kind<Object>)kind, context));
+            signal();
+        }
+    }
+
+    @Override
+    public final List<WatchEvent<?>> pollEvents() {
+        synchronized (this) {
+            List<WatchEvent<?>> result = events;
+            events = new ArrayList<WatchEvent<?>>();
+            return result;
+        }
+    }
+
+    @Override
+    public final boolean reset() {
+        synchronized (this) {
+            if (state == State.SIGNALLED && isValid()) {
+                if (events.isEmpty()) {
+                    state = State.READY;
+                } else {
+                    // pending events so re-queue key
+                    watcher.enqueueKey(this);
+                }
+            }
+            return isValid();
+        }
+    }
+
+    /**
+     * WatchEvent implementation
+     */
+    private static class Event<T> extends WatchEvent<T> {
+        private final WatchEvent.Kind<T> kind;
+        private final T context;
+
+        // synchronize on watch key to access/increment count
+        private int count;
+
+        Event(WatchEvent.Kind<T> type, T context) {
+            this.kind = type;
+            this.context = context;
+            this.count = 1;
+        }
+
+        @Override
+        public WatchEvent.Kind<T> kind() {
+            return kind;
+        }
+
+        @Override
+        public T context() {
+            return context;
+        }
+
+        @Override
+        public int count() {
+            return count;
+        }
+
+        // for repeated events
+        void increment() {
+            count++;
+        }
+    }
+}