diff options
author | Eike Stepper | 2006-10-22 07:32:35 +0000 |
---|---|---|
committer | Eike Stepper | 2006-10-22 07:32:35 +0000 |
commit | 0fefd7f4fb0598420de8832acdaed52d895eb62f (patch) | |
tree | c920c6d93677f7e2e13d603b3a1fd9486b924ce0 /plugins/org.eclipse.net4j/src/org/eclipse/net4j/util | |
parent | 4b41c537099072f6d2b7fdba3cfd605666da6e96 (diff) | |
download | cdo-0fefd7f4fb0598420de8832acdaed52d895eb62f.tar.gz cdo-0fefd7f4fb0598420de8832acdaed52d895eb62f.tar.xz cdo-0fefd7f4fb0598420de8832acdaed52d895eb62f.zip |
Initial provisioning of v0.8.0
Diffstat (limited to 'plugins/org.eclipse.net4j/src/org/eclipse/net4j/util')
27 files changed, 2258 insertions, 0 deletions
diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Asynchronizer.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Asynchronizer.java new file mode 100644 index 0000000000..60840f0777 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Asynchronizer.java @@ -0,0 +1,25 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.concurrent; + +/** + * @author Eike Stepper + */ +public class Asynchronizer +{ + public Asynchronizer() + { + } + + public void addWork(Runnable work) + { + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Correlator.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Correlator.java new file mode 100644 index 0000000000..959fbc3042 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Correlator.java @@ -0,0 +1,25 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.concurrent; + +/** + * @author Eike Stepper + */ +public interface Correlator<CORRELATION, VALUE> +{ + public boolean isCorrelated(CORRELATION correlation); + + public VALUE correlate(CORRELATION correlation); + + public VALUE correlateUnique(CORRELATION correlation); + + public VALUE uncorrelate(CORRELATION correlation); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/ResultSynchronizer.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/ResultSynchronizer.java new file mode 100644 index 0000000000..a9cf6a9dec --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/ResultSynchronizer.java @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.concurrent; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @author Eike Stepper + */ +public final class ResultSynchronizer<RESULT> implements Synchronizer<RESULT> +{ + private RESULT result; + + private Object consumerLock = new Object(); + + private CountDownLatch producerLatch = new CountDownLatch(1); + + public ResultSynchronizer() + { + } + + public RESULT get(long timeout) + { + try + { + final long stop = System.currentTimeMillis() + timeout; + synchronized (consumerLock) + { + while (result == null) + { + try + { + final long remaining = stop - System.currentTimeMillis(); + if (remaining <= 0) + { + return null; + } + + consumerLock.wait(Math.min(remaining, 100)); + } + catch (InterruptedException ex) + { + return null; + } + } + + return result; + } + } + finally + { + producerLatch.countDown(); + } + } + + public void put(RESULT result) + { + synchronized (consumerLock) + { + this.result = result; + consumerLock.notifyAll(); + } + } + + public boolean put(RESULT result, long timeout) + { + synchronized (consumerLock) + { + this.result = result; + consumerLock.notifyAll(); + } + + try + { + if (!producerLatch.await(timeout, TimeUnit.MILLISECONDS)) + { + return false; + } + } + catch (InterruptedException ex) + { + return false; + } + + return true; + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Synchronizer.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Synchronizer.java new file mode 100644 index 0000000000..b8a432aa50 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Synchronizer.java @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.concurrent; + +/** + * Synchronizes a producer and a consumer thread letting the producer pass a + * value to the consumer. Both producer and consumer must have access to this + * {@link Synchronizer} and there must only ever exist one consumer for it. Once + * the result value is consumed by the consumer this {@link Synchronizer} must + * not be reused. + * <p> + * + * @author Eike Stepper + */ +public interface Synchronizer<RESULT> +{ + public RESULT get(long timeout); + + public void put(RESULT result); + + public boolean put(RESULT result, long timeout); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/SynchronizingCorrelator.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/SynchronizingCorrelator.java new file mode 100644 index 0000000000..58f132fbda --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/SynchronizingCorrelator.java @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.concurrent; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * @author Eike Stepper + */ +public class SynchronizingCorrelator<CORRELATION, RESULT> implements + Correlator<CORRELATION, Synchronizer<RESULT>> +{ + private ConcurrentMap<CORRELATION, Synchronizer<RESULT>> map = new ConcurrentHashMap(); + + public boolean isCorrelated(CORRELATION correlation) + { + return map.containsKey(correlation); + } + + public Synchronizer<RESULT> correlate(CORRELATION correlation) + { + Synchronizer<RESULT> synchronizer = map.get(correlation); + if (synchronizer == null) + { + synchronizer = createSynchronizer(correlation); + map.put(correlation, synchronizer); + } + + return synchronizer; + } + + public Synchronizer<RESULT> correlateUnique(CORRELATION correlation) + { + Synchronizer<RESULT> synchronizer = createSynchronizer(correlation); + if (map.putIfAbsent(correlation, synchronizer) != null) + { + throw new IllegalStateException("Already correlated: " + correlation); + } + + return synchronizer; + } + + public Synchronizer<RESULT> uncorrelate(CORRELATION correlation) + { + return map.remove(correlation); + } + + public RESULT get(CORRELATION correlation, long timeout) + { + return correlate(correlation).get(timeout); + } + + public void put(CORRELATION correlation, RESULT result) + { + correlate(correlation).put(result); + } + + public boolean put(CORRELATION correlation, RESULT result, long timeout) + { + return correlate(correlation).put(result, timeout); + } + + protected Synchronizer<RESULT> createSynchronizer(final CORRELATION correlation) + { + return new Synchronizer<RESULT>() + { + private Synchronizer<RESULT> delegate = new ResultSynchronizer<RESULT>(); + + public RESULT get(long timeout) + { + RESULT result = delegate.get(timeout); + uncorrelate(correlation); + return result; + } + + public void put(RESULT result) + { + delegate.put(result); + } + + public boolean put(RESULT result, long timeout) + { + return delegate.put(result, timeout); + } + }; + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Worker.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Worker.java new file mode 100644 index 0000000000..0a1d268b18 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/concurrent/Worker.java @@ -0,0 +1,25 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.concurrent; + +/** + * @author Eike Stepper + */ +public class Worker +{ + public Worker() + { + } + + public void addWork(Runnable work) + { + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/AbstractLifecycle.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/AbstractLifecycle.java new file mode 100644 index 0000000000..1fa2d4eb0d --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/AbstractLifecycle.java @@ -0,0 +1,115 @@ +package org.eclipse.net4j.util.lifecycle; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * @author Eike Stepper + */ +public abstract class AbstractLifecycle implements Lifecycle, LifecycleNotifier +{ + private boolean active; + + /** + * Don't initialize lazily to circumvent synchronization! + */ + private Queue<LifecycleListener> listeners = new ConcurrentLinkedQueue(); + + protected AbstractLifecycle() + { + } + + public final void addLifecycleListener(LifecycleListener listener) + { + listeners.add(listener); + } + + public final void removeLifecycleListener(LifecycleListener listener) + { + listeners.remove(listener); + } + + public final synchronized void activate() throws Exception + { + if (!active) + { + System.out.println(toString() + ": Activating"); + onAccessBeforeActivate(); + onActivate(); + active = true; + fireLifecycleActivated(); + } + } + + public final synchronized Exception deactivate() + { + if (active) + { + System.out.println(toString() + ": Deactivating"); + fireLifecycleDeactivating(); + + try + { + onDeactivate(); + } + catch (Exception ex) + { + ex.printStackTrace(); + return ex; + } + finally + { + active = false; + } + } + + return null; + } + + public final boolean isActive() + { + return active; + } + + protected void fireLifecycleActivated() + { + for (LifecycleListener listener : listeners) + { + try + { + listener.notifyLifecycleActivated(this); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + } + + protected void fireLifecycleDeactivating() + { + for (LifecycleListener listener : listeners) + { + try + { + listener.notifyLifecycleDeactivating(this); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + } + + protected void onAccessBeforeActivate() throws Exception + { + } + + protected void onActivate() throws Exception + { + } + + protected void onDeactivate() throws Exception + { + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Activator.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Activator.java new file mode 100644 index 0000000000..9294ecb754 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Activator.java @@ -0,0 +1,13 @@ +package org.eclipse.net4j.util.lifecycle; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Activator +{ + boolean propagate() default true; +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Deactivator.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Deactivator.java new file mode 100644 index 0000000000..0781c7d0e7 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Deactivator.java @@ -0,0 +1,13 @@ +package org.eclipse.net4j.util.lifecycle; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Deactivator +{ + boolean propagate() default true; +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Lifecycle.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Lifecycle.java new file mode 100644 index 0000000000..1556f4c222 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/Lifecycle.java @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.lifecycle; + +/** + * @author Eike Stepper + */ +public interface Lifecycle +{ + public void activate() throws Exception; + + public Exception deactivate(); + + /** + * @author Eike Stepper + */ + public interface Introspection + { + public boolean isActive(); + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleListener.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleListener.java new file mode 100644 index 0000000000..eaa3863ff6 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleListener.java @@ -0,0 +1,11 @@ +package org.eclipse.net4j.util.lifecycle; + +/** + * @author Eike Stepper + */ +public interface LifecycleListener +{ + public void notifyLifecycleActivated(LifecycleNotifier notifier); + + public void notifyLifecycleDeactivating(LifecycleNotifier notifier); +}
\ No newline at end of file diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleNotifier.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleNotifier.java new file mode 100644 index 0000000000..f7f72be4d6 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleNotifier.java @@ -0,0 +1,11 @@ +package org.eclipse.net4j.util.lifecycle; + +/** + * @author Eike Stepper + */ +public interface LifecycleNotifier extends Lifecycle.Introspection +{ + public void addLifecycleListener(LifecycleListener listener); + + public void removeLifecycleListener(LifecycleListener listener); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleUtil.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleUtil.java new file mode 100644 index 0000000000..0eeec29f9a --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/lifecycle/LifecycleUtil.java @@ -0,0 +1,165 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.lifecycle; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +/** + * @author Eike Stepper + */ +public final class LifecycleUtil +{ + private LifecycleUtil() + { + } + + public static boolean isActive(Object object) + { + if (object instanceof Lifecycle.Introspection) + { + return ((Lifecycle.Introspection)object).isActive(); + } + + return true; + } + + public static void activate(Object object) throws Exception + { + activate(object, false); + } + + /** + * @see Activator + */ + public static void activate(Object object, boolean useAnnotation) throws Exception + { + if (object instanceof Lifecycle) + { + ((Lifecycle)object).activate(); + } + else if (useAnnotation) + { + invokeAnnotation(object, Activator.class); + } + } + + public static Exception activateSilent(Object object) + { + return activateSilent(object, false); + } + + /** + * @see Activator + */ + public static Exception activateSilent(Object object, boolean useAnnotation) + { + try + { + activate(object, useAnnotation); + return null; + } + catch (Exception ex) + { + return ex; + } + } + + public static Exception deactivate(Object object) + { + return deactivate(object, false); + } + + /** + * @see Deactivator + */ + public static Exception deactivate(Object object, boolean useAnnotation) + { + if (object instanceof Lifecycle) + { + return ((Lifecycle)object).deactivate(); + } + else if (useAnnotation) + { + invokeAnnotation(object, Deactivator.class); + } + + return null; + } + + public static void deactivateNoisy(Object object) throws Exception + { + deactivateNoisy(object, false); + } + + public static void deactivateNoisy(Object object, boolean useAnnotation) throws Exception + { + Exception ex = deactivate(object, useAnnotation); + if (ex != null) + { + throw ex; + } + } + + private static void invokeAnnotation(Object object, Class annotationClass) + { + Class c = object.getClass(); + while (c != Object.class) + { + final Method[] methods = c.getDeclaredMethods(); + for (Method method : methods) + { + if (method.getParameterTypes().length == 0) + { + Annotation annotation = method.getAnnotation(annotationClass); + if (annotation != null) + { + invokeMethod(object, method); + boolean propagate = annotationClass == Activator.class ? ((Activator)annotation) + .propagate() : ((Deactivator)annotation).propagate(); + if (!propagate) + { + break; + } + } + } + } + + c = c.getSuperclass(); + } + } + + private static Object invokeMethod(Object object, Method method) + { + try + { + return method.invoke(object, (Object[])null); + } + catch (IllegalAccessException iae) + { + try + { + method.setAccessible(true); + return method.invoke(object, (Object[])null); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + } + + return null; + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/map/AbstractCachingMap.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/map/AbstractCachingMap.java new file mode 100644 index 0000000000..530298e41c --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/map/AbstractCachingMap.java @@ -0,0 +1,323 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.map; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Implementation note: {@link AbstractCachingMap} does not preserve the + * "modifyable view" contract of {@link Map#entrySet()} as well as of + * {@link Map#keySet()}, i.e. they are disconnected sets and modifications + * applied to them are not applied to their underlying + * {@link AbstractCachingMap}. + * <p> + * + * @author Eike Stepper + */ +public abstract class AbstractCachingMap<K, V> extends AbstractDelegatingMap<K, V> +{ + protected AbstractCachingMap() + { + } + + protected AbstractCachingMap(Map<? extends K, ? extends V> t) + { + super(t); + } + + public void clear() + { + cachedClear(); + } + + public boolean containsKey(Object key) + { + return cachedContainsKey(key) || delegatedContainsKey(key); + } + + public boolean containsValue(Object value) + { + return cachedContainsValue(value) || cachedContainsValue(value); + } + + public Set<Entry<K, V>> entrySet() + { + return mergedEntrySet(); + } + + public V get(Object key) + { + V result = cachedGet(key); + if (result == null) + { + result = delegatedGet(key); + } + + return result; + } + + public boolean isEmpty() + { + return cachedIsEmpty() && delegatedIsEmpty(); + } + + public Set<K> keySet() + { + return mergedKeySet(); + } + + public V put(K key, V value) + { + return cachedPut(key, value); + } + + public void putAll(Map<? extends K, ? extends V> t) + { + cachedPutAll(t); + } + + public V remove(Object key) + { + return cachedRemove(key); + } + + public int size() + { + return keySet().size(); + } + + public Collection<V> values() + { + return mergedValues(); + } + + @Override + public boolean equals(Object obj) + { + return mergedEquals(obj); + } + + @Override + public int hashCode() + { + return mergedHashCode(); + } + + @Override + public String toString() + { + return mergedToString(); + } + + protected void cachedClear() + { + getCache().clear(); + } + + protected boolean cachedContainsKey(Object key) + { + return getCache().containsKey(key); + } + + protected boolean cachedContainsValue(Object value) + { + return getCache().containsValue(value); + } + + protected Set<Entry<K, V>> cachedEntrySet() + { + return getCache().entrySet(); + } + + protected V cachedGet(Object key) + { + return getCache().get(key); + } + + protected boolean cachedIsEmpty() + { + return getCache().isEmpty(); + } + + protected Set<K> cachedKeySet() + { + return getCache().keySet(); + } + + protected V cachedPut(K key, V value) + { + return getCache().put(key, value); + } + + protected void cachedPutAll(Map<? extends K, ? extends V> t) + { + getCache().putAll(t); + } + + protected V cachedRemove(Object key) + { + return getCache().remove(key); + } + + protected int cachedSize() + { + return getCache().size(); + } + + protected Collection<V> cachedValues() + { + return getCache().values(); + } + + protected boolean cachedEquals(Object obj) + { + return getCache().equals(obj); + } + + protected int cachedHashCode() + { + return getCache().hashCode(); + } + + protected String cachedToString() + { + return getCache().toString(); + } + + protected Set<Entry<K, V>> mergedEntrySet() + { + final Map<K, V> merged = new HashMap<K, V>(); + merged.putAll(getDelegate()); + merged.putAll(getCache()); + return merged.entrySet(); + } + + protected Set<K> mergedKeySet() + { + final Set<K> merged = new HashSet<K>(); + merged.addAll(getDelegate().keySet()); + merged.addAll(getCache().keySet()); + return merged; + } + + protected Collection<V> mergedValues() + { + final List<V> result = new ArrayList<V>(); + for (K key : keySet()) + { + result.add(get(key)); + } + + return result; + } + + /** + * @see AbstractMap#equals(Object) + */ + protected boolean mergedEquals(Object o) + { + if (o == this) + return true; + + if (!(o instanceof Map)) + return false; + + Map<K, V> t = (Map<K, V>)o; + if (t.size() != size()) + return false; + + try + { + Iterator<Entry<K, V>> i = entrySet().iterator(); + while (i.hasNext()) + { + Entry<K, V> e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + if (value == null) + { + if (!(t.get(key) == null && t.containsKey(key))) + return false; + } + else + { + if (!value.equals(t.get(key))) + return false; + } + } + } + catch (ClassCastException unused) + { + return false; + } + catch (NullPointerException unused) + { + return false; + } + + return true; + } + + /** + * @see AbstractMap#hashCode() + */ + protected int mergedHashCode() + { + int h = 0; + Iterator<Entry<K, V>> i = entrySet().iterator(); + while (i.hasNext()) + h += i.next().hashCode(); + return h; + } + + /** + * @see AbstractMap#toString() + */ + protected String mergedToString() + { + StringBuffer buf = new StringBuffer(); + buf.append("{"); + + Iterator<Entry<K, V>> i = entrySet().iterator(); + boolean hasNext = i.hasNext(); + while (hasNext) + { + Entry<K, V> e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + if (key == this) + buf.append("(this Map)"); + else + buf.append(key); + buf.append("="); + if (value == this) + buf.append("(this Map)"); + else + buf.append(value); + hasNext = i.hasNext(); + if (hasNext) + buf.append(", "); + } + + buf.append("}"); + return buf.toString(); + } + + protected abstract Map<K, V> getCache(); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/map/AbstractDelegatingMap.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/map/AbstractDelegatingMap.java new file mode 100644 index 0000000000..ab445ceb70 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/map/AbstractDelegatingMap.java @@ -0,0 +1,192 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.map; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * Implementation note: {@link AbstractDelegatingMap} does not necessarily + * preserve the "modifyable view" contract of {@link Map#entrySet()} as well as + * of {@link Map#keySet()}, i.e. they might be disconnected sets and + * modifications applied to them might not be applied to their underlying + * {@link AbstractDelegatingMap}. + * <p> + * + * @author Eike Stepper + */ +public abstract class AbstractDelegatingMap<K, V> implements Map<K, V> +{ + protected AbstractDelegatingMap() + { + } + + protected AbstractDelegatingMap(Map<? extends K, ? extends V> t) + { + putAll(t); + } + + public void clear() + { + delegatedClear(); + } + + public boolean containsKey(Object key) + { + return delegatedContainsKey(key); + } + + public boolean containsValue(Object value) + { + return delegatedContainsValue(value); + } + + public Set<Entry<K, V>> entrySet() + { + return delegatedEntrySet(); + } + + public V get(Object key) + { + return delegatedGet(key); + } + + public boolean isEmpty() + { + return delegatedIsEmpty(); + } + + public Set<K> keySet() + { + return delegatedKeySet(); + } + + public V put(K key, V value) + { + return delegatedPut(key, value); + } + + public void putAll(Map<? extends K, ? extends V> t) + { + delegatedPutAll(t); + } + + public V remove(Object key) + { + return delegatedRemove(key); + } + + public int size() + { + return delegatedSize(); + } + + public Collection<V> values() + { + return delegatedValues(); + } + + @Override + public boolean equals(Object obj) + { + return delegatedEquals(obj); + } + + @Override + public int hashCode() + { + return delegatedHashCode(); + } + + @Override + public String toString() + { + return delegatedToString(); + } + + protected void delegatedClear() + { + getDelegate().clear(); + } + + protected boolean delegatedContainsKey(Object key) + { + return getDelegate().containsKey(key); + } + + protected boolean delegatedContainsValue(Object value) + { + return getDelegate().containsValue(value); + } + + protected Set<Entry<K, V>> delegatedEntrySet() + { + return getDelegate().entrySet(); + } + + protected V delegatedGet(Object key) + { + return getDelegate().get(key); + } + + protected boolean delegatedIsEmpty() + { + return getDelegate().isEmpty(); + } + + protected Set<K> delegatedKeySet() + { + return getDelegate().keySet(); + } + + protected V delegatedPut(K key, V value) + { + return getDelegate().put(key, value); + } + + protected void delegatedPutAll(Map<? extends K, ? extends V> t) + { + getDelegate().putAll(t); + } + + protected V delegatedRemove(Object key) + { + return getDelegate().remove(key); + } + + protected int delegatedSize() + { + return getDelegate().size(); + } + + protected Collection<V> delegatedValues() + { + return getDelegate().values(); + } + + protected boolean delegatedEquals(Object obj) + { + return getDelegate().equals(obj); + } + + protected int delegatedHashCode() + { + return getDelegate().hashCode(); + } + + protected String delegatedToString() + { + return getDelegate().toString(); + } + + protected abstract Map<K, V> getDelegate(); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractCachingRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractCachingRegistry.java new file mode 100644 index 0000000000..c7b116fc24 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractCachingRegistry.java @@ -0,0 +1,162 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import org.eclipse.net4j.util.registry.IRegistry.Listener.EventType; +import org.eclipse.net4j.util.registry.IRegistryElement.Descriptor; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * TODO Check if all methods of DelegatingRegistry still do what they should. + * TODO Remove DelegatingRegistry? + * + * @author Eike Stepper + */ +public abstract class AbstractCachingRegistry<ID, E extends IRegistryElement<ID>> extends + DelegatingRegistry<ID, E> +{ + public AbstractCachingRegistry(IRegistry<ID, E> delegate) + { + this(delegate, DEFAULT_RESOLVING); + } + + public AbstractCachingRegistry(IRegistry<ID, E> delegate, boolean resolving) + { + super(delegate, resolving); + } + + @Override + public synchronized void register(E element) + { + ID id = element.getID(); + E delegatedElement = super.lookup(id, false); + E oldElement = getCache().put(id, element); + + if (oldElement == null) + { + if (delegatedElement != null) + { + // Unhidden delegated element now becomes hidden + fireElementDeregistering(delegatedElement); + } + } + else + { + fireElementDeregistering(oldElement); + oldElement.dispose(); + } + + fireElementRegistered(element); + } + + @Override + public synchronized void deregister(ID id) + { + E delegatedElement = super.lookup(id, false); + E element = getCache().remove(id); + + if (element != null) + { + fireElementDeregistering(element); + element.dispose(); + + if (delegatedElement != null) + { + // Hidden delegated element now becomes unhidden + fireElementRegistered(delegatedElement); + } + } + } + + /** + * Synchronized to support {@link #resolveElement(IRegistryElement)} + */ + @Override + public synchronized E lookup(ID id, boolean resolve) + { + E element = getCache().get(id); + if (element == null) + { + if (resolve) + { + return resolveDelegatedElement(id); + } + else + { + return super.lookup(id, false); + } + } + + if (resolve) + { + element = resolveElement(element); + } + + return element; + } + + @Override + public Set<ID> getElementIDs() + { + Set<ID> ids = new HashSet(); + ids.addAll(super.getElementIDs()); + ids.addAll(getCache().keySet()); + return ids; + } + + @Override + public synchronized void dispose() + { + for (E element : getCache().values()) + { + fireElementDeregistering(element); + element.dispose(); + } + + getCache().clear(); + super.dispose(); + } + + @Override + protected void replaceElement(ID id, E element) + { + getCache().put(id, element); + } + + @Override + protected synchronized void handleDelegateEvent(EventType eventType, E element) + { + if (!getCache().containsKey(element.getID())) + { + fireRegistryEvent(eventType, element); + } + } + + protected E resolveDelegatedElement(ID id) + { + synchronized (getDelegate()) + { + boolean wasUnresolved = super.lookup(id, false) instanceof Descriptor; + E e = super.lookup(id, true); + if (wasUnresolved) + { + fireElementResolved(e); + } + + return e; + } + } + + protected abstract Map<ID, E> getCache(); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractMappingRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractMappingRegistry.java new file mode 100644 index 0000000000..e9c4fd97e6 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractMappingRegistry.java @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import java.util.Map; +import java.util.Set; + +/** + * @author Eike Stepper + */ +public abstract class AbstractMappingRegistry<ID, E extends IRegistryElement<ID>> extends + AbstractRegistry<ID, E> +{ + public AbstractMappingRegistry() + { + this(DEFAULT_RESOLVING); + } + + public AbstractMappingRegistry(boolean resolving) + { + super(resolving); + } + + public synchronized void register(E element) + { + E oldElement = getMap().put(element.getID(), element); + if (oldElement != null) + { + fireElementDeregistering(oldElement); + oldElement.dispose(); + } + + fireElementRegistered(element); + } + + public synchronized void deregister(ID id) + { + E element = getMap().remove(id); + if (element != null) + { + fireElementDeregistering(element); + element.dispose(); + } + } + + /** + * Synchronized to support {@link #resolveElement(IRegistryElement)} + */ + public synchronized E lookup(ID id, boolean resolve) + { + E element = getMap().get(id); + if (resolve) + { + element = resolveElement(element); + } + + return element; + } + + public Set<ID> getElementIDs() + { + return getMap().keySet(); + } + + @Override + public synchronized void dispose() + { + for (E element : getMap().values()) + { + element.dispose(); + } + + getMap().clear(); + } + + @Override + protected void replaceElement(ID id, E element) + { + getMap().put(id, element); + } + + protected abstract Map<ID, E> getMap(); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractRegistry.java new file mode 100644 index 0000000000..3bba7218ef --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/AbstractRegistry.java @@ -0,0 +1,163 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import org.eclipse.net4j.util.registry.IRegistry.Listener.EventType; +import org.eclipse.net4j.util.registry.IRegistryElement.Descriptor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * @author Eike Stepper + */ +public abstract class AbstractRegistry<ID, E extends IRegistryElement<ID>> implements + IRegistry<ID, E> +{ + public static final boolean DEFAULT_RESOLVING = true; + + private boolean resolving; + + /** + * Don't initialize lazily to circumvent synchronization! + */ + private Queue<Listener> listeners = new ConcurrentLinkedQueue(); + + protected AbstractRegistry() + { + this(DEFAULT_RESOLVING); + } + + public AbstractRegistry(boolean resolving) + { + setResolving(resolving); + } + + public void setResolving(boolean resolving) + { + this.resolving = resolving; + } + + public final boolean isResolving() + { + return resolving; + } + + public final boolean isResolved(ID id) + { + E element = lookup(id, false); + return element != null && !(element instanceof Descriptor); + } + + public final boolean isRegistered(ID id) + { + return lookup(id, false) != null; + } + + public int size() + { + return getElementIDs().size(); + } + + public final E lookup(ID id) + { + return lookup(id, isResolving()); + } + + public final Collection<E> getElements() + { + return getElements(isResolving()); + } + + /** + * Synchronized to support {@link #resolveElement(IRegistryElement)} + */ + public final synchronized Collection<E> getElements(boolean resolve) + { + Set<ID> elementKeys = getElementIDs(); + List<E> elements = new ArrayList<E>(elementKeys.size()); + for (ID id : elementKeys) + { + elements.add(lookup(id, resolve)); + } + + return elements; + } + + public void addListener(IRegistry.Listener<ID, E> listener) + { + listeners.add(listener); + } + + public void removeListener(IRegistry.Listener<ID, E> listener) + { + listeners.remove(listener); + } + + public void dispose() + { + listeners.clear(); + } + + protected void fireRegistryEvent(EventType eventType, E element) + { + for (Listener listener : listeners) + { + try + { + listener.notifyRegistryEvent(this, eventType, element); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + } + + protected void fireElementRegistered(E element) + { + fireRegistryEvent(EventType.REGISTERED, element); + } + + protected void fireElementDeregistering(E element) + { + fireRegistryEvent(EventType.DEREGISTERING, element); + } + + protected void fireElementResolved(E element) + { + fireRegistryEvent(EventType.RESOLVED, element); + } + + /** + * Calling thread must already synchronize on this {@link IRegistry}! + */ + protected E resolveElement(E element) + { + if (element instanceof Descriptor) + { + element = (E)((Descriptor)element).resolve(); + replaceElement(element.getID(), element); + fireElementResolved(element); + } + + return element; + } + + /** + * Calling thread must already synchronize on this {@link IRegistry}! + */ + protected abstract void replaceElement(ID id, E element); +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/DelegatingRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/DelegatingRegistry.java new file mode 100644 index 0000000000..9676232c58 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/DelegatingRegistry.java @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import org.eclipse.net4j.util.registry.IRegistry.Listener.EventType; + +import java.util.Set; + +/** + * @author Eike Stepper + */ +public class DelegatingRegistry<ID, E extends IRegistryElement<ID>> extends AbstractRegistry<ID, E> +{ + private IRegistry<ID, E> delegate; + + private Listener<ID, E> delegateListener = new Listener<ID, E>() + { + public void notifyRegistryEvent(IRegistry<ID, E> registry, EventType eventType, E element) + { + handleDelegateEvent(eventType, element); + } + }; + + public DelegatingRegistry(IRegistry<ID, E> delegate) + { + this(delegate, DEFAULT_RESOLVING); + } + + public DelegatingRegistry(IRegistry<ID, E> delegate, boolean resolving) + { + super(resolving); + this.delegate = delegate; + delegate.addListener(delegateListener); + } + + public IRegistry<ID, E> getDelegate() + { + return delegate; + } + + public void register(E element) + { + delegatedRegister(element); + } + + public void deregister(ID id) + { + delegatedDeregister(id); + } + + public E lookup(ID id, boolean resolve) + { + return delegatedLookup(id, resolve); + } + + public Set<ID> getElementIDs() + { + return delegatedGetElementIDs(); + } + + @Override + public void dispose() + { + delegate.removeListener(delegateListener); + } + + protected void delegatedRegister(E element) + { + delegate.register(element); + } + + protected void delegatedDeregister(ID id) + { + delegate.deregister(id); + } + + protected E delegatedLookup(ID id, boolean resolve) + { + return delegate.lookup(id, resolve); + } + + protected Set<ID> delegatedGetElementIDs() + { + return delegate.getElementIDs(); + } + + protected int delegatedSize() + { + return delegate.size(); + } + + protected void delegatedDispose() + { + delegate.dispose(); + } + + protected void handleDelegateEvent(EventType eventType, E element) + { + fireRegistryEvent(eventType, element); + } + + @Override + protected void replaceElement(ID id, E element) + { + // Do nothing + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/HashCacheRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/HashCacheRegistry.java new file mode 100644 index 0000000000..29f80d4cbc --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/HashCacheRegistry.java @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public class HashCacheRegistry<ID, E extends IRegistryElement<ID>> extends + AbstractCachingRegistry<ID, E> +{ + private Map<ID, E> cache; + + public HashCacheRegistry(IRegistry<ID, E> delegate) + { + this(delegate, DEFAULT_RESOLVING); + } + + public HashCacheRegistry(IRegistry<ID, E> delegate, boolean resolving) + { + super(delegate, resolving); + cache = createCache(); + } + + @Override + protected Map<ID, E> getCache() + { + return cache; + } + + protected Map<ID, E> createCache() + { + return new HashMap(); + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/HashMapRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/HashMapRegistry.java new file mode 100644 index 0000000000..83b75fdaf3 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/HashMapRegistry.java @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public class HashMapRegistry<ID, E extends IRegistryElement<ID>> extends + AbstractMappingRegistry<ID, E> +{ + private Map<ID, E> map; + + public HashMapRegistry() + { + this(DEFAULT_RESOLVING); + } + + public HashMapRegistry(boolean resolving) + { + super(resolving); + this.map = createMap(); + } + + @Override + protected Map<ID, E> getMap() + { + return map; + } + + protected Map<ID, E> createMap() + { + return new HashMap(); + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/IRegistry.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/IRegistry.java new file mode 100644 index 0000000000..86a36a9ef5 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/IRegistry.java @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.registry; + +import java.util.Collection; +import java.util.Set; + +/** + * Implementation note: {@link Object#equals(Object)} and + * {@link Object#hashCode()} are based on pointer equality. + * <p> + * + * @author Eike Stepper + */ +public interface IRegistry<ID, E extends IRegistryElement<ID>> +{ + public void setResolving(boolean resolving); + + public boolean isResolving(); + + public boolean isResolved(ID id); + + public boolean isRegistered(ID id); + + public int size(); + + public void register(E element); + + public void deregister(ID id); + + public E lookup(ID id); + + public E lookup(ID id, boolean resolve); + + public Set<ID> getElementIDs(); + + public Collection<E> getElements(); + + public Collection<E> getElements(boolean resolve); + + public void addListener(Listener<ID, E> listener); + + public void removeListener(Listener<ID, E> listener); + + public void dispose(); + + /** + * @author Eike Stepper + */ + public interface Listener<ID, E extends IRegistryElement<ID>> + { + public void notifyRegistryEvent(IRegistry<ID, E> registry, EventType eventType, E element); + + /** + * @author Eike Stepper + */ + public enum EventType + { + REGISTERED, DEREGISTERING, RESOLVED + } + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/IRegistryElement.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/IRegistryElement.java new file mode 100644 index 0000000000..b25f11e9b6 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/registry/IRegistryElement.java @@ -0,0 +1,19 @@ +package org.eclipse.net4j.util.registry; + +/** + * @author Eike Stepper + */ +public interface IRegistryElement<ID> +{ + public ID getID(); + + public void dispose(); + + /** + * @author Eike Stepper + */ + public interface Descriptor<ID> extends IRegistryElement<ID> + { + public IRegistryElement<ID> resolve(); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/BufferInputStream.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/BufferInputStream.java new file mode 100644 index 0000000000..4208f91e91 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/BufferInputStream.java @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.stream; + +import org.eclipse.net4j.transport.Buffer; +import org.eclipse.net4j.transport.BufferHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * @author Eike Stepper + */ +public class BufferInputStream extends InputStream implements BufferHandler +{ + public static final long NO_TIMEOUT = -1; + + public static final long DEFAULT_MILLIS_BEFORE_TIMEOUT = NO_TIMEOUT; + + public static final long DEFAULT_MILLIS_INTERRUPT_CHECK = 100; + + private BlockingQueue<Buffer> buffers = new LinkedBlockingQueue<Buffer>(); + + private Buffer currentBuffer; + + private boolean eos; + + public BufferInputStream() + { + } + + public void handleBuffer(Buffer buffer) + { + buffers.add(buffer); + } + + @Override + public int read() throws IOException + { + if (eos && currentBuffer == null) + { + // End of sequence + return -1; + } + + if (!ensureBuffer()) + { + // Timeout or interrupt + return -1; + } + + int result = currentBuffer.getByteBuffer().get() - Byte.MIN_VALUE; + if (!currentBuffer.getByteBuffer().hasRemaining()) + { + currentBuffer.release(); + currentBuffer = null; + } + + return result; + } + + @Override + public void close() throws IOException + { + buffers = null; + currentBuffer = null; + super.close(); + } + + @Override + public String toString() + { + return "BufferInputStream"; + } + + protected boolean ensureBuffer() throws IOException + { + try + { + final long check = getMillisInterruptCheck(); + final long timeout = getMillisBeforeTimeout(); + + try + { + if (timeout == NO_TIMEOUT) + { + while (currentBuffer == null) + { + currentBuffer = buffers.poll(check, TimeUnit.MILLISECONDS); + } + } + else + { + final long stop = System.currentTimeMillis() + timeout; + while (currentBuffer == null) + { + final long remaining = stop - System.currentTimeMillis(); + if (remaining <= 0) + { + return false; + } + + currentBuffer = buffers.poll(Math.min(remaining, check), TimeUnit.MILLISECONDS); + } + } + } + catch (InterruptedException ex) + { + throw new IOException("Interrupted"); + } + + eos = currentBuffer.isEOS(); + } + catch (RuntimeException ex) + { + // TODO Remove + ex.printStackTrace(); + } + return true; + } + + public long getMillisBeforeTimeout() + { + return DEFAULT_MILLIS_BEFORE_TIMEOUT; + } + + public long getMillisInterruptCheck() + { + return DEFAULT_MILLIS_INTERRUPT_CHECK; + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/BufferOutputStream.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/BufferOutputStream.java new file mode 100644 index 0000000000..ab67ac766d --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/BufferOutputStream.java @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.stream; + +import org.eclipse.net4j.transport.Buffer; +import org.eclipse.net4j.transport.BufferHandler; +import org.eclipse.net4j.transport.BufferProvider; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +/** + * @author Eike Stepper + */ +public class BufferOutputStream extends OutputStream +{ + public static final boolean DEFAULT_PROPAGATE_CLOSE = false; + + private BufferHandler bufferHandler; + + private BufferProvider bufferProvider; + + private Buffer currentBuffer; + + private short channelID; + + public BufferOutputStream(BufferHandler bufferHandler, BufferProvider bufferProvider, + short channelID) + { + if (bufferHandler == null) + { + throw new IllegalArgumentException("bufferHandler == null"); + } + + if (bufferProvider == null) + { + throw new IllegalArgumentException("bufferProvider == null"); + } + + this.bufferHandler = bufferHandler; + this.bufferProvider = bufferProvider; + this.channelID = channelID; + } + + public BufferOutputStream(BufferHandler bufferHandler, short channelID) + { + this(bufferHandler, extractBufferProvider(bufferHandler), channelID); + } + + @Override + public void write(int b) throws IOException + { + ensureBuffer(); + ByteBuffer buffer = currentBuffer.getByteBuffer(); + buffer.put((byte)(b + Byte.MIN_VALUE)); + + if (!buffer.hasRemaining()) + { + flush(); + } + } + + @Override + public void flush() throws IOException + { + if (currentBuffer != null) + { + bufferHandler.handleBuffer(currentBuffer); + currentBuffer = null; + } + } + + public void flushWithEOS() throws IOException + { + ensureBuffer(); + currentBuffer.setEOS(true); + flush(); + } + + @Override + public void close() throws IOException + { + try + { + if (isPropagateClose()) + { + LifecycleUtil.deactivate(bufferHandler); + } + } + finally + { + bufferHandler = null; + bufferProvider = null; + currentBuffer = null; + super.close(); + } + } + + @Override + public String toString() + { + return "BufferOutputStream"; + } + + protected void ensureBuffer() + { + if (currentBuffer == null) + { + currentBuffer = bufferProvider.provideBuffer(); + currentBuffer.startPutting(channelID); + } + } + + protected boolean isPropagateClose() + { + return DEFAULT_PROPAGATE_CLOSE; + } + + private static BufferProvider extractBufferProvider(BufferHandler bufferHandler) + { + if (bufferHandler instanceof BufferProvider) + { + return (BufferProvider)bufferHandler; + } + + throw new IllegalArgumentException("Buffer handler unable to provide buffers"); + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/ChannelInputStream.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/ChannelInputStream.java new file mode 100644 index 0000000000..81cfb487f8 --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/ChannelInputStream.java @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.stream; + +import org.eclipse.net4j.transport.Channel; + +/** + * @author Eike Stepper + */ +public class ChannelInputStream extends BufferInputStream +{ + private Channel channel; + + private long millisBeforeTimeout = DEFAULT_MILLIS_BEFORE_TIMEOUT; + + private long millisInterruptCheck = DEFAULT_MILLIS_INTERRUPT_CHECK; + + public ChannelInputStream(Channel channel) + { + this(channel, DEFAULT_MILLIS_BEFORE_TIMEOUT); + } + + public ChannelInputStream(Channel channel, long millisBeforeTimeout) + { + this.channel = channel; + channel.setReceiveHandler(this); + this.millisBeforeTimeout = millisBeforeTimeout; + millisInterruptCheck = DEFAULT_MILLIS_INTERRUPT_CHECK; + } + + public Channel getChannel() + { + return channel; + } + + public long getMillisBeforeTimeout() + { + return millisBeforeTimeout; + } + + public void setMillisBeforeTimeout(long millisBeforeTimeout) + { + this.millisBeforeTimeout = millisBeforeTimeout; + } + + public long getMillisInterruptCheck() + { + return millisInterruptCheck; + } + + public void setMillisInterruptCheck(long millisInterruptCheck) + { + this.millisInterruptCheck = millisInterruptCheck; + } + + @Override + public String toString() + { + return "ChannelInputStream[" + channel + "]"; + } +} diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/ChannelOutputStream.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/ChannelOutputStream.java new file mode 100644 index 0000000000..2314836ffa --- /dev/null +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/util/stream/ChannelOutputStream.java @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.stream; + +import org.eclipse.net4j.transport.BufferProvider; +import org.eclipse.net4j.transport.Channel; + +/** + * @author Eike Stepper + */ +public class ChannelOutputStream extends BufferOutputStream +{ + public ChannelOutputStream(Channel channel) + { + super(channel, channel.getChannelID()); + } + + public ChannelOutputStream(Channel channel, BufferProvider bufferProvider) + { + super(channel, bufferProvider, channel.getChannelID()); + } +} |