Path: blob/master/src/java.base/share/classes/sun/nio/fs/AbstractWatchKey.java
41159 views
/*1* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.*;28import java.util.*;2930/**31* Base implementation class for watch keys.32*/3334abstract class AbstractWatchKey implements WatchKey {3536/**37* Maximum size of event list (in the future this may be tunable)38*/39static final int MAX_EVENT_LIST_SIZE = 512;4041/**42* Special event to signal overflow43*/44static final Event<Object> OVERFLOW_EVENT =45new Event<Object>(StandardWatchEventKinds.OVERFLOW, null);4647/**48* Possible key states49*/50private static enum State { READY, SIGNALLED };5152// reference to watcher53private final AbstractWatchService watcher;5455// reference to the original directory56private final Path dir;5758// key state59private State state;6061// pending events62private List<WatchEvent<?>> events;6364// maps a context to the last event for the context (iff the last queued65// event for the context is an ENTRY_MODIFY event).66private Map<Object,WatchEvent<?>> lastModifyEvents;6768protected AbstractWatchKey(Path dir, AbstractWatchService watcher) {69this.watcher = watcher;70this.dir = dir;71this.state = State.READY;72this.events = new ArrayList<>();73this.lastModifyEvents = new HashMap<>();74}7576final AbstractWatchService watcher() {77return watcher;78}7980/**81* Return the original watchable (Path)82*/83@Override84public Path watchable() {85return dir;86}8788/**89* Enqueues this key to the watch service90*/91final void signal() {92synchronized (this) {93if (state == State.READY) {94state = State.SIGNALLED;95watcher.enqueueKey(this);96}97}98}99100/**101* Adds the event to this key and signals it.102*/103@SuppressWarnings("unchecked")104final void signalEvent(WatchEvent.Kind<?> kind, Object context) {105boolean isModify = (kind == StandardWatchEventKinds.ENTRY_MODIFY);106synchronized (this) {107int size = events.size();108if (size > 0) {109// if the previous event is an OVERFLOW event or this is a110// repeated event then we simply increment the counter111WatchEvent<?> prev = events.get(size-1);112if ((prev.kind() == StandardWatchEventKinds.OVERFLOW) ||113((kind == prev.kind() &&114Objects.equals(context, prev.context()))))115{116((Event<?>)prev).increment();117return;118}119120// if this is a modify event and the last entry for the context121// is a modify event then we simply increment the count122if (!lastModifyEvents.isEmpty()) {123if (isModify) {124WatchEvent<?> ev = lastModifyEvents.get(context);125if (ev != null) {126assert ev.kind() == StandardWatchEventKinds.ENTRY_MODIFY;127((Event<?>)ev).increment();128return;129}130} else {131// not a modify event so remove from the map as the132// last event will no longer be a modify event.133lastModifyEvents.remove(context);134}135}136137// if the list has reached the limit then drop pending events138// and queue an OVERFLOW event139if (size >= MAX_EVENT_LIST_SIZE) {140kind = StandardWatchEventKinds.OVERFLOW;141isModify = false;142context = null;143}144}145146// non-repeated event147Event<Object> ev =148new Event<>((WatchEvent.Kind<Object>)kind, context);149if (isModify) {150lastModifyEvents.put(context, ev);151} else if (kind == StandardWatchEventKinds.OVERFLOW) {152// drop all pending events153events.clear();154lastModifyEvents.clear();155}156events.add(ev);157signal();158}159}160161@Override162public final List<WatchEvent<?>> pollEvents() {163synchronized (this) {164List<WatchEvent<?>> result = events;165events = new ArrayList<>();166lastModifyEvents.clear();167return result;168}169}170171@Override172public final boolean reset() {173synchronized (this) {174if (state == State.SIGNALLED && isValid()) {175if (events.isEmpty()) {176state = State.READY;177} else {178// pending events so re-queue key179watcher.enqueueKey(this);180}181}182return isValid();183}184}185186/**187* WatchEvent implementation188*/189private static class Event<T> implements WatchEvent<T> {190private final WatchEvent.Kind<T> kind;191private final T context;192193// synchronize on watch key to access/increment count194private int count;195196Event(WatchEvent.Kind<T> type, T context) {197this.kind = type;198this.context = context;199this.count = 1;200}201202@Override203public WatchEvent.Kind<T> kind() {204return kind;205}206207@Override208public T context() {209return context;210}211212@Override213public int count() {214return count;215}216217// for repeated events218void increment() {219count++;220}221}222}223224225