/* * 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++; } }}
/*
* 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++;
}
}
}