001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.ui.operations;
016:
017: import java.util.Map;
018: import java.util.WeakHashMap;
019: import java.util.concurrent.ExecutorService;
020: import java.util.concurrent.Executors;
021: import java.util.concurrent.locks.Lock;
022: import java.util.concurrent.locks.ReentrantLock;
023:
024: import net.refractions.udig.internal.ui.UiPlugin;
025:
026: /**
027: * A non-blocking version of the LazyOpFilter. Returns false first then calculates whether it is in
028: * fact false or true in a seperate thread and notifies the listeners of the actual state.
029: *
030: * @author Jesse
031: * @since 1.1.0
032: */
033: public class LazyOpFilter implements OpFilter {
034:
035: private final OpFilter opFilter;
036: private final ILazyOpListener listener;
037: private Worker worker;
038: final Map<Object, Boolean> cache = new WeakHashMap<Object, Boolean>();
039: final boolean blocking, caching;
040: final Lock lock = new ReentrantLock();
041:
042: private IOpFilterListener changeListener = new IOpFilterListener() {
043:
044: public void notifyChange(Object changed) {
045: boolean notify = false;
046: boolean newResult = false;
047:
048: lock.lock();
049: try {
050: if (!enabled) {
051: UiPlugin
052: .log(
053: "Warning listener called even though not enabled", new Exception()); //$NON-NLS-1$
054: return;
055: }
056: Boolean removed = cache.get(changed);
057: if (removed != null) {
058: cache.remove(changed);
059: if (listener != null) {
060: newResult = acceptInternal(changed, removed);
061: if (newResult != removed.booleanValue())
062: notify = true;
063: }
064: }
065: } finally {
066: lock.unlock();
067: }
068: if (notify)
069: listener.notifyResultObtained(newResult);
070: }
071:
072: };
073: private boolean enabled;
074:
075: private static final ExecutorService executor = Executors
076: .newSingleThreadExecutor();
077: public static final boolean DEFAULT_RETURN_VALUE = true;
078:
079: public LazyOpFilter(final ILazyOpListener listener,
080: final OpFilter opFilter) {
081: this .listener = listener;
082: this .opFilter = opFilter;
083:
084: caching = opFilter.canCacheResult();
085:
086: blocking = opFilter.isBlocking();
087: enabled = false;
088: }
089:
090: public boolean accept(final Object object) {
091: lock.lock();
092: try {
093: if (!enabled) {
094: enabled = true;
095: opFilter.addListener(changeListener);
096: }
097: return acceptInternal(object, DEFAULT_RETURN_VALUE);
098: } finally {
099: lock.unlock();
100: }
101: }
102:
103: private boolean acceptInternal(final Object object,
104: boolean defaultReturnValue) {
105: if (worker != null) {
106: worker.cancel();
107: }
108:
109: Boolean result = cache.get(object);
110: if (result != null && caching)
111: return result;
112:
113: if (result == null)
114: result = defaultReturnValue;
115:
116: if (blocking) {
117: worker = new Worker(object);
118: executor.submit(worker);
119: } else {
120: result = opFilter.accept(object);
121: cache.put(object, result);
122: }
123:
124: return result;
125: }
126:
127: private class Worker implements Runnable {
128: private final Object object;
129: private volatile boolean cancelled;
130:
131: public Worker(final Object object) {
132: this .object = object;
133: cancelled = false;
134: }
135:
136: public void cancel() {
137: cancelled = true;
138: }
139:
140: public void run() {
141: boolean result;
142: synchronized (LazyOpFilter.this ) {
143: result = opFilter.accept(object);
144: cache.put(object, result);
145: }
146: if (!cancelled) {
147: listener.notifyResultObtained(result);
148: }
149: }
150:
151: }
152:
153: public void addListener(IOpFilterListener listener) {
154: throw new UnsupportedOperationException();
155: }
156:
157: public boolean canCacheResult() {
158: throw new UnsupportedOperationException();
159: }
160:
161: public boolean isBlocking() {
162: throw new UnsupportedOperationException();
163: }
164:
165: public void removeListener(IOpFilterListener listener) {
166: throw new UnsupportedOperationException();
167: }
168:
169: public void disable() {
170: lock.lock();
171: try {
172: enabled = false;
173: opFilter.removeListener(changeListener);
174: } finally {
175: lock.unlock();
176: }
177: }
178:
179: }
|