JBoss Remoting SVN: r5566 - in remoting3/trunk: jboss-remoting/src/main/java/org/jboss/remoting3/spi and 1 other directories.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-23 15:10:31 -0400 (Fri, 23 Oct 2009)
New Revision: 5566
Added:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/CopyOnWriteHashMap.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/DuplicateRegistrationException.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Registration.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionContext.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocol.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocolDescriptor.java
Removed:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ConcurrentReferenceHashMap.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractConnectionProviderRegistration.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Cancellable.java
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientConnectorImpl.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/LocalRequestHandler.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistration.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistrationListener.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandler.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandlerFactory.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProvider.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderRegistration.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RemoteRequestContext.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RequestHandlerConnector.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Result.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/SpiUtils.java
remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/protocol/basic/BasicRequestHandler.java
Log:
Add service location for marshalling protocols, adjust connection provider SPI accordingly
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientConnectorImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientConnectorImpl.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientConnectorImpl.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -25,7 +25,7 @@
import org.jboss.xnio.IoFuture;
import org.jboss.remoting3.spi.RequestHandlerConnector;
import org.jboss.remoting3.spi.RequestHandler;
-import org.jboss.remoting3.spi.Cancellable;
+import org.jboss.xnio.Cancellable;
import java.io.Serializable;
import java.io.IOException;
Deleted: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ConcurrentReferenceHashMap.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ConcurrentReferenceHashMap.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ConcurrentReferenceHashMap.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -1,1709 +0,0 @@
-/*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
- */
-
-package org.jboss.remoting3;
-import java.io.IOException;
-import java.io.Serializable;
-import java.lang.ref.Reference;
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
-import java.util.AbstractCollection;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * An advanced hash table supporting configurable garbage collection semantics
- * of keys and values, optional referential-equality, full concurrency of
- * retrievals, and adjustable expected concurrency for updates.
- *
- * This table is designed around specific advanced use-cases. If there is any
- * doubt whether this table is for you, you most likely should be using
- * {@link java.util.concurrent.ConcurrentHashMap} instead.
- *
- * This table supports strong, weak, and soft keys and values. By default keys
- * are weak, and values are strong. Such a configuration offers similar behavior
- * to {@link java.util.WeakHashMap}, entries of this table are periodically
- * removed once their corresponding keys are no longer referenced outside of
- * this table. In other words, this table will not prevent a key from being
- * discarded by the garbage collector. Once a key has been discarded by the
- * collector, the corresponding entry is no longer visible to this table;
- * however, the entry may occupy space until a future table operation decides to
- * reclaim it. For this reason, summary functions such as <tt>size</tt> and
- * <tt>isEmpty</tt> might return a value greater than the observed number of
- * entries. In order to support a high level of concurrency, stale entries are
- * only reclaimed during blocking (usually mutating) operations.
- *
- * Enabling soft keys allows entries in this table to remain until their space
- * is absolutely needed by the garbage collector. This is unlike weak keys which
- * can be reclaimed as soon as they are no longer referenced by a normal strong
- * reference. The primary use case for soft keys is a cache, which ideally
- * occupies memory that is not in use for as long as possible.
- *
- * By default, values are held using a normal strong reference. This provides
- * the commonly desired guarantee that a value will always have at least the
- * same life-span as it's key. For this reason, care should be taken to ensure
- * that a value never refers, either directly or indirectly, to its key, thereby
- * preventing reclamation. If this is unavoidable, then it is recommended to use
- * the same reference type in use for the key. However, it should be noted that
- * non-strong values may disappear before their corresponding key.
- *
- * While this table does allow the use of both strong keys and values, it is
- * recommended to use {@link java.util.concurrent.ConcurrentHashMap} for such a
- * configuration, since it is optimized for that case.
- *
- * Just like {@link java.util.concurrent.ConcurrentHashMap}, this class obeys
- * the same functional specification as {@link java.util.Hashtable}, and
- * includes versions of methods corresponding to each method of
- * <tt>Hashtable</tt>. However, even though all operations are thread-safe,
- * retrieval operations do <em>not</em> entail locking, and there is
- * <em>not</em> any support for locking the entire table in a way that
- * prevents all access. This class is fully interoperable with
- * <tt>Hashtable</tt> in programs that rely on its thread safety but not on
- * its synchronization details.
- *
- * <p>
- * Retrieval operations (including <tt>get</tt>) generally do not block, so
- * may overlap with update operations (including <tt>put</tt> and
- * <tt>remove</tt>). Retrievals reflect the results of the most recently
- * <em>completed</em> update operations holding upon their onset. For
- * aggregate operations such as <tt>putAll</tt> and <tt>clear</tt>,
- * concurrent retrievals may reflect insertion or removal of only some entries.
- * Similarly, Iterators and Enumerations return elements reflecting the state of
- * the hash table at some point at or since the creation of the
- * iterator/enumeration. They do <em>not</em> throw
- * {@link ConcurrentModificationException}. However, iterators are designed to
- * be used by only one thread at a time.
- *
- * <p>
- * The allowed concurrency among update operations is guided by the optional
- * <tt>concurrencyLevel</tt> constructor argument (default <tt>16</tt>),
- * which is used as a hint for internal sizing. The table is internally
- * partitioned to try to permit the indicated number of concurrent updates
- * without contention. Because placement in hash tables is essentially random,
- * the actual concurrency will vary. Ideally, you should choose a value to
- * accommodate as many threads as will ever concurrently modify the table. Using
- * a significantly higher value than you need can waste space and time, and a
- * significantly lower value can lead to thread contention. But overestimates
- * and underestimates within an order of magnitude do not usually have much
- * noticeable impact. A value of one is appropriate when it is known that only
- * one thread will modify and all others will only read. Also, resizing this or
- * any other kind of hash table is a relatively slow operation, so, when
- * possible, it is a good idea to provide estimates of expected table sizes in
- * constructors.
- *
- * <p>
- * This class and its views and iterators implement all of the <em>optional</em>
- * methods of the {@link Map} and {@link Iterator} interfaces.
- *
- * <p>
- * Like {@link Hashtable} but unlike {@link HashMap}, this class does
- * <em>not</em> allow <tt>null</tt> to be used as a key or value.
- *
- * <p>
- * This class is a member of the <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
- *
- * @author Doug Lea
- * @author Jason T. Greene
- * @param <K> the type of keys maintained by this map
- * @param <V> the type of mapped values
- */
-class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V>
- implements java.util.concurrent.ConcurrentMap<K, V>, Serializable {
- private static final long serialVersionUID = 7249069246763182397L;
-
- /*
- * The basic strategy is to subdivide the table among Segments,
- * each of which itself is a concurrently readable hash table.
- */
-
- /**
- * An option specifying which Java reference type should be used to refer
- * to a key and/or value.
- */
- public static enum ReferenceType {
- /** Indicates a normal Java strong reference should be used */
- STRONG,
- /** Indicates a {@link WeakReference} should be used */
- WEAK,
- /** Indicates a {@link SoftReference} should be used */
- SOFT
- };
-
-
- public static enum Option {
- /** Indicates that referential-equality (== instead of .equals()) should
- * be used when locating keys. This offers similar behavior to {@link IdentityHashMap} */
- IDENTITY_COMPARISONS
- };
-
- /* ---------------- Constants -------------- */
-
- static final ReferenceType DEFAULT_KEY_TYPE = ReferenceType.WEAK;
-
- static final ReferenceType DEFAULT_VALUE_TYPE = ReferenceType.STRONG;
-
-
- /**
- * The default initial capacity for this table,
- * used when not otherwise specified in a constructor.
- */
- static final int DEFAULT_INITIAL_CAPACITY = 16;
-
- /**
- * The default load factor for this table, used when not
- * otherwise specified in a constructor.
- */
- static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
- /**
- * The default concurrency level for this table, used when not
- * otherwise specified in a constructor.
- */
- static final int DEFAULT_CONCURRENCY_LEVEL = 16;
-
- /**
- * The maximum capacity, used if a higher value is implicitly
- * specified by either of the constructors with arguments. MUST
- * be a power of two <= 1<<30 to ensure that entries are indexable
- * using ints.
- */
- static final int MAXIMUM_CAPACITY = 1 << 30;
-
- /**
- * The maximum number of segments to allow; used to bound
- * constructor arguments.
- */
- static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
-
- /**
- * Number of unsynchronized retries in size and containsValue
- * methods before resorting to locking. This is used to avoid
- * unbounded retries if tables undergo continuous modification
- * which would make it impossible to obtain an accurate result.
- */
- static final int RETRIES_BEFORE_LOCK = 2;
-
- /* ---------------- Fields -------------- */
-
- /**
- * Mask value for indexing into segments. The upper bits of a
- * key's hash code are used to choose the segment.
- */
- final int segmentMask;
-
- /**
- * Shift value for indexing within segments.
- */
- final int segmentShift;
-
- /**
- * The segments, each of which is a specialized hash table
- */
- final Segment<K,V>[] segments;
-
- boolean identityComparisons;
-
- transient Set<K> keySet;
- transient Set<Map.Entry<K,V>> entrySet;
- transient Collection<V> values;
-
- /* ---------------- Small Utilities -------------- */
-
- /**
- * Applies a supplemental hash function to a given hashCode, which
- * defends against poor quality hash functions. This is critical
- * because ConcurrentReferenceHashMap uses power-of-two length hash tables,
- * that otherwise encounter collisions for hashCodes that do not
- * differ in lower or upper bits.
- */
- private static int hash(int h) {
- // Spread bits to regularize both segment and index locations,
- // using variant of single-word Wang/Jenkins hash.
- h += (h << 15) ^ 0xffffcd7d;
- h ^= (h >>> 10);
- h += (h << 3);
- h ^= (h >>> 6);
- h += (h << 2) + (h << 14);
- return h ^ (h >>> 16);
- }
-
- /**
- * Returns the segment that should be used for key with given hash
- * @param hash the hash code for the key
- * @return the segment
- */
- final Segment<K,V> segmentFor(int hash) {
- return segments[(hash >>> segmentShift) & segmentMask];
- }
-
- private int hashOf(Object key) {
- return hash(identityComparisons ?
- System.identityHashCode(key) : key.hashCode());
- }
-
- /* ---------------- Inner Classes -------------- */
-
- static interface KeyReference {
- int keyHash();
- Object keyRef();
- }
-
- /**
- * A weak-key reference which stores the key hash needed for reclamation.
- */
- static final class WeakKeyReference<K> extends WeakReference<K> implements KeyReference {
- final int hash;
- WeakKeyReference(K key, int hash, ReferenceQueue<Object> refQueue) {
- super(key, refQueue);
- this.hash = hash;
- }
- public final int keyHash() {
- return hash;
- }
-
- public final Object keyRef() {
- return this;
- }
- }
-
- /**
- * A soft-key reference which stores the key hash needed for reclamation.
- */
- static final class SoftKeyReference<K> extends SoftReference<K> implements KeyReference {
- final int hash;
- SoftKeyReference(K key, int hash, ReferenceQueue<Object> refQueue) {
- super(key, refQueue);
- this.hash = hash;
- }
- public final int keyHash() {
- return hash;
- }
-
- public final Object keyRef() {
- return this;
- }
- }
-
- static final class WeakValueReference<V> extends WeakReference<V> implements KeyReference {
- final Object keyRef;
- final int hash;
- WeakValueReference(V value, Object keyRef, int hash, ReferenceQueue<Object> refQueue) {
- super(value, refQueue);
- this.keyRef = keyRef;
- this.hash = hash;
- }
-
- public final int keyHash() {
- return hash;
- }
-
- public final Object keyRef() {
- return keyRef;
- }
- }
-
- static final class SoftValueReference<V> extends SoftReference<V> implements KeyReference {
- final Object keyRef;
- final int hash;
- SoftValueReference(V value, Object keyRef, int hash, ReferenceQueue<Object> refQueue) {
- super(value, refQueue);
- this.keyRef = keyRef;
- this.hash = hash;
- }
- public final int keyHash() {
- return hash;
- }
-
- public final Object keyRef() {
- return keyRef;
- }
- }
-
- /**
- * ConcurrentReferenceHashMap list entry. Note that this is never exported
- * out as a user-visible Map.Entry.
- *
- * Because the value field is volatile, not final, it is legal wrt
- * the Java Memory Model for an unsynchronized reader to see null
- * instead of initial value when read via a data race. Although a
- * reordering leading to this is not likely to ever actually
- * occur, the Segment.readValueUnderLock method is used as a
- * backup in case a null (pre-initialized) value is ever seen in
- * an unsynchronized access method.
- */
- static final class HashEntry<K,V> {
- final Object keyRef;
- final int hash;
- volatile Object valueRef;
- final HashEntry<K,V> next;
-
- HashEntry(K key, int hash, HashEntry<K,V> next, V value,
- ReferenceType keyType, ReferenceType valueType,
- ReferenceQueue<Object> refQueue) {
- this.hash = hash;
- this.next = next;
- this.keyRef = newKeyReference(key, keyType, refQueue);
- this.valueRef = newValueReference(value, valueType, refQueue);
- }
-
- final Object newKeyReference(K key, ReferenceType keyType,
- ReferenceQueue<Object> refQueue) {
- if (keyType == ReferenceType.WEAK)
- return new WeakKeyReference<K>(key, hash, refQueue);
- if (keyType == ReferenceType.SOFT)
- return new SoftKeyReference<K>(key, hash, refQueue);
-
- return key;
- }
-
- final Object newValueReference(V value, ReferenceType valueType,
- ReferenceQueue<Object> refQueue) {
- if (valueType == ReferenceType.WEAK)
- return new WeakValueReference<V>(value, keyRef, hash, refQueue);
- if (valueType == ReferenceType.SOFT)
- return new SoftValueReference<V>(value, keyRef, hash, refQueue);
-
- return value;
- }
-
- @SuppressWarnings("unchecked")
- final K key() {
- if (keyRef instanceof Reference)
- return ((Reference<K>)keyRef).get();
-
- return (K) keyRef;
- }
-
- final V value() {
- return dereferenceValue(valueRef);
- }
-
- @SuppressWarnings("unchecked")
- final V dereferenceValue(Object value) {
- if (value instanceof Reference)
- return ((Reference<V>)value).get();
-
- return (V) value;
- }
-
- final void setValue(V value, ReferenceType valueType, ReferenceQueue<Object> refQueue) {
- this.valueRef = newValueReference(value, valueType, refQueue);
- }
-
- @SuppressWarnings("unchecked")
- static final <K,V> HashEntry<K,V>[] newArray(int i) {
- return new HashEntry[i];
- }
- }
-
- /**
- * Segments are specialized versions of hash tables. This
- * subclasses from ReentrantLock opportunistically, just to
- * simplify some locking and avoid separate construction.
- */
- static final class Segment<K,V> extends ReentrantLock implements Serializable {
- /*
- * Segments maintain a table of entry lists that are ALWAYS
- * kept in a consistent state, so can be read without locking.
- * Next fields of nodes are immutable (final). All list
- * additions are performed at the front of each bin. This
- * makes it easy to check changes, and also fast to traverse.
- * When nodes would otherwise be changed, new nodes are
- * created to replace them. This works well for hash tables
- * since the bin lists tend to be short. (The average length
- * is less than two for the default load factor threshold.)
- *
- * Read operations can thus proceed without locking, but rely
- * on selected uses of volatiles to ensure that completed
- * write operations performed by other threads are
- * noticed. For most purposes, the "count" field, tracking the
- * number of elements, serves as that volatile variable
- * ensuring visibility. This is convenient because this field
- * needs to be read in many read operations anyway:
- *
- * - All (unsynchronized) read operations must first read the
- * "count" field, and should not look at table entries if
- * it is 0.
- *
- * - All (synchronized) write operations should write to
- * the "count" field after structurally changing any bin.
- * The operations must not take any action that could even
- * momentarily cause a concurrent read operation to see
- * inconsistent data. This is made easier by the nature of
- * the read operations in Map. For example, no operation
- * can reveal that the table has grown but the threshold
- * has not yet been updated, so there are no atomicity
- * requirements for this with respect to reads.
- *
- * As a guide, all critical volatile reads and writes to the
- * count field are marked in code comments.
- */
-
- private static final long serialVersionUID = 2249069246763182397L;
-
- /**
- * The number of elements in this segment's region.
- */
- transient volatile int count;
-
- /**
- * Number of updates that alter the size of the table. This is
- * used during bulk-read methods to make sure they see a
- * consistent snapshot: If modCounts change during a traversal
- * of segments computing size or checking containsValue, then
- * we might have an inconsistent view of state so (usually)
- * must retry.
- */
- transient int modCount;
-
- /**
- * The table is rehashed when its size exceeds this threshold.
- * (The value of this field is always <tt>(int)(capacity *
- * loadFactor)</tt>.)
- */
- transient int threshold;
-
- /**
- * The per-segment table.
- */
- transient volatile HashEntry<K,V>[] table;
-
- /**
- * The load factor for the hash table. Even though this value
- * is same for all segments, it is replicated to avoid needing
- * links to outer object.
- * @serial
- */
- final float loadFactor;
-
- /**
- * The collected weak-key reference queue for this segment.
- * This should be (re)initialized whenever table is assigned,
- */
- transient volatile ReferenceQueue<Object> refQueue;
-
- final ReferenceType keyType;
-
- final ReferenceType valueType;
-
- final boolean identityComparisons;
-
- Segment(int initialCapacity, float lf, ReferenceType keyType,
- ReferenceType valueType, boolean identityComparisons) {
- loadFactor = lf;
- this.keyType = keyType;
- this.valueType = valueType;
- this.identityComparisons = identityComparisons;
- setTable(HashEntry.<K,V>newArray(initialCapacity));
- }
-
- @SuppressWarnings("unchecked")
- static final <K,V> Segment<K,V>[] newArray(int i) {
- return new Segment[i];
- }
-
- private boolean keyEq(Object src, Object dest) {
- return identityComparisons ? src == dest : src.equals(dest);
- }
-
- /**
- * Sets table to new HashEntry array.
- * Call only while holding lock or in constructor.
- */
- void setTable(HashEntry<K,V>[] newTable) {
- threshold = (int)(newTable.length * loadFactor);
- table = newTable;
- refQueue = new ReferenceQueue<Object>();
- }
-
- /**
- * Returns properly casted first entry of bin for given hash.
- */
- HashEntry<K,V> getFirst(int hash) {
- HashEntry<K,V>[] tab = table;
- return tab[hash & (tab.length - 1)];
- }
-
- HashEntry<K,V> newHashEntry(K key, int hash, HashEntry<K, V> next, V value) {
- return new HashEntry<K,V>(key, hash, next, value, keyType, valueType, refQueue);
- }
-
- /**
- * Reads value field of an entry under lock. Called if value
- * field ever appears to be null. This is possible only if a
- * compiler happens to reorder a HashEntry initialization with
- * its table assignment, which is legal under memory model
- * but is not known to ever occur.
- */
- V readValueUnderLock(HashEntry<K,V> e) {
- lock();
- try {
- removeStale();
- return e.value();
- } finally {
- unlock();
- }
- }
-
- /* Specialized implementations of map methods */
-
- V get(Object key, int hash) {
- if (count != 0) { // read-volatile
- HashEntry<K,V> e = getFirst(hash);
- while (e != null) {
- if (e.hash == hash && keyEq(key, e.key())) {
- Object opaque = e.valueRef;
- if (opaque != null)
- return e.dereferenceValue(opaque);
-
- return readValueUnderLock(e); // recheck
- }
- e = e.next;
- }
- }
- return null;
- }
-
- boolean containsKey(Object key, int hash) {
- if (count != 0) { // read-volatile
- HashEntry<K,V> e = getFirst(hash);
- while (e != null) {
- if (e.hash == hash && keyEq(key, e.key()))
- return true;
- e = e.next;
- }
- }
- return false;
- }
-
- boolean containsValue(Object value) {
- if (count != 0) { // read-volatile
- HashEntry<K,V>[] tab = table;
- int len = tab.length;
- for (int i = 0 ; i < len; i++) {
- for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
- Object opaque = e.valueRef;
- V v;
-
- if (opaque == null)
- v = readValueUnderLock(e); // recheck
- else
- v = e.dereferenceValue(opaque);
-
- if (value.equals(v))
- return true;
- }
- }
- }
- return false;
- }
-
- boolean replace(K key, int hash, V oldValue, V newValue) {
- lock();
- try {
- removeStale();
- HashEntry<K,V> e = getFirst(hash);
- while (e != null && (e.hash != hash || !keyEq(key, e.key())))
- e = e.next;
-
- boolean replaced = false;
- if (e != null && oldValue.equals(e.value())) {
- replaced = true;
- e.setValue(newValue, valueType, refQueue);
- }
- return replaced;
- } finally {
- unlock();
- }
- }
-
- V replace(K key, int hash, V newValue) {
- lock();
- try {
- removeStale();
- HashEntry<K,V> e = getFirst(hash);
- while (e != null && (e.hash != hash || !keyEq(key, e.key())))
- e = e.next;
-
- V oldValue = null;
- if (e != null) {
- oldValue = e.value();
- e.setValue(newValue, valueType, refQueue);
- }
- return oldValue;
- } finally {
- unlock();
- }
- }
-
-
- V put(K key, int hash, V value, boolean onlyIfAbsent) {
- lock();
- try {
- removeStale();
- int c = count;
- if (c++ > threshold) {// ensure capacity
- int reduced = rehash();
- if (reduced > 0) // adjust from possible weak cleanups
- count = (c -= reduced) - 1; // write-volatile
- }
-
- HashEntry<K,V>[] tab = table;
- int index = hash & (tab.length - 1);
- HashEntry<K,V> first = tab[index];
- HashEntry<K,V> e = first;
- while (e != null && (e.hash != hash || !keyEq(key, e.key())))
- e = e.next;
-
- V oldValue;
- if (e != null) {
- oldValue = e.value();
- if (!onlyIfAbsent)
- e.setValue(value, valueType, refQueue);
- }
- else {
- oldValue = null;
- ++modCount;
- tab[index] = newHashEntry(key, hash, first, value);
- count = c; // write-volatile
- }
- return oldValue;
- } finally {
- unlock();
- }
- }
-
- int rehash() {
- HashEntry<K,V>[] oldTable = table;
- int oldCapacity = oldTable.length;
- if (oldCapacity >= MAXIMUM_CAPACITY)
- return 0;
-
- /*
- * Reclassify nodes in each list to new Map. Because we are
- * using power-of-two expansion, the elements from each bin
- * must either stay at same index, or move with a power of two
- * offset. We eliminate unnecessary node creation by catching
- * cases where old nodes can be reused because their next
- * fields won't change. Statistically, at the default
- * threshold, only about one-sixth of them need cloning when
- * a table doubles. The nodes they replace will be garbage
- * collectable as soon as they are no longer referenced by any
- * reader thread that may be in the midst of traversing table
- * right now.
- */
-
- HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
- threshold = (int)(newTable.length * loadFactor);
- int sizeMask = newTable.length - 1;
- int reduce = 0;
- for (int i = 0; i < oldCapacity ; i++) {
- // We need to guarantee that any existing reads of old Map can
- // proceed. So we cannot yet null out each bin.
- HashEntry<K,V> e = oldTable[i];
-
- if (e != null) {
- HashEntry<K,V> next = e.next;
- int idx = e.hash & sizeMask;
-
- // Single node on list
- if (next == null)
- newTable[idx] = e;
-
- else {
- // Reuse trailing consecutive sequence at same slot
- HashEntry<K,V> lastRun = e;
- int lastIdx = idx;
- for (HashEntry<K,V> last = next;
- last != null;
- last = last.next) {
- int k = last.hash & sizeMask;
- if (k != lastIdx) {
- lastIdx = k;
- lastRun = last;
- }
- }
- newTable[lastIdx] = lastRun;
- // Clone all remaining nodes
- for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
- // Skip GC'd weak refs
- K key = p.key();
- if (key == null) {
- reduce++;
- continue;
- }
- int k = p.hash & sizeMask;
- HashEntry<K,V> n = newTable[k];
- newTable[k] = newHashEntry(key, p.hash, n, p.value());
- }
- }
- }
- }
- table = newTable;
- return reduce;
- }
-
- /**
- * Remove; match on key only if value null, else match both.
- */
- V remove(Object key, int hash, Object value, boolean refRemove) {
- lock();
- try {
- if (!refRemove)
- removeStale();
- int c = count - 1;
- HashEntry<K,V>[] tab = table;
- int index = hash & (tab.length - 1);
- HashEntry<K,V> first = tab[index];
- HashEntry<K,V> e = first;
- // a ref remove operation compares the Reference instance
- while (e != null && key != e.keyRef
- && (refRemove || hash != e.hash || !keyEq(key, e.key())))
- e = e.next;
-
- V oldValue = null;
- if (e != null) {
- V v = e.value();
- if (value == null || value.equals(v)) {
- oldValue = v;
- // All entries following removed node can stay
- // in list, but all preceding ones need to be
- // cloned.
- ++modCount;
- HashEntry<K,V> newFirst = e.next;
- for (HashEntry<K,V> p = first; p != e; p = p.next) {
- K pKey = p.key();
- if (pKey == null) { // Skip GC'd keys
- c--;
- continue;
- }
-
- newFirst = newHashEntry(pKey, p.hash, newFirst, p.value());
- }
- tab[index] = newFirst;
- count = c; // write-volatile
- }
- }
- return oldValue;
- } finally {
- unlock();
- }
- }
-
- final void removeStale() {
- KeyReference ref;
- while ((ref = (KeyReference) refQueue.poll()) != null) {
- remove(ref.keyRef(), ref.keyHash(), null, true);
- }
- }
-
- void clear() {
- if (count != 0) {
- lock();
- try {
- HashEntry<K,V>[] tab = table;
- for (int i = 0; i < tab.length ; i++)
- tab[i] = null;
- ++modCount;
- // replace the reference queue to avoid unnecessary stale cleanups
- refQueue = new ReferenceQueue<Object>();
- count = 0; // write-volatile
- } finally {
- unlock();
- }
- }
- }
- }
-
-
-
- /* ---------------- Public operations -------------- */
-
- /**
- * Creates a new, empty map with the specified initial
- * capacity, reference types, load factor and concurrency level.
- *
- * Behavioral changing options such as {@link Option#IDENTITY_COMPARISONS}
- * can also be specified.
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements.
- * @param loadFactor the load factor threshold, used to control resizing.
- * Resizing may be performed when the average number of elements per
- * bin exceeds this threshold.
- * @param concurrencyLevel the estimated number of concurrently
- * updating threads. The implementation performs internal sizing
- * to try to accommodate this many threads.
- * @param keyType the reference type to use for keys
- * @param valueType the reference type to use for values
- * @param options the behavioral options
- * @throws IllegalArgumentException if the initial capacity is
- * negative or the load factor or concurrencyLevel are
- * nonpositive.
- */
- public ConcurrentReferenceHashMap(int initialCapacity,
- float loadFactor, int concurrencyLevel,
- ReferenceType keyType, ReferenceType valueType,
- EnumSet<Option> options) {
- if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
- throw new IllegalArgumentException();
-
- if (concurrencyLevel > MAX_SEGMENTS)
- concurrencyLevel = MAX_SEGMENTS;
-
- // Find power-of-two sizes best matching arguments
- int sshift = 0;
- int ssize = 1;
- while (ssize < concurrencyLevel) {
- ++sshift;
- ssize <<= 1;
- }
- segmentShift = 32 - sshift;
- segmentMask = ssize - 1;
- this.segments = Segment.newArray(ssize);
-
- if (initialCapacity > MAXIMUM_CAPACITY)
- initialCapacity = MAXIMUM_CAPACITY;
- int c = initialCapacity / ssize;
- if (c * ssize < initialCapacity)
- ++c;
- int cap = 1;
- while (cap < c)
- cap <<= 1;
-
- identityComparisons = options != null && options.contains(Option.IDENTITY_COMPARISONS);
-
- for (int i = 0; i < this.segments.length; ++i)
- this.segments[i] = new Segment<K,V>(cap, loadFactor,
- keyType, valueType, identityComparisons);
- }
-
- /**
- * Creates a new, empty map with the specified initial
- * capacity, load factor and concurrency level.
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements.
- * @param loadFactor the load factor threshold, used to control resizing.
- * Resizing may be performed when the average number of elements per
- * bin exceeds this threshold.
- * @param concurrencyLevel the estimated number of concurrently
- * updating threads. The implementation performs internal sizing
- * to try to accommodate this many threads.
- * @throws IllegalArgumentException if the initial capacity is
- * negative or the load factor or concurrencyLevel are
- * nonpositive.
- */
- public ConcurrentReferenceHashMap(int initialCapacity,
- float loadFactor, int concurrencyLevel) {
- this(initialCapacity, loadFactor, concurrencyLevel,
- DEFAULT_KEY_TYPE, DEFAULT_VALUE_TYPE, null);
- }
-
- /**
- * Creates a new, empty map with the specified initial capacity
- * and load factor and with the default reference types (weak keys,
- * strong values), and concurrencyLevel (16).
- *
- * @param initialCapacity The implementation performs internal
- * sizing to accommodate this many elements.
- * @param loadFactor the load factor threshold, used to control resizing.
- * Resizing may be performed when the average number of elements per
- * bin exceeds this threshold.
- * @throws IllegalArgumentException if the initial capacity of
- * elements is negative or the load factor is nonpositive
- *
- * @since 1.6
- */
- public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor) {
- this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
- }
-
-
- /**
- * Creates a new, empty map with the specified initial capacity,
- * reference types and with default load factor (0.75) and concurrencyLevel (16).
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements.
- * @param keyType the reference type to use for keys
- * @param valueType the reference type to use for values
- * @throws IllegalArgumentException if the initial capacity of
- * elements is negative.
- */
- public ConcurrentReferenceHashMap(int initialCapacity,
- ReferenceType keyType, ReferenceType valueType) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL,
- keyType, valueType, null);
- }
-
- /**
- * Creates a new, empty map with the specified initial capacity,
- * and with default reference types (weak keys, strong values),
- * load factor (0.75) and concurrencyLevel (16).
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements.
- * @throws IllegalArgumentException if the initial capacity of
- * elements is negative.
- */
- public ConcurrentReferenceHashMap(int initialCapacity) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
- }
-
- /**
- * Creates a new, empty map with a default initial capacity (16),
- * reference types (weak keys, strong values), default
- * load factor (0.75) and concurrencyLevel (16).
- */
- public ConcurrentReferenceHashMap() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
- }
-
- /**
- * Creates a new map with the same mappings as the given map.
- * The map is created with a capacity of 1.5 times the number
- * of mappings in the given map or 16 (whichever is greater),
- * and a default load factor (0.75) and concurrencyLevel (16).
- *
- * @param m the map
- */
- public ConcurrentReferenceHashMap(Map<? extends K, ? extends V> m) {
- this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
- DEFAULT_INITIAL_CAPACITY),
- DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
- putAll(m);
- }
-
- /**
- * Returns <tt>true</tt> if this map contains no key-value mappings.
- *
- * @return <tt>true</tt> if this map contains no key-value mappings
- */
- public boolean isEmpty() {
- final Segment<K,V>[] segments = this.segments;
- /*
- * We keep track of per-segment modCounts to avoid ABA
- * problems in which an element in one segment was added and
- * in another removed during traversal, in which case the
- * table was never actually empty at any point. Note the
- * similar use of modCounts in the size() and containsValue()
- * methods, which are the only other methods also susceptible
- * to ABA problems.
- */
- int[] mc = new int[segments.length];
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++i) {
- if (segments[i].count != 0)
- return false;
- else
- mcsum += mc[i] = segments[i].modCount;
- }
- // If mcsum happens to be zero, then we know we got a snapshot
- // before any modifications at all were made. This is
- // probably common enough to bother tracking.
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++i) {
- if (segments[i].count != 0 ||
- mc[i] != segments[i].modCount)
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns the number of key-value mappings in this map. If the
- * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
- * <tt>Integer.MAX_VALUE</tt>.
- *
- * @return the number of key-value mappings in this map
- */
- public int size() {
- final Segment<K,V>[] segments = this.segments;
- long sum = 0;
- long check = 0;
- int[] mc = new int[segments.length];
- // Try a few times to get accurate count. On failure due to
- // continuous async changes in table, resort to locking.
- for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
- check = 0;
- sum = 0;
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++i) {
- sum += segments[i].count;
- mcsum += mc[i] = segments[i].modCount;
- }
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++i) {
- check += segments[i].count;
- if (mc[i] != segments[i].modCount) {
- check = -1; // force retry
- break;
- }
- }
- }
- if (check == sum)
- break;
- }
- if (check != sum) { // Resort to locking all segments
- sum = 0;
- for (int i = 0; i < segments.length; ++i)
- segments[i].lock();
- for (int i = 0; i < segments.length; ++i)
- sum += segments[i].count;
- for (int i = 0; i < segments.length; ++i)
- segments[i].unlock();
- }
- if (sum > Integer.MAX_VALUE)
- return Integer.MAX_VALUE;
- else
- return (int)sum;
- }
-
- /**
- * Returns the value to which the specified key is mapped,
- * or {@code null} if this map contains no mapping for the key.
- *
- * <p>More formally, if this map contains a mapping from a key
- * {@code k} to a value {@code v} such that {@code key.equals(k)},
- * then this method returns {@code v}; otherwise it returns
- * {@code null}. (There can be at most one such mapping.)
- *
- * @throws NullPointerException if the specified key is null
- */
- public V get(Object key) {
- int hash = hashOf(key);
- return segmentFor(hash).get(key, hash);
- }
-
- /**
- * Tests if the specified object is a key in this table.
- *
- * @param key possible key
- * @return <tt>true</tt> if and only if the specified object
- * is a key in this table, as determined by the
- * <tt>equals</tt> method; <tt>false</tt> otherwise.
- * @throws NullPointerException if the specified key is null
- */
- public boolean containsKey(Object key) {
- int hash = hashOf(key);
- return segmentFor(hash).containsKey(key, hash);
- }
-
- /**
- * Returns <tt>true</tt> if this map maps one or more keys to the
- * specified value. Note: This method requires a full internal
- * traversal of the hash table, and so is much slower than
- * method <tt>containsKey</tt>.
- *
- * @param value value whose presence in this map is to be tested
- * @return <tt>true</tt> if this map maps one or more keys to the
- * specified value
- * @throws NullPointerException if the specified value is null
- */
- public boolean containsValue(Object value) {
- if (value == null)
- throw new NullPointerException();
-
- // See explanation of modCount use above
-
- final Segment<K,V>[] segments = this.segments;
- int[] mc = new int[segments.length];
-
- // Try a few times without locking
- for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
- int sum = 0;
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++i) {
- int c = segments[i].count;
- mcsum += mc[i] = segments[i].modCount;
- if (segments[i].containsValue(value))
- return true;
- }
- boolean cleanSweep = true;
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++i) {
- int c = segments[i].count;
- if (mc[i] != segments[i].modCount) {
- cleanSweep = false;
- break;
- }
- }
- }
- if (cleanSweep)
- return false;
- }
- // Resort to locking all segments
- for (int i = 0; i < segments.length; ++i)
- segments[i].lock();
- boolean found = false;
- try {
- for (int i = 0; i < segments.length; ++i) {
- if (segments[i].containsValue(value)) {
- found = true;
- break;
- }
- }
- } finally {
- for (int i = 0; i < segments.length; ++i)
- segments[i].unlock();
- }
- return found;
- }
-
- /**
- * Legacy method testing if some key maps into the specified value
- * in this table. This method is identical in functionality to
- * {@link #containsValue}, and exists solely to ensure
- * full compatibility with class {@link java.util.Hashtable},
- * which supported this method prior to introduction of the
- * Java Collections framework.
-
- * @param value a value to search for
- * @return <tt>true</tt> if and only if some key maps to the
- * <tt>value</tt> argument in this table as
- * determined by the <tt>equals</tt> method;
- * <tt>false</tt> otherwise
- * @throws NullPointerException if the specified value is null
- */
- public boolean contains(Object value) {
- return containsValue(value);
- }
-
- /**
- * Maps the specified key to the specified value in this table.
- * Neither the key nor the value can be null.
- *
- * <p> The value can be retrieved by calling the <tt>get</tt> method
- * with a key that is equal to the original key.
- *
- * @param key key with which the specified value is to be associated
- * @param value value to be associated with the specified key
- * @return the previous value associated with <tt>key</tt>, or
- * <tt>null</tt> if there was no mapping for <tt>key</tt>
- * @throws NullPointerException if the specified key or value is null
- */
- public V put(K key, V value) {
- if (value == null)
- throw new NullPointerException();
- int hash = hashOf(key);
- return segmentFor(hash).put(key, hash, value, false);
- }
-
- /**
- * {@inheritDoc}
- *
- * @return the previous value associated with the specified key,
- * or <tt>null</tt> if there was no mapping for the key
- * @throws NullPointerException if the specified key or value is null
- */
- public V putIfAbsent(K key, V value) {
- if (value == null)
- throw new NullPointerException();
- int hash = hashOf(key);
- return segmentFor(hash).put(key, hash, value, true);
- }
-
- /**
- * Copies all of the mappings from the specified map to this one.
- * These mappings replace any mappings that this map had for any of the
- * keys currently in the specified map.
- *
- * @param m mappings to be stored in this map
- */
- public void putAll(Map<? extends K, ? extends V> m) {
- for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
- put(e.getKey(), e.getValue());
- }
-
- /**
- * Removes the key (and its corresponding value) from this map.
- * This method does nothing if the key is not in the map.
- *
- * @param key the key that needs to be removed
- * @return the previous value associated with <tt>key</tt>, or
- * <tt>null</tt> if there was no mapping for <tt>key</tt>
- * @throws NullPointerException if the specified key is null
- */
- public V remove(Object key) {
- int hash = hashOf(key);
- return segmentFor(hash).remove(key, hash, null, false);
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws NullPointerException if the specified key is null
- */
- public boolean remove(Object key, Object value) {
- int hash = hashOf(key);
- if (value == null)
- return false;
- return segmentFor(hash).remove(key, hash, value, false) != null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws NullPointerException if any of the arguments are null
- */
- public boolean replace(K key, V oldValue, V newValue) {
- if (oldValue == null || newValue == null)
- throw new NullPointerException();
- int hash = hashOf(key);
- return segmentFor(hash).replace(key, hash, oldValue, newValue);
- }
-
- /**
- * {@inheritDoc}
- *
- * @return the previous value associated with the specified key,
- * or <tt>null</tt> if there was no mapping for the key
- * @throws NullPointerException if the specified key or value is null
- */
- public V replace(K key, V value) {
- if (value == null)
- throw new NullPointerException();
- int hash = hashOf(key);
- return segmentFor(hash).replace(key, hash, value);
- }
-
- /**
- * Removes all of the mappings from this map.
- */
- public void clear() {
- for (int i = 0; i < segments.length; ++i)
- segments[i].clear();
- }
-
- /**
- * Removes any stale entries whose keys have been finalized. Use of this
- * method is normally not necessary since stale entries are automatically
- * removed lazily, when blocking operations are required. However, there
- * are some cases where this operation should be performed eagerly, such
- * as cleaning up old references to a ClassLoader in a multi-classloader
- * environment.
- *
- * Note: this method will acquire locks, one at a time, across all segments
- * of this table, so if it is to be used, it should be used sparingly.
- */
- public void purgeStaleEntries() {
- for (int i = 0; i < segments.length; ++i)
- segments[i].removeStale();
- }
-
-
- /**
- * Returns a {@link Set} view of the keys contained in this map.
- * The set is backed by the map, so changes to the map are
- * reflected in the set, and vice-versa. The set supports element
- * removal, which removes the corresponding mapping from this map,
- * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
- * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
- * operations. It does not support the <tt>add</tt> or
- * <tt>addAll</tt> operations.
- *
- * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
- * that will never throw {@link ConcurrentModificationException},
- * and guarantees to traverse elements as they existed upon
- * construction of the iterator, and may (but is not guaranteed to)
- * reflect any modifications subsequent to construction.
- */
- public Set<K> keySet() {
- Set<K> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet());
- }
-
- /**
- * Returns a {@link Collection} view of the values contained in this map.
- * The collection is backed by the map, so changes to the map are
- * reflected in the collection, and vice-versa. The collection
- * supports element removal, which removes the corresponding
- * mapping from this map, via the <tt>Iterator.remove</tt>,
- * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
- * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not
- * support the <tt>add</tt> or <tt>addAll</tt> operations.
- *
- * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
- * that will never throw {@link ConcurrentModificationException},
- * and guarantees to traverse elements as they existed upon
- * construction of the iterator, and may (but is not guaranteed to)
- * reflect any modifications subsequent to construction.
- */
- public Collection<V> values() {
- Collection<V> vs = values;
- return (vs != null) ? vs : (values = new Values());
- }
-
- /**
- * Returns a {@link Set} view of the mappings contained in this map.
- * The set is backed by the map, so changes to the map are
- * reflected in the set, and vice-versa. The set supports element
- * removal, which removes the corresponding mapping from the map,
- * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
- * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
- * operations. It does not support the <tt>add</tt> or
- * <tt>addAll</tt> operations.
- *
- * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
- * that will never throw {@link ConcurrentModificationException},
- * and guarantees to traverse elements as they existed upon
- * construction of the iterator, and may (but is not guaranteed to)
- * reflect any modifications subsequent to construction.
- */
- public Set<Map.Entry<K,V>> entrySet() {
- Set<Map.Entry<K,V>> es = entrySet;
- return (es != null) ? es : (entrySet = new EntrySet());
- }
-
- /**
- * Returns an enumeration of the keys in this table.
- *
- * @return an enumeration of the keys in this table
- * @see #keySet()
- */
- public Enumeration<K> keys() {
- return new KeyIterator();
- }
-
- /**
- * Returns an enumeration of the values in this table.
- *
- * @return an enumeration of the values in this table
- * @see #values()
- */
- public Enumeration<V> elements() {
- return new ValueIterator();
- }
-
- /* ---------------- Iterator Support -------------- */
-
- abstract class HashIterator {
- int nextSegmentIndex;
- int nextTableIndex;
- HashEntry<K,V>[] currentTable;
- HashEntry<K, V> nextEntry;
- HashEntry<K, V> lastReturned;
- K currentKey; // Strong reference to weak key (prevents gc)
-
- HashIterator() {
- nextSegmentIndex = segments.length - 1;
- nextTableIndex = -1;
- advance();
- }
-
- public boolean hasMoreElements() { return hasNext(); }
-
- final void advance() {
- if (nextEntry != null && (nextEntry = nextEntry.next) != null)
- return;
-
- while (nextTableIndex >= 0) {
- if ( (nextEntry = currentTable[nextTableIndex--]) != null)
- return;
- }
-
- while (nextSegmentIndex >= 0) {
- Segment<K,V> seg = segments[nextSegmentIndex--];
- if (seg.count != 0) {
- currentTable = seg.table;
- for (int j = currentTable.length - 1; j >= 0; --j) {
- if ( (nextEntry = currentTable[j]) != null) {
- nextTableIndex = j - 1;
- return;
- }
- }
- }
- }
- }
-
- public boolean hasNext() {
- while (nextEntry != null) {
- if (nextEntry.key() != null)
- return true;
- advance();
- }
-
- return false;
- }
-
- HashEntry<K,V> nextEntry() {
- do {
- if (nextEntry == null)
- throw new NoSuchElementException();
-
- lastReturned = nextEntry;
- currentKey = lastReturned.key();
- advance();
- } while (currentKey == null); // Skip GC'd keys
-
- return lastReturned;
- }
-
- public void remove() {
- if (lastReturned == null)
- throw new IllegalStateException();
- ConcurrentReferenceHashMap.this.remove(currentKey);
- lastReturned = null;
- }
- }
-
- final class KeyIterator
- extends HashIterator
- implements Iterator<K>, Enumeration<K>
- {
- public K next() { return super.nextEntry().key(); }
- public K nextElement() { return super.nextEntry().key(); }
- }
-
- final class ValueIterator
- extends HashIterator
- implements Iterator<V>, Enumeration<V>
- {
- public V next() { return super.nextEntry().value(); }
- public V nextElement() { return super.nextEntry().value(); }
- }
-
- /*
- * This class is needed for JDK5 compatibility.
- */
- static class SimpleEntry<K, V> implements Entry<K, V>,
- java.io.Serializable {
- private static final long serialVersionUID = -8499721149061103585L;
-
- private final K key;
- private V value;
-
- public SimpleEntry(K key, V value) {
- this.key = key;
- this.value = value;
- }
-
- public SimpleEntry(Entry<? extends K, ? extends V> entry) {
- this.key = entry.getKey();
- this.value = entry.getValue();
- }
-
- public K getKey() {
- return key;
- }
-
- public V getValue() {
- return value;
- }
-
- public V setValue(V value) {
- V oldValue = this.value;
- this.value = value;
- return oldValue;
- }
-
- public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- @SuppressWarnings("unchecked")
- Map.Entry e = (Map.Entry) o;
- return eq(key, e.getKey()) && eq(value, e.getValue());
- }
-
- public int hashCode() {
- return (key == null ? 0 : key.hashCode())
- ^ (value == null ? 0 : value.hashCode());
- }
-
- public String toString() {
- return key + "=" + value;
- }
-
- private static boolean eq(Object o1, Object o2) {
- return o1 == null ? o2 == null : o1.equals(o2);
- }
- }
-
-
- /**
- * Custom Entry class used by EntryIterator.next(), that relays setValue
- * changes to the underlying map.
- */
- final class WriteThroughEntry extends SimpleEntry<K,V>
- {
- private static final long serialVersionUID = -7900634345345313646L;
-
- WriteThroughEntry(K k, V v) {
- super(k,v);
- }
-
- /**
- * Set our entry's value and write through to the map. The
- * value to return is somewhat arbitrary here. Since a
- * WriteThroughEntry does not necessarily track asynchronous
- * changes, the most recent "previous" value could be
- * different from what we return (or could even have been
- * removed in which case the put will re-establish). We do not
- * and cannot guarantee more.
- */
- public V setValue(V value) {
- if (value == null) throw new NullPointerException();
- V v = super.setValue(value);
- ConcurrentReferenceHashMap.this.put(getKey(), value);
- return v;
- }
- }
-
- final class EntryIterator
- extends HashIterator
- implements Iterator<Entry<K,V>>
- {
- public Map.Entry<K,V> next() {
- HashEntry<K,V> e = super.nextEntry();
- return new WriteThroughEntry(e.key(), e.value());
- }
- }
-
- final class KeySet extends AbstractSet<K> {
- public Iterator<K> iterator() {
- return new KeyIterator();
- }
- public int size() {
- return ConcurrentReferenceHashMap.this.size();
- }
- public boolean isEmpty() {
- return ConcurrentReferenceHashMap.this.isEmpty();
- }
- public boolean contains(Object o) {
- return ConcurrentReferenceHashMap.this.containsKey(o);
- }
- public boolean remove(Object o) {
- return ConcurrentReferenceHashMap.this.remove(o) != null;
- }
- public void clear() {
- ConcurrentReferenceHashMap.this.clear();
- }
- }
-
- final class Values extends AbstractCollection<V> {
- public Iterator<V> iterator() {
- return new ValueIterator();
- }
- public int size() {
- return ConcurrentReferenceHashMap.this.size();
- }
- public boolean isEmpty() {
- return ConcurrentReferenceHashMap.this.isEmpty();
- }
- public boolean contains(Object o) {
- return ConcurrentReferenceHashMap.this.containsValue(o);
- }
- public void clear() {
- ConcurrentReferenceHashMap.this.clear();
- }
- }
-
- final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
- public Iterator<Map.Entry<K,V>> iterator() {
- return new EntryIterator();
- }
- public boolean contains(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- V v = ConcurrentReferenceHashMap.this.get(e.getKey());
- return v != null && v.equals(e.getValue());
- }
- public boolean remove(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- return ConcurrentReferenceHashMap.this.remove(e.getKey(), e.getValue());
- }
- public int size() {
- return ConcurrentReferenceHashMap.this.size();
- }
- public boolean isEmpty() {
- return ConcurrentReferenceHashMap.this.isEmpty();
- }
- public void clear() {
- ConcurrentReferenceHashMap.this.clear();
- }
- }
-
- /* ---------------- Serialization Support -------------- */
-
- /**
- * Save the state of the <tt>ConcurrentReferenceHashMap</tt> instance to a
- * stream (i.e., serialize it).
- * @param s the stream
- * @serialData
- * the key (Object) and value (Object)
- * for each key-value mapping, followed by a null pair.
- * The key-value mappings are emitted in no particular order.
- */
- private void writeObject(java.io.ObjectOutputStream s) throws IOException {
- s.defaultWriteObject();
-
- for (int k = 0; k < segments.length; ++k) {
- Segment<K,V> seg = segments[k];
- seg.lock();
- try {
- HashEntry<K,V>[] tab = seg.table;
- for (int i = 0; i < tab.length; ++i) {
- for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
- K key = e.key();
- if (key == null) // Skip GC'd keys
- continue;
-
- s.writeObject(key);
- s.writeObject(e.value());
- }
- }
- } finally {
- seg.unlock();
- }
- }
- s.writeObject(null);
- s.writeObject(null);
- }
-
- /**
- * Reconstitute the <tt>ConcurrentReferenceHashMap</tt> instance from a
- * stream (i.e., deserialize it).
- * @param s the stream
- */
- @SuppressWarnings("unchecked")
- private void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- s.defaultReadObject();
-
- // Initialize each segment to be minimally sized, and let grow.
- for (int i = 0; i < segments.length; ++i) {
- segments[i].setTable(new HashEntry[1]);
- }
-
- // Read the keys and values, and put the mappings in the table
- for (;;) {
- K key = (K) s.readObject();
- V value = (V) s.readObject();
- if (key == null)
- break;
- put(key, value);
- }
- }
-}
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/CopyOnWriteHashMap.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/CopyOnWriteHashMap.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/CopyOnWriteHashMap.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -0,0 +1,205 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.HashMap;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonMap;
+import static java.util.Collections.unmodifiableMap;
+import static java.util.Collections.unmodifiableCollection;
+import static java.util.Collections.unmodifiableSet;
+import java.util.concurrent.ConcurrentMap;
+
+final class CopyOnWriteHashMap<K, V> implements ConcurrentMap<K, V> {
+ private final Object writeLock = new Object();
+ private volatile Map<K, V> map = emptyMap();
+
+ public V putIfAbsent(final K key, final V value) {
+ if (key == null) {
+ throw new NullPointerException("key is null");
+ }
+ if (value == null) {
+ throw new NullPointerException("value is null");
+ }
+ synchronized (writeLock) {
+ final Map<K, V> map = this.map;
+ final V old = map.get(key);
+ if (old != null) return old;
+ if (map.size() == 0) {
+ this.map = singletonMap(key, value);
+ } else {
+ final HashMap<K, V> copy = new HashMap<K, V>(map);
+ map.put(key, value);
+ this.map = copy;
+ }
+ return null;
+ }
+ }
+
+ public boolean remove(final Object key, final Object value) {
+ if (key == null || value == null) return false;
+ synchronized (writeLock) {
+ final Map<K, V> map = this.map;
+ final V old = map.get(key);
+ if (old == null) {
+ return false;
+ }
+ if (map.size() == 1) {
+ this.map = emptyMap();
+ } else {
+ final HashMap<K, V> copy = new HashMap<K, V>(map);
+ map.remove(key);
+ this.map = copy;
+ }
+ return true;
+ }
+ }
+
+ public boolean replace(final K key, final V oldValue, final V newValue) {
+ if (key == null || oldValue == null) return false;
+ if (newValue == null) {
+ throw new NullPointerException("newValue is null");
+ }
+ synchronized (writeLock) {
+ final Map<K, V> map = this.map;
+ final V old = map.get(key);
+ if (old == null) {
+ return false;
+ }
+ if (map.size() == 1) {
+ this.map = singletonMap(key, newValue);
+ } else {
+ final HashMap<K, V> copy = new HashMap<K, V>(map);
+ map.put(key, newValue);
+ this.map = copy;
+ }
+ return true;
+ }
+ }
+
+ public V replace(final K key, final V value) {
+ if (key == null) {
+ return null;
+ }
+ if (value == null) {
+ throw new NullPointerException("value is null");
+ }
+ synchronized (writeLock) {
+ final Map<K, V> map = this.map;
+ final V old = map.get(key);
+ if (old != null) {
+ if (map.size() == 1) {
+ this.map = singletonMap(key, value);
+ } else {
+ final HashMap<K, V> copy = new HashMap<K, V>(map);
+ map.put(key, value);
+ this.map = copy;
+ }
+ }
+ return old;
+ }
+ }
+
+ public int size() {
+ return map.size();
+ }
+
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ public boolean containsKey(final Object key) {
+ return map.containsKey(key);
+ }
+
+ public boolean containsValue(final Object value) {
+ return map.containsValue(value);
+ }
+
+ public V get(final Object key) {
+ return map.get(key);
+ }
+
+ public V put(final K key, final V value) {
+ if (key == null) {
+ throw new NullPointerException("key is null");
+ }
+ if (value == null) {
+ throw new NullPointerException("value is null");
+ }
+ synchronized (writeLock) {
+ final Map<K, V> map = this.map;
+ final V old = map.get(key);
+ if (map.size() == 0) {
+ this.map = singletonMap(key, value);
+ } else {
+ final HashMap<K, V> copy = new HashMap<K, V>(map);
+ map.put(key, value);
+ this.map = copy;
+ }
+ return old;
+ }
+ }
+
+ public V remove(final Object key) {
+ if (key == null) return null;
+ synchronized (writeLock) {
+ final Map<K, V> map = this.map;
+ final V old = map.get(key);
+ if (old != null) {
+ if (map.size() == 1) {
+ this.map = emptyMap();
+ } else {
+ final HashMap<K, V> copy = new HashMap<K, V>(map);
+ map.remove(key);
+ this.map = copy;
+ }
+ }
+ return old;
+ }
+ }
+
+ public void putAll(final Map<? extends K, ? extends V> m) {
+ }
+
+ public void clear() {
+ synchronized (writeLock) {
+ map = emptyMap();
+ }
+ }
+
+ public Set<K> keySet() {
+ return unmodifiableSet(map.keySet());
+ }
+
+ public Collection<V> values() {
+ return unmodifiableCollection(map.values());
+ }
+
+ public Set<Entry<K, V>> entrySet() {
+ return unmodifiableMap(map).entrySet();
+ }
+}
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/DuplicateRegistrationException.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/DuplicateRegistrationException.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/DuplicateRegistrationException.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -0,0 +1,69 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3;
+
+/**
+ * An exception which is thrown when a provider is registered under a name which is already registered.
+ */
+public class DuplicateRegistrationException extends IllegalArgumentException {
+
+ private static final long serialVersionUID = -1973333658984209308L;
+
+ /**
+ * Constructs a {@code DuplicateRegistrationException} with no detail message. The cause is not initialized, and may
+ * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}.
+ */
+ public DuplicateRegistrationException() {
+ }
+
+ /**
+ * Constructs a {@code DuplicateRegistrationException} with the specified detail message. The cause is not initialized,
+ * and may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}.
+ *
+ * @param msg the detail message
+ */
+ public DuplicateRegistrationException(final String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a {@code DuplicateRegistrationException} with the specified cause. The detail message is set to:
+ * <pre>(cause == null ? null : cause.toString())</pre>
+ * (which typically contains the class and detail message of {@code cause}).
+ *
+ * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method)
+ */
+ public DuplicateRegistrationException(final Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a {@code DuplicateRegistrationException} with the specified detail message and cause.
+ *
+ * @param msg the detail message
+ * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method)
+ */
+ public DuplicateRegistrationException(final String msg, final Throwable cause) {
+ super(msg, cause);
+ }
+}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -6,8 +6,14 @@
import org.jboss.remoting3.spi.ConnectionProviderFactory;
import org.jboss.remoting3.spi.RequestHandler;
import org.jboss.remoting3.spi.ConnectionProviderRegistration;
+import org.jboss.remoting3.spi.MarshallingProtocol;
import org.jboss.xnio.IoFuture;
import org.jboss.xnio.OptionMap;
+import org.jboss.marshalling.ClassTable;
+import org.jboss.marshalling.ObjectTable;
+import org.jboss.marshalling.ClassExternalizerFactory;
+import org.jboss.marshalling.ClassResolver;
+import org.jboss.marshalling.ObjectResolver;
/**
* A potential participant in a JBoss Remoting communications relationship.
@@ -53,6 +59,8 @@
/**
* Add a service registration listener which is called whenever a local service is registered.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addServiceListener EndpointPermission} to invoke this method.
*
* @param listener the listener
* @param flags the flags to apply to the listener
@@ -78,6 +86,8 @@
/**
* Open a connection with a peer. Returns a future connection which may be used to cancel the connection attempt.
* This method does not block; use the return value to wait for a result if you wish to block.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission connect EndpointPermission} to invoke this method.
*
* @param destination the destination
* @param connectOptions options to configure this connection
@@ -89,14 +99,89 @@
/**
* Register a connection provider for a URI scheme. The provider factory is called with the context which can
* be used to accept new connections or terminate the registration.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addConnectionProvider EndpointPermission} to invoke this method.
*
* @param uriScheme the URI scheme
* @param providerFactory the provider factory
* @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already a provider registered to that URI scheme
*/
- <T> ConnectionProviderRegistration<T> addConnectionProvider(String uriScheme, ConnectionProviderFactory<T> providerFactory);
+ <T> ConnectionProviderRegistration<T> addConnectionProvider(String uriScheme, ConnectionProviderFactory<T> providerFactory) throws DuplicateRegistrationException;
/**
+ * Register a named marshalling protocol.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addMarshallingProtocol EndpointPermission} to invoke this method.
+ *
+ * @param name the protocol name
+ * @param marshallingProtocol the implementation
+ * @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already a protocol registered to that name
+ */
+ Registration addMarshallingProtocol(String name, MarshallingProtocol marshallingProtocol) throws DuplicateRegistrationException;
+
+ /**
+ * Register a named class table for marshalling.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addMarshallingProtocol EndpointPermission} to invoke this method.
+ *
+ * @param name the protocol name
+ * @param classTable the class table
+ * @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already a class table registered to that name
+ */
+ Registration addUserClassTable(String name, ClassTable classTable) throws DuplicateRegistrationException;
+
+ /**
+ * Register a named object table for marshalling.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addMarshallingProtocol EndpointPermission} to invoke this method.
+ *
+ * @param name the protocol name
+ * @param objectTable the object table
+ * @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already an object table registered to that name
+ */
+ Registration addUserObjectTable(String name, ObjectTable objectTable) throws DuplicateRegistrationException;
+
+ /**
+ * Register a named class externalizer factory for marshalling.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addMarshallingProtocol EndpointPermission} to invoke this method.
+ *
+ * @param name the protocol name
+ * @param classExternalizerFactory the class externalizer factory
+ * @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already a class externalizer factory registered to that name
+ */
+ Registration addUserExternalizerFactory(String name, ClassExternalizerFactory classExternalizerFactory) throws DuplicateRegistrationException;
+
+ /**
+ * Register a named class resolver for marshalling.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addMarshallingProtocol EndpointPermission} to invoke this method.
+ *
+ * @param name the protocol name
+ * @param classResolver the class resolver
+ * @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already a class resolver registered to that name
+ */
+ Registration addUserClassResolver(String name, ClassResolver classResolver) throws DuplicateRegistrationException;
+
+ /**
+ * Register a named object resolver for marshalling.
+ * <p/>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission addMarshallingProtocol EndpointPermission} to invoke this method.
+ *
+ * @param name the protocol name
+ * @param objectResolver the class resolver
+ * @return a handle which may be used to remove the registration
+ * @throws DuplicateRegistrationException if there is already an object resolver registered to that name
+ */
+ Registration addUserObjectResolver(String name, ObjectResolver objectResolver) throws DuplicateRegistrationException;
+
+ /**
* Flags which can be passed in to listener registration methods.
*/
enum ListenerFlag {
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -33,15 +33,14 @@
import java.util.Map;
import java.util.Queue;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.jboss.remoting3.spi.AbstractHandleableCloseable;
import org.jboss.remoting3.spi.AbstractSimpleCloseable;
-import org.jboss.remoting3.spi.Cancellable;
import org.jboss.remoting3.spi.ConnectionHandler;
import org.jboss.remoting3.spi.ConnectionHandlerFactory;
import org.jboss.remoting3.spi.ConnectionProvider;
@@ -51,25 +50,36 @@
import org.jboss.remoting3.spi.RequestHandlerConnector;
import org.jboss.remoting3.spi.Result;
import org.jboss.remoting3.spi.ConnectionProviderRegistration;
-import org.jboss.remoting3.spi.AbstractConnectionProviderRegistration;
+import org.jboss.remoting3.spi.MarshallingProtocol;
+import org.jboss.remoting3.spi.ConnectionContext;
+import org.jboss.xnio.Cancellable;
import org.jboss.xnio.IoFuture;
import org.jboss.xnio.IoUtils;
import org.jboss.xnio.WeakCloseable;
import org.jboss.xnio.OptionMap;
+import org.jboss.xnio.FinishedIoFuture;
+import org.jboss.xnio.FailedIoFuture;
import org.jboss.xnio.log.Logger;
+import org.jboss.marshalling.ClassTable;
+import org.jboss.marshalling.ObjectTable;
+import org.jboss.marshalling.ClassExternalizerFactory;
+import org.jboss.marshalling.ClassResolver;
+import org.jboss.marshalling.ObjectResolver;
/**
*
*/
final class EndpointImpl extends AbstractHandleableCloseable<Endpoint> implements Endpoint {
+ private static final NullCancellable NULL_CANCELLABLE = new NullCancellable();
+
static {
// Print Remoting "greeting" message
Logger.getLogger("org.jboss.remoting").info("JBoss Remoting version %s", Version.VERSION);
}
- static <K, V> ConcurrentMap<K, V> concurrentHashMap() {
- return new ConcurrentHashMap<K, V>();
+ static <K, V> ConcurrentMap<K, V> concurrentMap() {
+ return new CopyOnWriteHashMap<K, V>();
}
static <K, V> Map<K, V> hashMap() {
@@ -98,10 +108,16 @@
*/
private final Lock serviceRegistrationLock = new ReentrantLock();
- private final Set<Registration<ServiceRegistrationListener>> serviceListenerRegistrations = hashSet();
+ private final Set<ListenerRegistration<ServiceRegistrationListener>> serviceListenerRegistrations = hashSet();
private final Map<String, ServiceRegistration> registeredLocalServices = hashMap();
- private final ConcurrentMap<String, ConnectionProvider<?>> connectionProviders = concurrentHashMap();
+ private final ConcurrentMap<String, ConnectionProvider<?>> connectionProviders = concurrentMap();
+ private final ConcurrentMap<String, MarshallingProtocol> marshallingProtocols = concurrentMap();
+ private final ConcurrentMap<String, ClassTable> classTables = concurrentMap();
+ private final ConcurrentMap<String, ObjectTable> objectTables = concurrentMap();
+ private final ConcurrentMap<String, ClassExternalizerFactory> classExternalizerFactories = concurrentMap();
+ private final ConcurrentMap<String, ClassResolver> classResolvers = concurrentMap();
+ private final ConcurrentMap<String, ObjectResolver> objectResolvers = concurrentMap();
private static final EndpointPermission CREATE_ENDPOINT_PERM = new EndpointPermission("createEndpoint");
private static final EndpointPermission CREATE_REQUEST_HANDLER_PERM = new EndpointPermission("createRequestHandler");
@@ -110,6 +126,7 @@
private static final EndpointPermission ADD_SERVICE_LISTENER_PERM = new EndpointPermission("addServiceListener");
private static final EndpointPermission CONNECT_PERM = new EndpointPermission("connect");
private static final EndpointPermission ADD_CONNECTION_PROVIDER_PERM = new EndpointPermission("addConnectionProvider");
+ private static final EndpointPermission ADD_MARSHALLING_PROTOCOL_PERM = new EndpointPermission("addMarshallingProtocol");
public EndpointImpl(final Executor executor, final String name) {
super(executor);
@@ -119,6 +136,7 @@
}
this.executor = executor;
this.name = name;
+ connectionProviders.put("local", new LocalConnectionProvider());
}
private final Executor executor;
@@ -204,10 +222,10 @@
} catch (IOException e) {
result.setException(e);
}
- return Cancellable.NULL_CANCELLABLE;
+ return NULL_CANCELLABLE;
}
};
- final ServiceRegistration registration = new ServiceRegistration(serviceType, groupName, name, requestHandlerConnector);
+ final ServiceRegistration registration = new ServiceRegistration(serviceType, groupName, name, optionMap, requestHandlerConnector);
// this handle is used to remove the service registration
final AbstractSimpleCloseable newHandle = new AbstractSimpleCloseable(executor) {
protected void closeAction() throws IOException {
@@ -221,16 +239,16 @@
}
};
registration.setHandle(newHandle);
- final List<Registration<ServiceRegistrationListener>> serviceListenerRegistrations;
+ final List<ListenerRegistration<ServiceRegistrationListener>> serviceListenerRegistrations;
final Lock lock = serviceRegistrationLock;
// actually register the service, and while we have the lock, snag a copy of the registration listener list
lock.lock();
try {
if (registeredLocalServices.containsKey(serviceKey)) {
- throw new ServiceRegistrationException("Registration of service of type \"" + serviceType + "\" in group \"" + groupName + "\" duplicates an already-registered service's specification");
+ throw new ServiceRegistrationException("ListenerRegistration of service of type \"" + serviceType + "\" in group \"" + groupName + "\" duplicates an already-registered service's specification");
}
registeredLocalServices.put(serviceKey, registration);
- serviceListenerRegistrations = new ArrayList<Registration<ServiceRegistrationListener>>(this.serviceListenerRegistrations);
+ serviceListenerRegistrations = new ArrayList<ListenerRegistration<ServiceRegistrationListener>>(this.serviceListenerRegistrations);
} finally {
lock.unlock();
}
@@ -256,7 +274,7 @@
serviceInfo.setRequestHandlerConnector(requestHandlerConnector);
executor.execute(new Runnable() {
public void run() {
- for (final Registration<ServiceRegistrationListener> slr : serviceListenerRegistrations) {
+ for (final ListenerRegistration<ServiceRegistrationListener> slr : serviceListenerRegistrations) {
final ServiceRegistrationListener registrationListener = slr.getResource();
try {
registrationListener.serviceRegistered(slr, serviceInfo.clone());
@@ -311,7 +329,7 @@
if (sm != null) {
sm.checkPermission(ADD_SERVICE_LISTENER_PERM);
}
- final Registration<ServiceRegistrationListener> registration = new Registration<ServiceRegistrationListener>(listener);
+ final ListenerRegistration<ServiceRegistrationListener> registration = new ListenerRegistration<ServiceRegistrationListener>(listener);
final Lock lock = serviceRegistrationLock;
final Collection<ServiceRegistration> services;
lock.lock();
@@ -330,7 +348,7 @@
serviceInfo.setGroupName(service.getGroupName());
serviceInfo.setOptionMap(service.getOptionMap());
serviceInfo.setRegistrationHandle(service.getHandle());
- serviceInfo.setRequestHandlerConnector(service.getConnector());
+ serviceInfo.setRequestHandlerConnector(service.getRequestHandlerConnector());
serviceInfo.setServiceType(service.getServiceType());
listener.serviceRegistered(registration, serviceInfo);
if (! registration.isOpen()) {
@@ -364,20 +382,20 @@
if (sm != null) {
sm.checkPermission(ADD_CONNECTION_PROVIDER_PERM);
}
- final ConnectionProviderContextImpl context = new ConnectionProviderContextImpl(executor, loopbackConnectionHandler);
+ final ConnectionProviderContextImpl context = new ConnectionProviderContextImpl();
final ConnectionProvider<T> provider = providerFactory.createInstance(context);
if (connectionProviders.putIfAbsent(uriScheme, provider) != null) {
IoUtils.safeClose(context);
- throw new IllegalArgumentException("URI scheme '" + uriScheme + "' is already registered to a provider");
+ throw new DuplicateRegistrationException("URI scheme '" + uriScheme + "' is already registered to a provider");
}
context.addCloseHandler(new CloseHandler<ConnectionProviderContext>() {
public void handleClose(final ConnectionProviderContext closed) {
connectionProviders.remove(uriScheme, provider);
}
});
- final AbstractConnectionProviderRegistration<T> handle = new AbstractConnectionProviderRegistration<T>(executor) {
- protected void closeAction() throws IOException {
- context.close();
+ final ConnectionProviderRegistration<T> handle = new ConnectionProviderRegistration<T>() {
+ public void close() {
+ IoUtils.safeClose(context);
}
public T getProviderInterface() {
@@ -392,6 +410,44 @@
return handle;
}
+ private <T> Registration addMarshallingRegistration(final String name, final T target, final ConcurrentMap<String, T> map, final String descr) throws DuplicateRegistrationException {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(ADD_MARSHALLING_PROTOCOL_PERM);
+ }
+ if ("default".equals(name)) {
+ throw new IllegalArgumentException("'default' is not an allowed name");
+ }
+ if (map.putIfAbsent(name, target) != null) {
+ throw new DuplicateRegistrationException(descr + " '" + name + "' is already registered");
+ }
+ return new MapRegistration<T>(map, name, target);
+ }
+
+ public Registration addMarshallingProtocol(final String name, final MarshallingProtocol marshallingProtocol) throws DuplicateRegistrationException {
+ return addMarshallingRegistration(name, marshallingProtocol, marshallingProtocols, "Marshalling protocol");
+ }
+
+ public Registration addUserClassTable(final String name, final ClassTable classTable) throws DuplicateRegistrationException {
+ return addMarshallingRegistration(name, classTable, classTables, "Class table");
+ }
+
+ public Registration addUserObjectTable(final String name, final ObjectTable objectTable) throws DuplicateRegistrationException {
+ return addMarshallingRegistration(name, objectTable, objectTables, "Object table");
+ }
+
+ public Registration addUserExternalizerFactory(final String name, final ClassExternalizerFactory classExternalizerFactory) throws DuplicateRegistrationException {
+ return addMarshallingRegistration(name, classExternalizerFactory, classExternalizerFactories, "Class externalizer factory");
+ }
+
+ public Registration addUserClassResolver(final String name, final ClassResolver classResolver) throws DuplicateRegistrationException {
+ return addMarshallingRegistration(name, classResolver, classResolvers, "Class resolver");
+ }
+
+ public Registration addUserObjectResolver(final String name, final ObjectResolver objectResolver) throws DuplicateRegistrationException {
+ return addMarshallingRegistration(name, objectResolver, objectResolvers, "Object resolver");
+ }
+
public String toString() {
return "endpoint \"" + name + "\" <" + Integer.toHexString(hashCode()) + ">";
}
@@ -406,12 +462,64 @@
return futureResult;
}
+ private static class MapRegistration<T> implements Registration {
+ private static final class Info<T> {
+ private final ConcurrentMap<String, T> map;
+ private final String key;
+ private final T value;
+
+ private Info(final ConcurrentMap<String, T> map, final String key, final T value) {
+ this.map = map;
+ this.key = key;
+ this.value = value;
+ }
+ }
+ private final AtomicReference<Info<T>> infoRef = new AtomicReference<Info<T>>();
+
+ private MapRegistration(final ConcurrentMap<String, T> map, final String key, final T value) {
+ infoRef.set(new Info<T>(map, key, value));
+ }
+
+ public void close() {
+ final Info<T> info = infoRef.getAndSet(null);
+ if (info != null) {
+ info.map.remove(info.key, info.value);
+ }
+ }
+ }
+
+ private final class LocalConnectionContext implements ConnectionContext {
+
+ public void openService(final String serviceType, final String groupName, final OptionMap optionMap, final ServiceResult serviceResult) {
+ final ServiceRegistration registration = registeredLocalServices.get(serviceType + ":" + groupName);
+ if (registration != null) {
+ registration.getRequestHandlerConnector().createRequestHandler(new Result<RequestHandler>() {
+ public void setResult(final RequestHandler result) {
+ serviceResult.opened(result, registration.getOptionMap());
+ }
+
+ public void setException(final IOException exception) {
+ log.warn(exception, "Unexpected exception on service lookup");
+ serviceResult.notFound();
+ }
+
+ public void setCancelled() {
+ log.warn("Unexpected cancellation on service lookup");
+ serviceResult.notFound();
+ }
+ });
+ } else {
+ serviceResult.notFound();
+ }
+ }
+ }
+
private class ConnectionImpl extends AbstractHandleableCloseable<Connection> implements Connection {
private final ConnectionHandler connectionHandler;
private ConnectionImpl(final ConnectionHandlerFactory connectionHandlerFactory) {
super(EndpointImpl.this.executor);
- connectionHandler = connectionHandlerFactory.createInstance(loopbackConnectionHandler);
+ connectionHandler = connectionHandlerFactory.createInstance(localConnectionContext);
}
public <I, O> IoFuture<? extends Client<I, O>> openClient(final String serviceType, final String groupName, final Class<I> requestClass, final Class<O> replyClass) {
@@ -431,24 +539,21 @@
}
}
- private static final class ConnectionProviderContextImpl extends AbstractHandleableCloseable<ConnectionProviderContext> implements ConnectionProviderContext {
+ private final class ConnectionProviderContextImpl extends AbstractHandleableCloseable<ConnectionProviderContext> implements ConnectionProviderContext {
- private final ConnectionHandler localConnectionHandler;
-
- private ConnectionProviderContextImpl(final Executor executor, final ConnectionHandler localConnectionHandler) {
+ private ConnectionProviderContextImpl() {
super(executor);
- this.localConnectionHandler = localConnectionHandler;
}
public void accept(final ConnectionHandlerFactory connectionHandlerFactory) {
- connectionHandlerFactory.createInstance(localConnectionHandler);
+ connectionHandlerFactory.createInstance(localConnectionContext);
}
}
- private final class Registration<T> extends AbstractSimpleCloseable {
+ private final class ListenerRegistration<T> extends AbstractSimpleCloseable {
private final T resource;
- private Registration(final T resource) {
+ private ListenerRegistration(final T resource) {
super(executor);
this.resource = resource;
}
@@ -472,16 +577,114 @@
}
}
- private final ConnectionHandler loopbackConnectionHandler = new ConnectionHandler() {
+ private final ConnectionContext localConnectionContext = new LocalConnectionContext();
+ private final ConnectionHandler loopbackConnectionHandler = new LoopbackConnectionHandler();
+ private final Connection loopbackConnection = new LoopbackConnection();
+
+ // todo - move this into XNIO IoUtils
+ private static class NullCancellable implements Cancellable {
+ public Cancellable cancel() {
+ return this;
+ }
+ }
+
+ final class LocalConnectionProvider implements ConnectionProvider<Void> {
+
+ public Cancellable connect(final URI uri, final OptionMap connectOptions, final Result<ConnectionHandlerFactory> result) throws IllegalArgumentException {
+ result.setResult(new ConnectionHandlerFactory() {
+ public ConnectionHandler createInstance(final ConnectionContext context) {
+ return loopbackConnectionHandler;
+ }
+
+ });
+ return NULL_CANCELLABLE;
+ }
+
+ public Void getProviderInterface() {
+ return null;
+ }
+ }
+
+ private class LoopbackConnection implements Connection {
+
+ public <I, O> IoFuture<? extends Client<I, O>> openClient(final String serviceType, final String groupName, final Class<I> requestClass, final Class<O> replyClass) {
+ final IoFuture.Manager<Client<I, O>> mgr = new IoFuture.Manager<Client<I, O>>();
+ mgr.addCancelHandler(loopbackConnectionHandler.open(serviceType, groupName, new Result<RequestHandler>() {
+ public void setResult(final RequestHandler result) {
+ mgr.setResult(ClientImpl.create(result, executor, requestClass, replyClass));
+ }
+
+ public void setException(final IOException exception) {
+ mgr.setException(exception);
+ }
+
+ public void setCancelled() {
+ mgr.finishCancel();
+ }
+ }));
+ return mgr.getIoFuture();
+ }
+
+ public <I, O> ClientConnector<I, O> createClientConnector(final RequestListener<I, O> listener, final Class<I> requestClass, final Class<O> replyClass) {
+ final Client<I, O> client;
+ final ClientContextImpl context = new ClientContextImpl(executor, LoopbackConnection.this);
+ try {
+ client = createClient(createLocalRequestHandler(listener, requestClass, replyClass), requestClass, replyClass);
+ context.addCloseHandler(new CloseHandler<ClientContext>() {
+ public void handleClose(final ClientContext closed) {
+ IoUtils.safeClose(client);
+ }
+ });
+ return new LoopbackClientConnector<I, O>(new FinishedIoFuture<Client<I, O>>(client), context);
+ } catch (IOException e) {
+ return new LoopbackClientConnector<I, O>(new FailedIoFuture<Client<I, O>>(e), context);
+ }
+ }
+
+ public void close() {
+ // ignored
+ }
+
+ public Key addCloseHandler(final CloseHandler<? super Connection> closeHandler) {
+ return EndpointImpl.this.addCloseHandler(new CloseHandler<Endpoint>() {
+ public void handleClose(final Endpoint closed) {
+ closeHandler.handleClose(LoopbackConnection.this);
+ }
+ });
+ }
+ }
+
+ private static class LoopbackClientConnector<I, O> implements ClientConnector<I, O> {
+
+ private final IoFuture<Client<I, O>> ioFuture;
+ private final ClientContextImpl context;
+
+ public LoopbackClientConnector(final IoFuture<Client<I, O>> ioFuture, final ClientContextImpl context) {
+ this.ioFuture = ioFuture;
+ this.context = context;
+ }
+
+ public IoFuture<? extends Client<I, O>> getFutureClient() throws SecurityException {
+ return ioFuture;
+ }
+
+ public ClientContext getClientContext() throws SecurityException {
+ return context;
+ }
+ }
+
+ private class LoopbackConnectionHandler implements ConnectionHandler {
+
public Cancellable open(final String serviceName, final String groupName, final Result<RequestHandler> result) {
// the loopback connection opens a local service
// local services are registered as RequestHandlerConnectors
final ServiceRegistration registration = registeredLocalServices.get(serviceName + ":" + groupName);
if (registration != null) {
- return registration.getConnector().createRequestHandler(result);
+ registration.getRequestHandlerConnector().createRequestHandler(result);
+ } else {
+ result.setException(new ServiceNotFoundException(ServiceURI.create(serviceName, groupName, name), "No such service located"));
}
- result.setException(new ServiceNotFoundException(ServiceURI.create(serviceName, groupName, name), "No such service located"));
- return Cancellable.NULL_CANCELLABLE;
+ return NULL_CANCELLABLE;
}
public RequestHandlerConnector createConnector(final RequestHandler localHandler) {
@@ -489,7 +692,7 @@
return new RequestHandlerConnector() {
public Cancellable createRequestHandler(final Result<RequestHandler> result) throws SecurityException {
result.setResult(localHandler);
- return Cancellable.NULL_CANCELLABLE;
+ return NULL_CANCELLABLE;
}
};
}
@@ -497,22 +700,5 @@
public void close() {
// not closeable
}
- };
-
- private final Connection loopbackConnection = new Connection() {
- public <I, O> IoFuture<? extends Client<I, O>> openClient(final String serviceType, final String groupName, final Class<I> requestClass, final Class<O> replyClass) {
- return null;
- }
-
- public <I, O> ClientConnector<I, O> createClientConnector(final RequestListener<I, O> listener, final Class<I> requestClass, final Class<O> replyClass) {
- return null;
- }
-
- public void close() throws IOException {
- }
-
- public Key addCloseHandler(final CloseHandler<? super Connection> closeHandler) {
- return null;
- }
- };
+ }
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/LocalRequestHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/LocalRequestHandler.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/LocalRequestHandler.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -78,8 +78,9 @@
return SpiUtils.getBlankRemoteRequestContext();
}
return new RemoteRequestContext() {
- public void cancel() {
+ public RemoteRequestContext cancel() {
context.cancel();
+ return this;
}
};
}
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Registration.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Registration.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Registration.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3;
+
+import java.io.Closeable;
+
+/**
+ * A simple registration handle. Registration handles are closeable but the close will not throw an exception.
+ */
+public interface Registration extends Closeable {
+
+ /**
+ * Close the registration.
+ */
+ void close();
+}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -32,9 +32,11 @@
import java.util.ServiceLoader;
import org.jboss.remoting3.spi.RequestHandler;
import org.jboss.remoting3.spi.ConnectionProviderDescriptor;
+import org.jboss.remoting3.spi.MarshallingProtocolDescriptor;
import org.jboss.xnio.CloseableExecutor;
import org.jboss.xnio.IoUtils;
import org.jboss.xnio.OptionMap;
+import org.jboss.xnio.Option;
import org.jboss.xnio.log.Logger;
/**
@@ -99,9 +101,16 @@
}
});
if (optionMap.get(Options.LOAD_PROVIDERS, true)) {
- for (ConnectionProviderDescriptor descriptor : ServiceLoader.load(ConnectionProviderDescriptor.class)) {
+ for (ConnectionProviderDescriptor descriptor : ServiceLoader.load(ConnectionProviderDescriptor.class)) try {
endpoint.addConnectionProvider(descriptor.getUriScheme(), descriptor.getConnectionProviderFactory());
+ } catch (DuplicateRegistrationException e) {
+ log.debug("Duplicate registration for URI scheme '" + descriptor.getUriScheme() + "'");
}
+ for (MarshallingProtocolDescriptor descriptor : ServiceLoader.load(MarshallingProtocolDescriptor.class)) try {
+ endpoint.addMarshallingProtocol(descriptor.getName(), descriptor.getMarshallingProtocol());
+ } catch (DuplicateRegistrationException e) {
+ log.debug("Duplicate registration for marshalling protocol '" + descriptor.getName() + "'");
+ }
// todo - marshallers and components thereof
}
return endpoint;
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistration.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistration.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistration.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -23,6 +23,7 @@
package org.jboss.remoting3;
import org.jboss.remoting3.spi.RequestHandlerConnector;
+import org.jboss.remoting3.spi.RequestHandler;
import org.jboss.xnio.OptionMap;
/**
@@ -34,25 +35,25 @@
private final String groupName;
private final String endpointName;
private final OptionMap optionMap;
- private final RequestHandlerConnector connector;
+ private final RequestHandlerConnector requestHandlerConnector;
private volatile SimpleCloseable handle;
- ServiceRegistration(final String serviceType, final String groupName, final String endpointName, final OptionMap optionMap, final RequestHandlerConnector connector) {
+ ServiceRegistration(final String serviceType, final String groupName, final String endpointName, final OptionMap optionMap, final RequestHandlerConnector requestHandlerConnector) {
+ this.requestHandlerConnector = requestHandlerConnector;
remote = true;
this.serviceType = serviceType;
this.groupName = groupName;
this.endpointName = endpointName;
this.optionMap = optionMap;
- this.connector = connector;
}
- ServiceRegistration(final String serviceType, final String groupName, final String endpointName, final RequestHandlerConnector connector) {
+ ServiceRegistration(final String serviceType, final String groupName, final String endpointName, final RequestHandlerConnector requestHandlerConnector) {
+ this.requestHandlerConnector = requestHandlerConnector;
remote = false;
optionMap = OptionMap.EMPTY;
this.serviceType = serviceType;
this.groupName = groupName;
this.endpointName = endpointName;
- this.connector = connector;
}
public boolean matches(final String serviceType, final String groupName, final String endpointName) {
@@ -81,8 +82,8 @@
return optionMap;
}
- public RequestHandlerConnector getConnector() {
- return connector;
+ public RequestHandlerConnector getRequestHandlerConnector() {
+ return requestHandlerConnector;
}
public SimpleCloseable getHandle() {
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistrationListener.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistrationListener.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ServiceRegistrationListener.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -23,6 +23,7 @@
package org.jboss.remoting3;
import org.jboss.remoting3.spi.RequestHandlerConnector;
+import org.jboss.remoting3.spi.RequestHandler;
import org.jboss.xnio.OptionMap;
/**
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -30,6 +30,7 @@
* @param <I> the request type
* @param <O> the reply type for this request type
*/
+@SuppressWarnings({ "UnusedDeclaration" })
public interface TypedRequest<I, O> {
/**
Deleted: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractConnectionProviderRegistration.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractConnectionProviderRegistration.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractConnectionProviderRegistration.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -1,42 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2009, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.remoting3.spi;
-
-import java.util.concurrent.Executor;
-
-/**
- * An abstract implementation of {@code ConnectionProviderRegistration}.
- *
- * @param <T> the provider interface type
- */
-public abstract class AbstractConnectionProviderRegistration<T> extends AbstractHandleableCloseable<ConnectionProviderRegistration<T>> implements ConnectionProviderRegistration<T> {
-
- /**
- * Basic constructor.
- *
- * @param executor the executor used to execute the close notification handlers
- */
- protected AbstractConnectionProviderRegistration(final Executor executor) {
- super(executor);
- }
-}
Deleted: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Cancellable.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Cancellable.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Cancellable.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -1,43 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2009, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.remoting3.spi;
-
-/**
- * A handle which can be used to cancel an operation. Cancellation is not mandatory; calling this method merely indicates
- * that the operation need not complete.
- */
-public interface Cancellable {
-
- /**
- * Cancel the operation. Calling this method more than one time has no additional effect.
- */
- void cancel();
-
- /**
- * A Cancellable instance which does nothing.
- */
- Cancellable NULL_CANCELLABLE = new Cancellable() {
- public void cancel() {
- }
- };
-}
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionContext.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionContext.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionContext.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3.spi;
+
+import org.jboss.xnio.OptionMap;
+
+/**
+ * The context for connections to service incoming requests to open a client service.
+ */
+public interface ConnectionContext {
+
+ /**
+ * Open a service.
+ *
+ * @param serviceType the service type
+ * @param groupName the service group name
+ * @param optionMap the open options
+ * @param serviceResult the result of the service open
+ */
+ void openService(String serviceType, String groupName, OptionMap optionMap, ServiceResult serviceResult);
+
+ /**
+ * The result acceptor for a service open request.
+ */
+ interface ServiceResult {
+
+ /**
+ * Called if the service was opened.
+ *
+ * @param requestHandler the opened request handler
+ * @param optionMap the service's option map
+ */
+ void opened(RequestHandler requestHandler, OptionMap optionMap);
+
+ /**
+ * Called if no matching service was found.
+ */
+ void notFound();
+ }
+}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandler.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandler.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -23,6 +23,7 @@
package org.jboss.remoting3.spi;
import java.io.Closeable;
+import org.jboss.xnio.Cancellable;
/**
* A connection to a foreign endpoint. This interface is implemented by the protocol implementation.
@@ -32,17 +33,18 @@
/**
* Open a request handler.
*
- * @param serviceName the service name
+ * @param serviceType the service type
* @param groupName the group name
* @param result the result for the connected request handler
* @return a handle which may be used to cancel the pending operation
*/
- Cancellable open(String serviceName, String groupName, Result<RequestHandler> result);
+ Cancellable open(String serviceType, String groupName, Result<RequestHandler> result);
/**
* Create a connector which may be used to communicate with the given local RequestHandler. The connector
* should only produce a result once it has passed to the remote side of this connection.
*
+ * @param localHandler the local handler
* @return the connector
*/
RequestHandlerConnector createConnector(RequestHandler localHandler);
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandlerFactory.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandlerFactory.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionHandlerFactory.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -31,11 +31,10 @@
public interface ConnectionHandlerFactory {
/**
- * Create a connection handler instance. The provided connection handler is the handler for the next hop of
- * the local connection; typically this will be the endpoint loopback connection but it may not be.
+ * Create a connection handler instance. The provided connection context is used to open local services.
*
- * @param localConnectionHandler the local connection handler for incoming requests
+ * @param connectionContext the local connection handler for incoming requests
* @return the connection handler for outgoing requests
*/
- ConnectionHandler createInstance(ConnectionHandler localConnectionHandler);
+ ConnectionHandler createInstance(ConnectionContext connectionContext);
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProvider.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProvider.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProvider.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -23,6 +23,7 @@
package org.jboss.remoting3.spi;
import java.net.URI;
+import org.jboss.xnio.Cancellable;
import org.jboss.xnio.OptionMap;
/**
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderRegistration.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderRegistration.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderRegistration.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -22,14 +22,14 @@
package org.jboss.remoting3.spi;
-import org.jboss.remoting3.HandleableCloseable;
+import org.jboss.remoting3.Registration;
/**
* A handle representing the registration of a connection provider.
*
* @param <T> the provider interface type
*/
-public interface ConnectionProviderRegistration<T> extends HandleableCloseable<ConnectionProviderRegistration<T>> {
+public interface ConnectionProviderRegistration<T> extends Registration {
/**
* Get the created provider interface associated with this registration.
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocol.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocol.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocol.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -0,0 +1,99 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3.spi;
+
+import org.jboss.marshalling.Marshaller;
+import org.jboss.marshalling.Unmarshaller;
+import org.jboss.marshalling.ClassTable;
+import org.jboss.marshalling.ObjectTable;
+import org.jboss.marshalling.ClassExternalizerFactory;
+import org.jboss.marshalling.ClassResolver;
+import org.jboss.marshalling.ObjectResolver;
+import org.jboss.xnio.Pool;
+
+/**
+ * A registered marshalling protocol.
+ *
+ * @remoting.implement
+ */
+public interface MarshallingProtocol {
+
+ /**
+ * Get a configured unmarshaller pool.
+ *
+ * @param configuration the configuration to use
+ * @return the pool
+ */
+ Pool<Unmarshaller> getUnmarshallerPool(Configuration configuration);
+
+ /**
+ * Get a configured marshaller pool.
+ *
+ * @param configuration the configuration to use
+ * @return the pool
+ */
+ Pool<Marshaller> getMarshallerPool(Configuration configuration);
+
+ /**
+ * The configuration for a marshalling protocol.
+ *
+ * @remoting.consume
+ */
+ interface Configuration {
+
+ /**
+ * Get a user class table, if any.
+ *
+ * @return the user class table or {@code null} if none is configured
+ */
+ ClassTable getUserClassTable();
+
+ /**
+ * Get a user object table, if any.
+ *
+ * @return the user object table or {@code null} if none is configured
+ */
+ ObjectTable getUserObjectTable();
+
+ /**
+ * Get a user externalizer factory, if any.
+ *
+ * @return the user externalizer factory
+ */
+ ClassExternalizerFactory getUserExternalizerFactory();
+
+ /**
+ * Get a user class resolver, if any.
+ *
+ * @return the user class resolver
+ */
+ ClassResolver getUserClassResolver();
+
+ /**
+ * Get a user object resolver, if any.
+ *
+ * @return the user object resolver
+ */
+ ObjectResolver getUserObjectResolver();
+ }
+}
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocolDescriptor.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocolDescriptor.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/MarshallingProtocolDescriptor.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3.spi;
+
+/**
+ * A descriptor for automatically-discovered marshaller types. Since instances of this interface are
+ * constructed automatically, implementing classes should have a no-arg constructor.
+ * <p>
+ * To add an automatically-discovered marshaller, create a file called {@code "META-INF/services/org.jboss.remoting3.spi.MarshallingProtocolDescriptor"}
+ * and populate it with the names of classes that implement this interface.
+ *
+ * @see java.util.ServiceLoader
+ */
+public interface MarshallingProtocolDescriptor {
+
+ /**
+ * Get the name of this marshalling protocol.
+ *
+ * @return the name
+ */
+ String getName();
+
+ /**
+ * Get the marshalling protocol to associate with the given name.
+ *
+ * @return the marshalling protocol
+ */
+ MarshallingProtocol getMarshallingProtocol();
+}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RemoteRequestContext.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RemoteRequestContext.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RemoteRequestContext.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -22,6 +22,8 @@
package org.jboss.remoting3.spi;
+import org.jboss.xnio.Cancellable;
+
/**
* The context of an outstanding remote request. This instance should be discarded when a reply (of any sort)
* is received for the request.
@@ -31,5 +33,5 @@
/**
* Signal that the request should be cancelled, if possible.
*/
- void cancel();
+ RemoteRequestContext cancel();
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RequestHandlerConnector.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RequestHandlerConnector.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/RequestHandlerConnector.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -22,6 +22,8 @@
package org.jboss.remoting3.spi;
+import org.jboss.xnio.Cancellable;
+
/**
* A holder for a request handler that is to be sent to a remote peer.
*/
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Result.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Result.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/Result.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -24,10 +24,30 @@
import java.io.IOException;
+/**
+ * A handler for accepting the result of an operation. Used by protocol implementations to tell Remoting
+ * the result of an operation.
+ *
+ * @param <T> the type of the result
+ */
public interface Result<T> {
+
+ /**
+ * Indicate a successful result, and hand in the result value.
+ *
+ * @param result the result value
+ */
void setResult(T result);
+ /**
+ * Indicate a failure, and hand in the exception.
+ *
+ * @param exception the exception
+ */
void setException(IOException exception);
+ /**
+ * Indicate a cancellation of the operation.
+ */
void setCancelled();
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/SpiUtils.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/SpiUtils.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/SpiUtils.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -116,111 +116,6 @@
}
/**
- * Get a {@code Cancellable} for an {@code IoFuture}.
- *
- * @param future the future
- * @return the cancellable
- */
- public static Cancellable cancellable(final IoFuture<?> future) {
- return new Cancellable() {
- public void cancel() {
- future.cancel();
- }
- };
- }
-
- /**
- * Create a connection handler factory for a public class which implements {@code ConnectionHandler} and has a
- * public constructor which accepts a {@code ConnectionHandler} as its sole parameter.
- *
- * @param handlerClass the class of the handler
- * @param <T> the type of the handler
- * @return the handler factory
- * @throws IllegalArgumentException if the class does not meet the requirements
- */
- public static <T extends ConnectionHandler> ConnectionHandlerFactory connectionHandlerFactory(final Class<T> handlerClass) throws IllegalArgumentException {
- return AccessController.doPrivileged(new PrivilegedAction<ConnectionHandlerFactory>() {
- public ConnectionHandlerFactory run() {
- final Constructor<T> constructor = getPutOneArgConstructor(ConnectionHandler.class, handlerClass);
- checkForCheckedExceptions(constructor);
- return new ConnectionHandlerFactory() {
- public ConnectionHandler createInstance(final ConnectionHandler localConnectionHandler) {
- return AccessController.doPrivileged(new PrivilegedAction<ConnectionHandler>() {
- public ConnectionHandler run() {
- try {
- return constructor.newInstance(localConnectionHandler);
- } catch (InstantiationException e) {
- throw new IllegalStateException("Unexpected exception", e);
- } catch (IllegalAccessException e) {
- throw new IllegalStateException("Unexpected exception", e);
- } catch (InvocationTargetException e) {
- throw new IllegalStateException("Unexpected exception", e.getCause());
- }
- }
- });
- }
- };
- }
- });
- }
-
- private static <T> Constructor<T> getPutOneArgConstructor(final Class<?> argType, final Class<T> targetClass) {
- final Constructor<T> constructor;
- try {
- constructor = targetClass.getConstructor(argType);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("No valid constructor is present");
- }
- if ((targetClass.getModifiers() & constructor.getModifiers() & Modifier.PUBLIC) == 0) {
- throw new IllegalArgumentException("Class or constructor is not public");
- }
- return constructor;
- }
-
- /**
- * Create a connection provider factory for a public class which implements {@code ConnectionProvider} and has a
- * public constructor which accepts a {@code ConnectionProviderContext} as its sole parameter.
- *
- * @param providerClass the class of the provider
- * @param <T> the type of the provider
- * @return the provider factory
- * @throws IllegalArgumentException if the class does not meet the requirements
- */
- public static <T extends ConnectionProvider> ConnectionProviderFactory connectionProviderFactory(final Class<T> providerClass) throws IllegalArgumentException {
- return AccessController.doPrivileged(new PrivilegedAction<ConnectionProviderFactory>() {
- public ConnectionProviderFactory run() {
- final Constructor<T> constructor = getPutOneArgConstructor(ConnectionProviderContext.class, providerClass);
- checkForCheckedExceptions(constructor);
- return new ConnectionProviderFactory() {
- public ConnectionProvider createInstance(final ConnectionProviderContext context) {
- return AccessController.doPrivileged(new PrivilegedAction<ConnectionProvider>() {
- public ConnectionProvider run() {
- try {
- return constructor.newInstance(context);
- } catch (InstantiationException e) {
- throw new IllegalStateException("Unexpected exception", e);
- } catch (IllegalAccessException e) {
- throw new IllegalStateException("Unexpected exception", e);
- } catch (InvocationTargetException e) {
- throw new IllegalStateException("Unexpected exception", e.getCause());
- }
- }
- });
- }
- };
- }
- });
- }
-
- private static void checkForCheckedExceptions(final Constructor<?> constructor) {
- for (Class<?> exceptionType : constructor.getExceptionTypes()) {
- if (! Error.class.isAssignableFrom(exceptionType) && ! RuntimeException.class.isAssignableFrom(exceptionType)) {
- throw new IllegalArgumentException("Constructor may not throw checked exceptions");
- }
- }
- }
-
- /**
* Get a remote request context that simply ignores a cancel request.
*
* @return a blank remote request context
@@ -232,7 +127,8 @@
private static final RemoteRequestContext BLANK_REMOTE_REQUEST_CONTEXT = new BlankRemoteRequestContext();
private static final class BlankRemoteRequestContext implements RemoteRequestContext {
- public void cancel() {
+ public RemoteRequestContext cancel() {
+ return this;
}
}
}
Modified: remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/protocol/basic/BasicRequestHandler.java
===================================================================
--- remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/protocol/basic/BasicRequestHandler.java 2009-10-23 04:01:17 UTC (rev 5565)
+++ remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/protocol/basic/BasicRequestHandler.java 2009-10-23 19:10:31 UTC (rev 5566)
@@ -67,7 +67,7 @@
final int id = requestSequence.getAndIncrement();
replyQueue.add(replyHandler);
return new RemoteRequestContext() {
- public void cancel() {
+ public RemoteRequestContext cancel() {
reqLock.lock();
try {
marshaller.write(3);
@@ -79,6 +79,7 @@
} finally {
reqLock.unlock();
}
+ return this;
}
};
} catch (IOException e) {
15 years, 2 months
JBoss Remoting SVN: r5565 - in remoting3/trunk: jboss-remoting and 1 other directory.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-23 00:01:17 -0400 (Fri, 23 Oct 2009)
New Revision: 5565
Modified:
remoting3/trunk/jboss-remoting/pom.xml
remoting3/trunk/pom.xml
Log:
POM fixes, update to 2.0.0.CR3 release of XNIO
Modified: remoting3/trunk/jboss-remoting/pom.xml
===================================================================
--- remoting3/trunk/jboss-remoting/pom.xml 2009-10-22 22:15:13 UTC (rev 5564)
+++ remoting3/trunk/jboss-remoting/pom.xml 2009-10-23 04:01:17 UTC (rev 5565)
@@ -26,6 +26,9 @@
<modelVersion>4.0.0</modelVersion>
+ <name>JBoss Remoting</name>
+ <description>JBoss Remoting</description>
+
<groupId>org.jboss.remoting</groupId>
<artifactId>jboss-remoting</artifactId>
<packaging>jar</packaging>
@@ -34,7 +37,7 @@
<dependency>
<groupId>org.jboss.xnio</groupId>
<artifactId>xnio-api</artifactId>
- <version>2.0.0.CR3-SNAPSHOT</version>
+ <version>2.0.0.CR3</version>
<scope>compile</scope>
</dependency>
<dependency>
Modified: remoting3/trunk/pom.xml
===================================================================
--- remoting3/trunk/pom.xml 2009-10-22 22:15:13 UTC (rev 5564)
+++ remoting3/trunk/pom.xml 2009-10-23 04:01:17 UTC (rev 5565)
@@ -26,6 +26,9 @@
<modelVersion>4.0.0</modelVersion>
+ <name>JBoss Remoting Parent</name>
+ <description>JBoss Remoting Parent POM</description>
+
<groupId>org.jboss.remoting</groupId>
<artifactId>jboss-remoting-all</artifactId>
<packaging>pom</packaging>
15 years, 2 months
JBoss Remoting SVN: r5564 - in remoting3/trunk/samples/src: test/java/org/jboss/remoting3/samples/protocol/basic and 1 other directory.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-22 18:15:13 -0400 (Thu, 22 Oct 2009)
New Revision: 5564
Modified:
remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/simple/MultiplexServerExample.java
remoting3/trunk/samples/src/test/java/org/jboss/remoting3/samples/protocol/basic/BasicTestCase.java
Log:
XNIO options class moved
Modified: remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/simple/MultiplexServerExample.java
===================================================================
--- remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/simple/MultiplexServerExample.java 2009-10-22 17:16:09 UTC (rev 5563)
+++ remoting3/trunk/samples/src/main/java/org/jboss/remoting3/samples/simple/MultiplexServerExample.java 2009-10-22 22:15:13 UTC (rev 5564)
@@ -33,6 +33,7 @@
import org.jboss.xnio.CloseableExecutor;
import org.jboss.xnio.Xnio;
import org.jboss.xnio.TcpServer;
+import org.jboss.xnio.OptionMap;
import org.jboss.xnio.channels.Channels;
import java.io.IOException;
@@ -66,10 +67,10 @@
final SimpleCloseable handle = endpoint.registerService(config);
try {
// now create the server...
- final MultiplexConnectionProviderFactory multiplexConnectionProviderFactory = new MultiplexConnectionProviderFactory(xnio.createTcpConnector().create());
+ final MultiplexConnectionProviderFactory multiplexConnectionProviderFactory = new MultiplexConnectionProviderFactory(xnio.createTcpConnector(OptionMap.EMPTY));
final ConnectionProviderRegistration<MultiplexServerFactory> cpHandle = endpoint.addConnectionProvider("multiplex", multiplexConnectionProviderFactory);
try {
- final TcpServer tcpServer = xnio.createTcpServer(Channels.convertStreamToAllocatedMessage(cpHandle.getProviderInterface().getHandlerFactory(), 0x1000, 0x1000)).create();
+ final TcpServer tcpServer = xnio.createTcpServer(Channels.createAllocatedMessageChannel(cpHandle.getProviderInterface().getServerListener(), OptionMap.EMPTY)).create();
try {
// now just wait for 15 seconds, and then shut it all down
Thread.sleep(15000L);
Modified: remoting3/trunk/samples/src/test/java/org/jboss/remoting3/samples/protocol/basic/BasicTestCase.java
===================================================================
--- remoting3/trunk/samples/src/test/java/org/jboss/remoting3/samples/protocol/basic/BasicTestCase.java 2009-10-22 17:16:09 UTC (rev 5563)
+++ remoting3/trunk/samples/src/test/java/org/jboss/remoting3/samples/protocol/basic/BasicTestCase.java 2009-10-22 22:15:13 UTC (rev 5564)
@@ -25,7 +25,6 @@
import junit.framework.TestCase;
import org.jboss.xnio.Xnio;
import org.jboss.xnio.IoUtils;
-import org.jboss.xnio.IoHandler;
import org.jboss.xnio.ChannelSource;
import org.jboss.xnio.IoFuture;
import org.jboss.xnio.nio.NioXnio;
15 years, 2 months
JBoss Remoting SVN: r5563 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-22 13:16:09 -0400 (Thu, 22 Oct 2009)
New Revision: 5563
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java
Log:
Doc clarification
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java 2009-10-22 16:52:02 UTC (rev 5562)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java 2009-10-22 17:16:09 UTC (rev 5563)
@@ -25,6 +25,11 @@
/**
* A descriptor for automatically-discovered connection provider types. Since instances of this interface are
* constructed automatically, implementing classes should have a no-arg constructor.
+ * <p>
+ * To add an automatically-discovered provider, create a file called {@code "META-INF/services/org.jboss.remoting3.spi.ConnectionProviderDescriptor"}
+ * and populate it with the names of classes that implement this interface.
+ *
+ * @see java.util.ServiceLoader
*/
public interface ConnectionProviderDescriptor {
15 years, 2 months
JBoss Remoting SVN: r5562 - in remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3: spi and 1 other directory.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-22 12:52:02 -0400 (Thu, 22 Oct 2009)
New Revision: 5562
Added:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemoteExecutionException.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java
Log:
Remoting API cleanup; start of service provider automation for connection providers.
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java 2009-10-17 00:14:13 UTC (rev 5561)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Endpoint.java 2009-10-22 16:52:02 UTC (rev 5562)
@@ -36,7 +36,7 @@
* @param requestListener the request listener
* @param requestClass the class of requests sent to this request listener
* @param replyClass the class of replies received back from this request listener
- * @return a handle for the client
+ * @return the request handler
* @throws IOException if an error occurs
*/
<I, O> RequestHandler createLocalRequestHandler(RequestListener<I, O> requestListener, final Class<I> requestClass, final Class<O> replyClass) throws IOException;
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java 2009-10-17 00:14:13 UTC (rev 5561)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Options.java 2009-10-22 16:52:02 UTC (rev 5562)
@@ -34,6 +34,16 @@
}
/**
+ * Configure the maximum number of threads for a simple endpoint.
+ */
+ public static final Option<Integer> MAX_THREADS = Option.simple(Options.class, "MAX_THREADS", Integer.class);
+
+ /**
+ * Specify whether connection providers should automatically be detected and loaded.
+ */
+ public static final Option<Boolean> LOAD_PROVIDERS = Option.simple(Options.class, "LOAD_PROVIDERS", Boolean.class);
+
+ /**
* Request that the marshalling layer require the use of one of the listed marshalling protocols, in order of decreasing preference. If
* not specified, use a default value. The marshaller {@code "default"} can be specified explicitly for this default value.
*/
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemoteExecutionException.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemoteExecutionException.java 2009-10-17 00:14:13 UTC (rev 5561)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemoteExecutionException.java 2009-10-22 16:52:02 UTC (rev 5562)
@@ -76,15 +76,51 @@
}
/**
- * Rethrow the cause, if it is a runtime exception. This is a convenience method to extract a runtime exception
- * from a remote execution exception.
+ * Convenience method to rethrow the cause of a {@code RemoteExecutionException} as a specific type, in order
+ * to simplify application exception handling.
+ * <p/>
+ * A typical usage might look like this:
+ * <pre>
+ * try {
+ * client.invoke(request);
+ * } catch (RemoteExecutionException ree) {
+ * ree.rethrow(IOException.class);
+ * ree.rethrow(RuntimeException.class);
+ * throw ree.unexpected();
+ * }
+ * </pre>
+ * <p/>
+ * Note that if the nested exception is an {@link InterruptedException}, the type that will actually be thrown
+ * will be {@link RemoteInterruptedException}.
*
- * @throws RuntimeException the cause
+ * @param type the class of the exception
+ * @param <T> the exception type
+ * @throws T the exception, if it matches the given type
*/
- public final void throwRuntime() throws RuntimeException {
+ public <T extends Throwable> void rethrow(Class<T> type) throws T {
final Throwable cause = getCause();
- if (cause instanceof RuntimeException) {
- throw ((RuntimeException)cause);
+ if (cause == null) {
+ return;
}
+ if (type.isAssignableFrom(cause.getClass()) || type == RemoteInterruptedException.class) {
+ if (cause instanceof InterruptedException) {
+ final RemoteInterruptedException rie = new RemoteInterruptedException(cause.getMessage(), cause.getCause());
+ rie.setStackTrace(cause.getStackTrace());
+ throw rie;
+ }
+ throw type.cast(cause);
+ }
+ return;
}
+
+ /**
+ * Convenience method to get an unexpected exception type wrapped within a runtime exception.
+ */
+ public IllegalStateException unexpected() {
+ Throwable cause = getCause();
+ if (cause instanceof InterruptedException) {
+ cause = new RemoteInterruptedException(cause.getMessage(), cause.getCause());
+ }
+ throw new IllegalStateException("Unexpected remote exception occurred", cause);
+ }
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java 2009-10-17 00:14:13 UTC (rev 5561)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Remoting.java 2009-10-22 16:52:02 UTC (rev 5562)
@@ -29,9 +29,12 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.ServiceLoader;
import org.jboss.remoting3.spi.RequestHandler;
+import org.jboss.remoting3.spi.ConnectionProviderDescriptor;
import org.jboss.xnio.CloseableExecutor;
import org.jboss.xnio.IoUtils;
+import org.jboss.xnio.OptionMap;
import org.jboss.xnio.log.Logger;
/**
@@ -46,6 +49,8 @@
/**
* Create an endpoint. The endpoint will create its own thread pool with a maximum of 10 threads.
+ * <p>
+ * You must have the {@link org.jboss.remoting3.EndpointPermission createEndpoint EndpointPermission} to invoke this method.
*
* @param name the name of the endpoint
* @return the endpoint
@@ -56,7 +61,7 @@
/**
* Create an endpoint. The endpoint will create its own thread pool with a maximum of {@code maxThreads} threads.
- *
+ * <p>
* You must have the {@link org.jboss.remoting3.EndpointPermission createEndpoint EndpointPermission} to invoke this method.
*
* @param name the name of the endpoint
@@ -64,13 +69,41 @@
* @return the endpoint
*/
public static Endpoint createEndpoint(final String name, final int maxThreads) throws IOException {
- final CloseableExecutor executor = createExecutor(maxThreads);
+ return createEndpoint(name, OptionMap.builder().set(Options.MAX_THREADS, maxThreads).getMap());
+ }
+
+ /**
+ * Create an endpoint configured with the given option map. The following options are supported:
+ * <ul>
+ * <li>{@link Options#MAX_THREADS} - specify the maximum number of threads for the created thread pool (default 10)</li>
+ * <li>{@link Options#LOAD_PROVIDERS} - specify whether providers should be auto-loaded (default {@code true})</li>
+ * </ul>
+ *
+ * @param name the endpoint name
+ * @param optionMap the endpoint options
+ * @return the endpoint
+ * @throws IOException if an error occurs
+ */
+ public static Endpoint createEndpoint(final String name, final OptionMap optionMap) throws IOException {
+ if (name == null) {
+ throw new NullPointerException("name is null");
+ }
+ if (optionMap == null) {
+ throw new NullPointerException("optionMap is null");
+ }
+ final CloseableExecutor executor = createExecutor(optionMap.get(Options.MAX_THREADS, 10));
final Endpoint endpoint = createEndpoint(executor, name);
endpoint.addCloseHandler(new CloseHandler<Endpoint>() {
public void handleClose(final Endpoint closed) {
IoUtils.safeClose(executor);
}
});
+ if (optionMap.get(Options.LOAD_PROVIDERS, true)) {
+ for (ConnectionProviderDescriptor descriptor : ServiceLoader.load(ConnectionProviderDescriptor.class)) {
+ endpoint.addConnectionProvider(descriptor.getUriScheme(), descriptor.getConnectionProviderFactory());
+ }
+ // todo - marshallers and components thereof
+ }
return endpoint;
}
@@ -124,58 +157,18 @@
* @throws IOException if an error occurs
*/
public static <I, O> Client<I, O> createLocalClient(final Endpoint endpoint, final RequestListener<I, O> requestListener, final Class<I> requestClass, final Class<O> replyClass) throws IOException {
+ boolean ok = false;
final RequestHandler requestHandler = endpoint.createLocalRequestHandler(requestListener, requestClass, replyClass);
try {
- return endpoint.createClient(requestHandler, requestClass, replyClass);
+ final Client<I, O> client = endpoint.createClient(requestHandler, requestClass, replyClass);
+ ok = true;
+ return client;
} finally {
- IoUtils.safeClose(requestHandler);
- }
- }
-
- /**
- * Convenience method to rethrow the cause of a {@code RemoteExecutionException} as a specific type, in order
- * to simplify application exception handling.
- * <p/>
- * A typical usage might look like this:
- * <pre>
- * try {
- * client.invoke(request);
- * } catch (RemoteExecutionException ree) {
- * Remoting.rethrowAs(IOException.class, ree);
- * Remoting.rethrowAs(RuntimeException.class, ree);
- * Remoting.rethrowUnexpected(ree);
- * }
- * </pre>
- * <p/>
- * Note that if the nested exception is an {@link InterruptedException}, the type that will actually be thrown
- * will be {@link RemoteInterruptedException}.
- *
- * @param type the class of the exception
- * @param original the remote execution exception
- * @param <T> the exception type
- * @throws T the exception, if it matches the given type
- */
- public static <T extends Throwable> void rethrowAs(Class<T> type, RemoteExecutionException original) throws T {
- final Throwable cause = original.getCause();
- if (cause == null) {
- return;
- }
- if (type.isAssignableFrom(cause.getClass())) {
- if (cause instanceof InterruptedException) {
- throw new RemoteInterruptedException(cause.getMessage(), cause.getCause());
+ if (! ok) {
+ IoUtils.safeClose(requestHandler);
}
- throw type.cast(cause);
}
- return;
}
- public static void rethrowUnexpected(RemoteExecutionException original) throws IllegalStateException {
- Throwable cause = original.getCause();
- if (cause instanceof InterruptedException) {
- cause = new RemoteInterruptedException(cause.getMessage(), cause.getCause());
- }
- throw new IllegalStateException("Unexpected remote exception occurred", cause);
- }
-
private Remoting() { /* empty */ }
}
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderDescriptor.java 2009-10-22 16:52:02 UTC (rev 5562)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3.spi;
+
+/**
+ * A descriptor for automatically-discovered connection provider types. Since instances of this interface are
+ * constructed automatically, implementing classes should have a no-arg constructor.
+ */
+public interface ConnectionProviderDescriptor {
+
+ /**
+ * Get the URI scheme for this provider. A provider factory may be registered more than one time with different
+ * URI schemes.
+ *
+ * @return the URI scheme
+ */
+ String getUriScheme();
+
+ /**
+ * Get the connection provider factory to associate with the given URI scheme.
+ *
+ * @return the connection provider factory
+ */
+ ConnectionProviderFactory<?> getConnectionProviderFactory();
+}
15 years, 2 months
JBoss Remoting SVN: r5561 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-16 20:14:13 -0400 (Fri, 16 Oct 2009)
New Revision: 5561
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
Log:
Fix a problem where typed request invocations are ambiguous with respect to regular requests
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-17 00:13:42 UTC (rev 5560)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-17 00:14:13 UTC (rev 5561)
@@ -117,7 +117,7 @@
* @throws IOException if an I/O error occurred while sending the request
* @throws CancellationException if the operation was cancelled asynchronously
*/
- <T extends O> T invoke(TypedRequest<? extends I, T> request) throws IOException, CancellationException, ClassCastException;
+ <T extends O> T invokeTyped(TypedRequest<? extends I, T> request) throws IOException, CancellationException, ClassCastException;
/**
* Send a request asynchronously. If the remote side manipulates a stream, it
@@ -165,5 +165,5 @@
* @throws IOException if some other I/O error occurred while sending the request
* @see #send(Object) send(I)
*/
- <T extends O> IoFuture<? extends T> send(TypedRequest<? extends I, T> request) throws IOException;
+ <T extends O> IoFuture<? extends T> sendTyped(TypedRequest<? extends I, T> request) throws IOException;
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-17 00:13:42 UTC (rev 5560)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-17 00:14:13 UTC (rev 5561)
@@ -96,7 +96,7 @@
}
}
- public <T extends O> T invoke(final TypedRequest<? extends I, T> typedRequest) throws IOException, CancellationException {
+ public <T extends O> T invokeTyped(final TypedRequest<? extends I, T> typedRequest) throws IOException, CancellationException {
return invoke(requestClass.cast(typedRequest), typedRequest.getReplyClass());
}
@@ -117,7 +117,7 @@
return futureReply;
}
- public <T extends O> IoFuture<? extends T> send(final TypedRequest<? extends I, T> typedRequest) throws IOException {
+ public <T extends O> IoFuture<? extends T> sendTyped(final TypedRequest<? extends I, T> typedRequest) throws IOException {
return send(requestClass.cast(typedRequest), typedRequest.getReplyClass());
}
15 years, 2 months
JBoss Remoting SVN: r5560 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-16 20:13:42 -0400 (Fri, 16 Oct 2009)
New Revision: 5560
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
Log:
Allow typed request to be applied to just subclasses
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-16 22:48:44 UTC (rev 5559)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-17 00:13:42 UTC (rev 5560)
@@ -30,7 +30,7 @@
* @param <I> the request type
* @param <O> the reply type for this request type
*/
-public interface TypedRequest<I extends TypedRequest<I, O>, O> {
+public interface TypedRequest<I, O> {
/**
* Get the reply type class for this request type.
15 years, 2 months
JBoss Remoting SVN: r5559 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-16 18:48:44 -0400 (Fri, 16 Oct 2009)
New Revision: 5559
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
Log:
Use "class" when talking about class objects; reserve "type" for type parameters
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-16 22:24:34 UTC (rev 5558)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-16 22:48:44 UTC (rev 5559)
@@ -97,7 +97,7 @@
}
public <T extends O> T invoke(final TypedRequest<? extends I, T> typedRequest) throws IOException, CancellationException {
- return invoke(requestClass.cast(typedRequest), typedRequest.getReplyType());
+ return invoke(requestClass.cast(typedRequest), typedRequest.getReplyClass());
}
public IoFuture<? extends O> send(final I request) throws IOException {
@@ -118,7 +118,7 @@
}
public <T extends O> IoFuture<? extends T> send(final TypedRequest<? extends I, T> typedRequest) throws IOException {
- return send(requestClass.cast(typedRequest), typedRequest.getReplyType());
+ return send(requestClass.cast(typedRequest), typedRequest.getReplyClass());
}
/**
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-16 22:24:34 UTC (rev 5558)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-16 22:48:44 UTC (rev 5559)
@@ -33,9 +33,9 @@
public interface TypedRequest<I extends TypedRequest<I, O>, O> {
/**
- * Get the reply type for this request type.
+ * Get the reply type class for this request type.
*
* @return the reply type's class
*/
- Class<O> getReplyType();
+ Class<O> getReplyClass();
}
15 years, 2 months
JBoss Remoting SVN: r5558 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-16 18:24:34 -0400 (Fri, 16 Oct 2009)
New Revision: 5558
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
Log:
Javadoc fixes
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-16 20:52:24 UTC (rev 5557)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-16 22:24:34 UTC (rev 5558)
@@ -108,7 +108,7 @@
/**
* Send a typed request and block until a reply is received. If, for some reason, the given typed request object
- * is not a subtype of {@link #<I>}, a {@code ClassCastException} is thrown. Otherwise this method functions
+ * is not a subtype of {@code <I>}, a {@code ClassCastException} is thrown. Otherwise this method functions
* identically to {@link #invoke(Object) invoke(I)}.
*
* @param request the request
@@ -155,7 +155,7 @@
/**
* Send a typed request asynchronously. If, for some reason, the given typed request object
- * is not a subtype of {@link #<I>}, a {@code ClassCastException} is thrown. Otherwise
+ * is not a subtype of {@code <I>}, a {@code ClassCastException} is thrown. Otherwise
* this method functions identically to {@link #send(Object) send(I)}.
*
* @param request the request to send
15 years, 2 months
JBoss Remoting SVN: r5557 - remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3.
by jboss-remoting-commits@lists.jboss.org
Author: david.lloyd(a)jboss.com
Date: 2009-10-16 16:52:24 -0400 (Fri, 16 Oct 2009)
New Revision: 5557
Added:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java
Log:
Additional type-safe request API for clients
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-09 20:35:17 UTC (rev 5556)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-16 20:52:24 UTC (rev 5557)
@@ -94,6 +94,32 @@
O invoke(I request) throws IOException, CancellationException;
/**
+ * Send a reqest and block until a reply is received, requiring the reply to be of a specific type.
+ * Otherwise this method functions identically to {@link #invoke(Object) invoke(I)}.
+ *
+ * @param request the reqest to send
+ * @param expectedResultType the expected result type
+ * @return the result of the request
+ * @throws IOException if an I/O error occurred while sending the request
+ * @throws CancellationException if the operation was cancelled asynchronously
+ * @see #invoke(Object) invoke(I)
+ */
+ <T extends O> T invoke(I request, Class<T> expectedResultType) throws IOException, CancellationException;
+
+ /**
+ * Send a typed request and block until a reply is received. If, for some reason, the given typed request object
+ * is not a subtype of {@link #<I>}, a {@code ClassCastException} is thrown. Otherwise this method functions
+ * identically to {@link #invoke(Object) invoke(I)}.
+ *
+ * @param request the request
+ * @param <T> the specific reply subtype
+ * @return the result of the request
+ * @throws IOException if an I/O error occurred while sending the request
+ * @throws CancellationException if the operation was cancelled asynchronously
+ */
+ <T extends O> T invoke(TypedRequest<? extends I, T> request) throws IOException, CancellationException, ClassCastException;
+
+ /**
* Send a request asynchronously. If the remote side manipulates a stream, it
* may use a local policy to assign one or more thread(s) to handle the local end of that stream, or it may
* fail with an exception (e.g. if this method is called on a client with no threads to handle streaming).
@@ -112,4 +138,32 @@
* @throws IOException if some other I/O error occurred while sending the request
*/
IoFuture<? extends O> send(I request) throws IOException;
+
+ /**
+ * Send a request asynchronously, requiring the reply to be of a specific result type.
+ * Otherwise this method functions identically to {@link #send(Object) send(I)}.
+ *
+ * @param request the request to send
+ * @param expectedResultType the expected result type class
+ * @param <T> the expected result type
+ * @return a future representing the result of the request
+ * @throws ObjectStreamException if marshalling some part of the request failed
+ * @throws IOException if some other I/O error occurred while sending the request
+ * @see #send(Object) send(I)
+ */
+ <T extends O> IoFuture<? extends T> send(I request, Class<T> expectedResultType) throws IOException;
+
+ /**
+ * Send a typed request asynchronously. If, for some reason, the given typed request object
+ * is not a subtype of {@link #<I>}, a {@code ClassCastException} is thrown. Otherwise
+ * this method functions identically to {@link #send(Object) send(I)}.
+ *
+ * @param request the request to send
+ * @param <T> the expected result type
+ * @return a future representing the result of the request
+ * @throws ObjectStreamException if marshalling some part of the request failed
+ * @throws IOException if some other I/O error occurred while sending the request
+ * @see #send(Object) send(I)
+ */
+ <T extends O> IoFuture<? extends T> send(TypedRequest<? extends I, T> request) throws IOException;
}
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-09 20:35:17 UTC (rev 5556)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-16 20:52:24 UTC (rev 5557)
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.util.concurrent.Executor;
+import java.util.concurrent.CancellationException;
import org.jboss.remoting3.spi.RemoteRequestContext;
import org.jboss.remoting3.spi.ReplyHandler;
import org.jboss.remoting3.spi.RequestHandler;
@@ -65,45 +66,61 @@
}
public O invoke(final I request) throws IOException {
- if (! isOpen()) {
- throw new IOException("Client is not open");
- }
- log.trace("Client.invoke() sending request \"%s\"", request);
- final I actualRequest = castRequest(request);
- final QueueExecutor executor = new QueueExecutor();
- final FutureReplyImpl<O> futureReply = new FutureReplyImpl<O>(executor, replyClass);
- final ReplyHandler replyHandler = futureReply.getReplyHandler();
- final RemoteRequestContext requestContext = handler.receiveRequest(actualRequest, replyHandler);
- futureReply.setRemoteRequestContext(requestContext);
- futureReply.addNotifier(IoUtils.attachmentClosingNotifier(), executor);
- executor.runQueue();
- try {
- final O reply = futureReply.getInterruptibly();
- log.trace("Client.invoke() received reply \"%s\"", reply);
- return reply;
- } catch (InterruptedException e) {
- try {
- futureReply.cancel();
- throw new IndeterminateOutcomeException("The current thread was interrupted before the result could be read");
- } finally {
- Thread.currentThread().interrupt();
- }
- }
+ return invoke(request, replyClass);
}
+ public <T extends O> T invoke(final I request, final Class<T> replyClass) throws IOException, CancellationException {
+ if (! isOpen()) {
+ throw new IOException("Client is not open");
+ }
+ log.trace("Client.invoke() sending request \"%s\"", request);
+ final I actualRequest = castRequest(request);
+ final QueueExecutor executor = new QueueExecutor();
+ final FutureReplyImpl<T> futureReply = new FutureReplyImpl<T>(executor, replyClass);
+ final ReplyHandler replyHandler = futureReply.getReplyHandler();
+ final RemoteRequestContext requestContext = handler.receiveRequest(actualRequest, replyHandler);
+ futureReply.setRemoteRequestContext(requestContext);
+ futureReply.addNotifier(IoUtils.attachmentClosingNotifier(), executor);
+ executor.runQueue();
+ try {
+ final T reply = futureReply.getInterruptibly();
+ log.trace("Client.invoke() received reply \"%s\"", reply);
+ return reply;
+ } catch (InterruptedException e) {
+ try {
+ futureReply.cancel();
+ throw new IndeterminateOutcomeException("The current thread was interrupted before the result could be read");
+ } finally {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public <T extends O> T invoke(final TypedRequest<? extends I, T> typedRequest) throws IOException, CancellationException {
+ return invoke(requestClass.cast(typedRequest), typedRequest.getReplyType());
+ }
+
public IoFuture<? extends O> send(final I request) throws IOException {
+ return send(request, replyClass);
+ }
+
+ public <T extends O> IoFuture<? extends T> send(final I request, final Class<T> replyClass) throws IOException {
if (! isOpen()) {
throw new IOException("Client is not open");
}
log.trace("Client.send() sending request \"%s\"", request);
final I actualRequest = castRequest(request);
- final FutureReplyImpl<O> futureReply = new FutureReplyImpl<O>(getExecutor(), replyClass);
+ final FutureReplyImpl<T> futureReply = new FutureReplyImpl<T>(getExecutor(), replyClass);
final ReplyHandler replyHandler = futureReply.getReplyHandler();
final RemoteRequestContext requestContext = handler.receiveRequest(actualRequest, replyHandler);
futureReply.setRemoteRequestContext(requestContext);
return futureReply;
}
+ public <T extends O> IoFuture<? extends T> send(final TypedRequest<? extends I, T> typedRequest) throws IOException {
+ return send(requestClass.cast(typedRequest), typedRequest.getReplyType());
+ }
+
/**
* Since type is erased, it's possible that the wrong type was passed.
* @param request
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java 2009-10-09 20:35:17 UTC (rev 5556)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java 2009-10-16 20:52:24 UTC (rev 5557)
@@ -35,11 +35,11 @@
final class FutureReplyImpl<O> extends AbstractIoFuture<O> {
private final Executor executor;
- private final Class<O> replyType;
+ private final Class<? extends O> replyType;
private final ReplyHandler replyHandler = new Handler();
private volatile RemoteRequestContext remoteRequestContext;
- FutureReplyImpl(final Executor executor, final Class<O> replyType) {
+ FutureReplyImpl(final Executor executor, final Class<? extends O> replyType) {
this.executor = executor;
this.replyType = replyType;
}
@@ -65,7 +65,7 @@
private final class Handler implements ReplyHandler {
public void handleReply(final Object reply) {
- final Class<O> replyType = FutureReplyImpl.this.replyType;
+ final Class<? extends O> replyType = FutureReplyImpl.this.replyType;
final O actualReply;
try {
actualReply = replyType.cast(reply);
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-16 20:52:24 UTC (rev 5557)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3;
+
+/**
+ * A request whose replies should be of a specific type. Request classes may choose to implement this interface
+ * in order to provide additional type checking and convenience to Remoting API users by causing the reply type
+ * to be chosen based upon the request type.
+ *
+ * @param <I> the request type
+ * @param <O> the reply type for this request type
+ */
+public interface TypedRequest<I extends TypedRequest<I, O>, O> {
+
+ /**
+ * Get the reply type for this request type.
+ *
+ * @return the reply type's class
+ */
+ Class<O> getReplyType();
+}
15 years, 2 months