223 lines · 6.9 KB · Java
RawDownload
/* * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.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 implements 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<Object> OVERFLOW_EVENT =        new Event<Object>(StandardWatchEventKinds.OVERFLOW, null);     /**     * Possible key states     */    private static enum State { READY, SIGNALLED };     // reference to watcher    private final AbstractWatchService watcher;     // reference to the original directory    private final Path dir;     // key state    private State state;     // pending events    private List<WatchEvent<?>> events;     // maps a context to the last event for the context (iff the last queued    // event for the context is an ENTRY_MODIFY event).    private Map<Object,WatchEvent<?>> lastModifyEvents;     protected AbstractWatchKey(Path dir, AbstractWatchService watcher) {        this.watcher = watcher;        this.dir = dir;        this.state = State.READY;        this.events = new ArrayList<WatchEvent<?>>();        this.lastModifyEvents = new HashMap<Object,WatchEvent<?>>();    }     final AbstractWatchService watcher() {        return watcher;    }     /**     * Return the original watchable (Path)     */    @Override    public Path watchable() {        return dir;    }     /**     * 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) {        boolean isModify = (kind == StandardWatchEventKinds.ENTRY_MODIFY);        synchronized (this) {            int size = events.size();            if (size > 0) {                // if the previous event is an OVERFLOW event or this is a                // repeated event then we simply increment the counter                WatchEvent<?> prev = events.get(size-1);                if ((prev.kind() == StandardWatchEventKinds.OVERFLOW) ||                    ((kind == prev.kind() &&                     Objects.equals(context, prev.context()))))                {                    ((Event<?>)prev).increment();                    return;                }                 // if this is a modify event and the last entry for the context                // is a modify event then we simply increment the count                if (!lastModifyEvents.isEmpty()) {                    if (isModify) {                        WatchEvent<?> ev = lastModifyEvents.get(context);                        if (ev != null) {                            assert ev.kind() == StandardWatchEventKinds.ENTRY_MODIFY;                            ((Event<?>)ev).increment();                            return;                        }                    } else {                        // not a modify event so remove from the map as the                        // last event will no longer be a modify event.                        lastModifyEvents.remove(context);                    }                }                 // if the list has reached the limit then drop pending events                // and queue an OVERFLOW event                if (size >= MAX_EVENT_LIST_SIZE) {                    kind = StandardWatchEventKinds.OVERFLOW;                    isModify = false;                    context = null;                }            }             // non-repeated event            Event<Object> ev =                new Event<Object>((WatchEvent.Kind<Object>)kind, context);            if (isModify) {                lastModifyEvents.put(context, ev);            } else if (kind == StandardWatchEventKinds.OVERFLOW) {                // drop all pending events                events.clear();                lastModifyEvents.clear();            }            events.add(ev);            signal();        }    }     @Override    public final List<WatchEvent<?>> pollEvents() {        synchronized (this) {            List<WatchEvent<?>> result = events;            events = new ArrayList<WatchEvent<?>>();            lastModifyEvents.clear();            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> implements 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++;        }    }}