blob: 8e33f81ed8431c38fce563d0771b59580bb6716f [file] [log] [blame]
/*
* 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++;
}
}
}