openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r406215 [7/10] - in /incubator/openjpa/trunk/openjpa-lib: ./ java/ java/org/ java/org/apache/ java/org/apache/openjpa/ java/org/apache/openjpa/lib/ java/org/apache/openjpa/lib/conf/ java/org/apache/openjpa/lib/jdbc/ java/org/apache/openjpa/...
Date Sun, 14 May 2006 03:26:02 GMT
Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RandomAccessResultList.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RandomAccessResultList.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RandomAccessResultList.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RandomAccessResultList.java Sat May 13 20:25:56 2006
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.io.*;
+import java.util.*;
+
+import serp.util.*;
+
+
+/**
+ *	<p>Random-access result list implementation. It maintains a map 
+ *	of the items that we have already instantiated.</p>
+ *
+ *	@author Marc Prud'hommeaux
+ *	@author Abe White
+ *	@nojavadoc
+ */
+public class RandomAccessResultList
+	extends AbstractNonSequentialResultList
+{
+	private static final int OPEN	= 0;
+	private static final int FREED	= 1;
+	private static final int CLOSED	= 2;
+
+	// data provider
+	private ResultObjectProvider _rop = null;
+
+	// holds all the row values that have been instantiated so far
+	private Map 		_rows 	= null;
+	private Object[]	_full	= null;
+
+	// bookkeeping
+	private long	_requests	= 0;
+	private int		_state		= OPEN;
+	private int		_size		= -1;
+
+
+	public RandomAccessResultList (ResultObjectProvider rop)
+	{
+		_rop = rop;
+		_rows = newRowMap ();
+
+		try
+		{
+			_rop.open ();
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+		}
+	}
+
+
+	/**
+	 *	Override this method to control what kind of map is used for
+	 *	the instantiated rows.
+	 */
+	protected Map newRowMap ()
+	{
+		return new HashMap ();	
+	}
+
+
+	public boolean isProviderOpen ()
+	{
+		return _state == OPEN;
+	}
+
+
+	public boolean isClosed ()
+	{
+		return _state == CLOSED;
+	}
+
+
+	public void close ()
+	{
+		if (_state != CLOSED)
+		{
+			free ();
+			_state = CLOSED;
+		}
+	}
+
+
+	protected Object getInternal (int index)
+	{
+		if (_full != null)
+		{
+			if (index >= _full.length)
+				return PAST_END;
+			return _full[index];
+		}
+
+		Integer i = Numbers.valueOf (index);
+		Object ret = _rows.get (i);
+		if (ret != null)
+		{
+			if (ret instanceof Null)
+				return null;
+			return ret;
+		}
+
+		ret = instantiateRow (i);
+		return (ret == null) ? PAST_END : ret;
+	}
+
+
+	/**
+	 *	Instantiate the row object at the specified index.
+	 */
+	private Object instantiateRow (Integer i)
+	{
+		_requests++;
+		try
+		{
+			if (!_rop.absolute (i.intValue ()))
+				return PAST_END;
+
+			Object ob = _rop.getResultObject ();
+			if (ob == null)
+				ob = new Null ();
+
+			// cache the result
+			_rows.put (i, ob);
+
+			// check to see if our map is full
+			checkComplete ();
+			return ob;
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return null;
+		}
+	}
+
+
+	/**
+	 *	Check to see if the soft map is the same size as all the
+	 *	rows in the Result: if so, we copy over the values to a
+	 *	hard reference HashSet and close the Result object associated with 
+	 *	this endeavour.
+	 */
+	private void checkComplete ()
+	{
+		// only check if we've actually gotten the size for some reason already
+		if (_size == -1 || _rows.size () != _size)
+			return;
+
+		Object[] full = new Object[_size];
+		int count = 0;
+		Integer key;
+		for (Iterator itr = _rows.keySet ().iterator (); itr.hasNext(); count++)
+		{
+			key = (Integer) itr.next ();
+			full[key.intValue ()] = _rows.get (key);
+		}
+
+		// double-check, in case any of the soft references were
+		// cleaned up between the time we checked the size and the
+		// time we completed the copy to the hard reference map
+		if (count == _size)
+		{
+			_full = full;
+			free ();
+		}
+	}
+
+
+	public int size ()
+	{
+		assertOpen ();
+		if (_size != -1)
+			return _size;
+		if (_full != null)
+			return _full.length;
+		try
+		{
+			_size = _rop.size ();
+			return _size;
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return -1;
+		}
+	}
+
+
+	private void free ()
+	{
+		if (_state == OPEN)
+		{
+			try { _rop.close (); } catch (Exception e) {}
+			_rows = null;
+			_state = FREED;
+		}
+	}
+
+
+	public Object writeReplace ()
+		throws ObjectStreamException
+	{
+		if (_full != null)
+			return new ListResultList (Arrays.asList (_full));
+		ArrayList list = new ArrayList ();
+		for (Iterator itr = iterator (); itr.hasNext ();)
+			list.add (itr.next ());
+		return list;
+	}
+
+
+	public String toString ()
+	{
+		return getClass ().getName () 
+			+ "; identity: " + System.identityHashCode (this)
+			+ "; cached: " + _rows.size ()
+			+ "; requests: " + _requests;
+	}
+
+
+	public int hashCode ()
+	{
+		// superclass tries to traverses entire list for hashcode 
+		return System.identityHashCode (this);
+	}
+
+
+	public boolean equals (Object other)
+	{
+		// superclass tries to traverse entire list for equality
+		return other == this;
+	}
+
+
+	/**
+	 *	Used to represent nulls in the result list.  Can't use a singleton
+	 *	pattern, because then there will always be a hard ref to all the
+	 *	nulls, and they'll never get GC'd; this is bad in the unlikely
+	 *	event of a huge result set with lots of nulls.
+	 */
+	private static class Null
+	{
+	}
+}
+

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RandomAccessResultList.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RangeResultObjectProvider.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RangeResultObjectProvider.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RangeResultObjectProvider.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RangeResultObjectProvider.java Sat May 13 20:25:56 2006
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.util.*;
+
+import org.apache.openjpa.lib.util.*;
+
+
+/**
+ *	<p>Prevents a view of a given range of indices from the delegate
+ *	result object provider.</p>
+ *
+ *	@author	Abe White
+ *	@nojavadoc
+ */
+public class RangeResultObjectProvider
+	implements ResultObjectProvider
+{
+	private static final Localizer _loc = Localizer.forPackage 
+		(RangeResultObjectProvider.class);
+
+	private final ResultObjectProvider 	_delegate;
+	private final int 					_startIdx;
+	private final int 					_endIdx;	
+	private int							_idx = -1;
+
+
+	/**
+	 *	Constructor. Because this is a wrapper around some delegate,
+	 *	and result object providers work with int indexes, neither the start
+	 *	or end index can be greater than Integer.MAX_VALUE (with the exception
+	 *	of Long.MAX_VALUE, which is used to indicate no limit).
+	 *
+	 *	@param	delegate	the result object provider to delegate to
+	 *	@param	startIdx	0-based inclusive start index of the range 
+	 *						to present; must be &lt; Integer.MAX_VALUE
+	 *	@param	endIdx		0-based exclusive end index of the range to 
+	 *						present; must be &lt; Integer.MAX_VALUE, or 
+	 *						Long.MAX_VALUE for no limit
+ 	 */
+	public RangeResultObjectProvider (ResultObjectProvider delegate,
+		long startIdx, long endIdx)
+	{
+		// use Integer.MAX_VALUE for no limit internally
+		if (endIdx == Long.MAX_VALUE)
+			endIdx = Integer.MAX_VALUE; 
+
+		_delegate = delegate;
+		if (startIdx > Integer.MAX_VALUE || endIdx > Integer.MAX_VALUE)
+			throw new IllegalArgumentException (_loc.get ("range-too-high",
+				String.valueOf (startIdx), String.valueOf (endIdx)));
+
+		_startIdx = (int) startIdx;
+		_endIdx = (int) endIdx;
+	}
+
+
+	public boolean supportsRandomAccess ()
+	{
+		return _delegate.supportsRandomAccess ();
+	}
+
+
+	public void open ()
+		throws Exception
+	{
+		_delegate.open ();
+	}
+
+
+	public Object getResultObject ()
+		throws Exception
+	{
+		if (_idx < _startIdx || _idx >= _endIdx)
+			throw new NoSuchElementException (String.valueOf (_idx));
+		return _delegate.getResultObject ();
+	}
+
+
+	public boolean next ()
+		throws Exception
+	{
+		// advance up to just behind _startIdx if we haven't already
+		while (_idx < _startIdx - 1)
+		{
+			if (_delegate.supportsRandomAccess ())
+			{
+				_idx = _startIdx - 1;
+				if (!_delegate.absolute (_startIdx - 1))
+					return false;
+			}
+			else
+			{
+				_idx++;
+				if (!_delegate.next ())
+					return false;
+			}
+		}
+			
+		// make sure we're not falling off the end of the range
+		if (_idx >= _endIdx - 1)
+			return false;
+
+		_idx++;
+		return _delegate.next ();
+	}
+
+
+	public boolean absolute (int pos)
+		throws Exception
+	{
+		_idx = pos + _startIdx;
+		if (_idx >= _endIdx)
+			return false;
+		return _delegate.absolute (_idx);
+	}
+
+
+	public int size ()
+		throws Exception
+	{
+		int size = _delegate.size ();
+		if (size == Integer.MAX_VALUE)
+			return size;
+		size = Math.min (_endIdx, size) - _startIdx; 
+		return (size < 0) ? 0 : size;
+	}
+
+
+	public void reset ()
+		throws Exception
+	{
+		_idx = -1;
+		_delegate.reset ();
+	}
+
+
+	public void close ()
+		throws Exception
+	{
+		_delegate.close ();
+	}
+
+
+	public void handleCheckedException (Exception e)
+	{
+		_delegate.handleCheckedException (e);
+	}
+}	
+

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/RangeResultObjectProvider.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultList.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultList.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultList.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultList.java Sat May 13 20:25:56 2006
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.io.*;
+import java.util.*;
+import java.util.NoSuchElementException;	// for javadoc; bug #4330419
+
+import org.apache.openjpa.lib.util.*;
+import org.apache.openjpa.lib.util.Closeable;
+
+
+/**
+ *	<p>List interface that represents a potentially lazy ResultList
+ *	instantiation.</p>
+ *
+ *	<p>A ResultList will typically be instantiated from a factory, and
+ *	will use a ResultObjectProvider for obtaining individual object
+ *	data representations.</p>
+ *
+ *	<p>Depending on the support for scrolling inputs, 
+ *	the list that is returned may use lazy instantiation of the
+ *	objects, and thus allow very large result sets to be obtained and
+ *	manipulated.</p>
+ *
+ *	<p>Note that wrapping a ResultList in another Collection will
+ *	always instantiate the entire set of elements contained in the
+ *	ResultList. This may not always be desireable, since the list may
+ *	be very large.</p>
+ *
+ *	@author Marc Prud'hommeaux
+ */
+public interface ResultList
+	extends List, Serializable, Closeable
+{
+	/**
+	 *	Returns true if the provider backing this list is open.
+	 */
+	public boolean isProviderOpen ();
+
+
+	/**
+	 *	Close the list.
+	 */
+	public void close ();
+
+
+	/**
+	 *	Returns true if the list has been closed.
+	 */
+	public boolean isClosed ();
+}
+

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultList.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultListIterator.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultListIterator.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultListIterator.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultListIterator.java Sat May 13 20:25:56 2006
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+import java.util.*;
+
+import org.apache.openjpa.lib.util.*;
+
+/**
+ *	Wrapper iterator that will return false for <code>hasNext()</code> if
+ *	the owning ResultList has been closed.
+ *
+ *	@author	Marc Prud'hommeaux
+ *	@nojavadoc
+ */
+public class ResultListIterator
+	extends AbstractListIterator
+{
+	private static final Localizer _loc = Localizer.forPackage (
+		ResultListIterator.class);
+
+	private final ListIterator	_li;
+	private final ResultList	_rl;
+
+
+	public ResultListIterator (ListIterator li, ResultList rl)
+	{
+		_li = li;
+		_rl = rl;
+	}
+
+
+	public ResultList getResultList ()
+	{
+		return _rl;
+	}
+
+
+	public boolean hasNext ()
+	{
+		if (_rl.isClosed ())
+			return false;
+		return _li.hasNext ();
+	}
+
+
+	public boolean hasPrevious ()
+	{
+		return _li.hasPrevious ();
+	}
+
+
+	public Object next ()
+	{
+		if (_rl.isClosed ())
+			throw new NoSuchElementException (_loc.get ("closed"));
+		return _li.next ();
+	}
+
+
+	public int nextIndex ()
+	{
+		return _li.nextIndex ();
+	}
+
+
+	public Object previous ()
+	{
+		return _li.previous ();
+	}
+
+
+	public int previousIndex ()
+	{
+		return _li.previousIndex ();
+	}
+}
+

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultListIterator.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProvider.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProvider.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProvider.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProvider.java Sat May 13 20:25:56 2006
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import org.apache.openjpa.lib.util.*;
+
+
+/**
+ *	<p>Interface that allows lazy/custom instantiation of input
+ *	objects.</p>
+ *
+ *	<p>{@link ResultList} objects do not necessarily load in data all
+ *	at once. Instead, they may lazily load objects as necessary. So,
+ *	the lifespan of a {@link ResultObjectProvider} instance is
+ *	related to how the application deals with processing the
+ *	{@link ResultList} created with a given
+ *	{@link ResultObjectProvider} instance.</p>
+ *
+ *	@author Marc Prud'hommeaux
+ *	@author Patrick Linskey
+ *	@author Abe White
+ */
+public interface ResultObjectProvider
+	extends Closeable
+{
+	/**
+	 *	Return true if this provider supports random access.
+	 */
+	public boolean supportsRandomAccess ();
+
+
+	/**
+	 *	Open the result.  This will be called before 
+	 *	{@link #next}, {@link #absolute}, or {@link #size}.
+	 */
+	public void open ()
+		throws Exception;
+
+
+	/**
+	 *	Instantiate the current result object.  This method will only be
+	 *	called after {@link #next} or {@link #absolute}.
+	 */
+	public Object getResultObject ()
+		throws Exception;
+
+
+	/**
+	 *	Advance the input to the next position. Return <code>true</code> if 
+	 *	there is more data; otherwise <code>false</code>.
+	 */
+	public boolean next ()
+		throws Exception;
+
+
+	/**
+	 *	Move to the given 0-based position.  This method is
+	 *	only called for providers that support random access.
+ 	 *	Return <code>true</code> if there is data at this position;
+	 *	otherwise <code>false</code>.  This may be invoked in place of
+	 *	{@link #next}.
+	 */
+	public boolean absolute (int pos)
+		throws Exception;
+
+
+	/**
+	 *	Return the number of items in the input, or {@link Integer#MAX_VALUE}
+	 *	if the size in unknown.
+	 */
+	public int size ()
+		throws Exception;
+
+
+	/**
+	 *	Reset this provider.  This is an optional operation.  If supported,
+	 *	it should move the position of the provider to before the first 
+	 *	element.  Non-random-access providers may be able to support this
+	 *	method by re-acquiring all resources as if the result were
+	 *	just opened.
+	 */
+	public void reset ()
+		throws Exception;
+	
+
+	/**
+	 *	Free the resources associated with this provider.
+	 */
+	public void close ()
+		throws Exception;
+
+
+	/**
+	 *	Any checked exceptions that are thrown will be passed to this method.
+	 *	The provider should re-throw the exception as an appropriate unchecked 
+	 *	exception.
+	 */
+	public void handleCheckedException (Exception e);
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProvider.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProviderIterator.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProviderIterator.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProviderIterator.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProviderIterator.java Sat May 13 20:25:56 2006
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.util.*;
+
+import org.apache.openjpa.lib.util.*;
+
+
+/**
+ *	<p>Iterator wrapped around a {@link ResultObjectProvider}.</p>
+ *
+ *	@author		Abe White
+ *	@nojavadoc
+ */
+public class ResultObjectProviderIterator
+	implements Iterator, Closeable
+{
+	private final ResultObjectProvider	_rop;
+	private Boolean						_hasNext 	= null; 
+	private Boolean						_open		= null;
+
+
+	/**
+	 *	Constructor.  Supply object provider.
+	 */
+	public ResultObjectProviderIterator (ResultObjectProvider rop)
+	{
+		_rop = rop;
+	}
+
+
+	/**
+	 *	Close the underlying result object provider.
+	 */
+	public void close ()
+	{
+		if (_open == Boolean.TRUE)
+		{
+			try { _rop.close (); } catch (Exception e) {}
+			_open = Boolean.FALSE;
+		}
+	}
+
+
+	public void remove ()
+	{
+		throw new UnsupportedOperationException ();
+	}
+
+
+	public boolean hasNext ()
+	{
+		if (_open == Boolean.FALSE)
+			return false;
+
+		if (_hasNext == null)
+		{
+			try
+			{
+				if (_open == null)
+				{
+					_rop.open ();
+					_open = Boolean.TRUE;
+				}
+				_hasNext = (_rop.next ()) ? Boolean.TRUE : Boolean.FALSE;
+			}
+			catch (RuntimeException re)
+			{
+				close ();
+				throw re;
+			}
+			catch (Exception e)
+			{
+				close ();
+				_rop.handleCheckedException (e);
+				return false;
+			}
+		}
+
+		// close if we reach the end of the list
+		if (!_hasNext.booleanValue ())
+		{
+			close ();
+			return false;
+		}
+		return true;
+	}
+
+
+	public Object next ()
+	{
+		if (!hasNext ())
+			throw new NoSuchElementException ();	
+		try
+		{
+			Object ret = _rop.getResultObject ();
+			_hasNext = null;
+			return ret;
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return null;
+		}	
+	}
+
+
+	protected void finalize ()
+	{
+		close ();
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/ResultObjectProviderIterator.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SimpleResultList.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SimpleResultList.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SimpleResultList.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SimpleResultList.java Sat May 13 20:25:56 2006
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.io.*;
+import java.util.*;
+
+
+/** 
+ *  <p>An almost stateless {@link ResultList} designed for use with result 
+ *	object providers backed by efficient random-access data structures, such
+ *	as the {@link ListResultObjectProvider}.  This result list does not
+ *	perform any caching.</p>
+ *  
+ *  @author Abe White
+ *	@nojavadoc
+ */
+public class SimpleResultList
+	extends AbstractNonSequentialResultList
+{
+	private final transient ResultObjectProvider	_rop;
+	private boolean 								_closed = false;
+	private int										_size	= -1;
+
+
+	public SimpleResultList (ResultObjectProvider rop)
+	{
+		_rop = rop;
+		try
+		{
+			_rop.open ();
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+		}
+	}
+
+
+	public boolean isProviderOpen ()
+	{
+		return !_closed;
+	}
+
+
+	public boolean isClosed ()
+	{
+		return _closed;
+	}
+
+
+	public void close ()
+	{
+		if (!_closed)
+		{
+			_closed = true;
+			try { _rop.close (); } catch (Exception e) {}		
+		}
+	}
+
+
+	public Object getInternal (int index)
+	{
+		try
+		{
+			if (!_rop.absolute (index))
+				return PAST_END;
+			return _rop.getResultObject ();
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return PAST_END;
+		}
+	}
+
+
+	public int size ()
+	{
+		assertOpen ();
+		if (_size != -1)
+			return _size;
+		try
+		{
+			_size = _rop.size ();
+			return _size;
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return -1;
+		}
+	}
+
+
+	public Object writeReplace ()
+		throws ObjectStreamException
+	{
+		if (_closed)
+			return this;
+
+		// load results into list
+		List list = new ArrayList ();
+		for (Iterator itr = iterator (); itr.hasNext ();) 
+			list.add (itr.next ());
+		return list;
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SimpleResultList.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SoftRandomAccessResultList.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SoftRandomAccessResultList.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SoftRandomAccessResultList.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SoftRandomAccessResultList.java Sat May 13 20:25:56 2006
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.util.*;
+
+import org.apache.commons.collections.*;
+
+
+/**
+ *	<p>Specialization of the {@link RandomAccessResultList} that only maintains
+ *	soft references to instantiated objects.</p>
+ *
+ *	@author Abe White
+ *	@nojavadoc
+ */
+public class SoftRandomAccessResultList
+	extends RandomAccessResultList
+{
+	public SoftRandomAccessResultList (ResultObjectProvider rop)
+	{
+		super (rop);
+	}
+
+
+	protected Map newRowMap ()
+	{
+		return new ReferenceMap ();
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/SoftRandomAccessResultList.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/WindowResultList.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/WindowResultList.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/WindowResultList.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/WindowResultList.java Sat May 13 20:25:56 2006
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.rop;
+
+
+import java.io.*;
+import java.util.*;
+
+
+/** 
+ *  <p>ResultList implementation that uses a forward-scrolling window of 
+ *	results.</p>  
+ *
+ *	@author		Abe White
+ *	@nojavadoc
+ */
+public class WindowResultList
+	extends AbstractNonSequentialResultList
+{
+	private static final int OPEN	= 0;
+	private static final int FREED	= 1;
+	private static final int CLOSED	= 2;
+
+	private final Object[]			_window;
+	private int						_pos	= -1;
+	private ResultObjectProvider	_rop 	= null;
+	private boolean 				_random	= false;
+	private int						_state	= OPEN;
+	private int						_size	= -1;
+
+
+	public WindowResultList (ResultObjectProvider rop)
+	{
+		this (rop, 10);
+	}
+
+
+	public WindowResultList (ResultObjectProvider rop, int windowSize)
+	{
+		_rop = rop;
+
+		if (windowSize <= 0)
+			windowSize = 10;
+		_window = new Object[windowSize];
+
+		try
+		{
+			_rop.open ();
+			_random = _rop.supportsRandomAccess ();
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+		}
+	}
+
+
+	public boolean isProviderOpen ()
+	{
+		return _state == OPEN;
+	}
+
+
+	public boolean isClosed ()
+	{
+		return _state == CLOSED;
+	}
+
+
+	public void close ()
+	{
+		if (_state != CLOSED)
+		{
+			free ();
+			_state = CLOSED;
+		}
+	}
+
+
+	public int size ()
+	{
+		assertOpen ();
+		if (_size != -1)
+			return _size;
+		try
+		{
+			_size = _rop.size ();
+			return _size;
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return -1;
+		}
+	}
+
+
+	public Object getInternal (int index)
+	{
+		// out of range?
+		if (index < 0 || (_size != -1 && index >= _size))
+			return PAST_END;
+
+		try
+		{
+			// if this is before window range, move window back
+			if (index < _pos)
+			{
+				if (!_random || index == 0)
+					_rop.reset ();
+				_pos = -1;
+			}
+	
+			// if this is the first get or past window range, move window
+			if (_pos == -1 || index >= _pos + _window.length)
+			{
+				// position result provider just before requested index
+				if (_random && index != 0)
+				{
+					if (!_rop.absolute (index - 1))
+						return PAST_END; 
+				}
+				else
+				{
+					int begin = (_pos == -1) ? 0 : _pos + _window.length;
+					for (int i = begin; i < index; i++)
+						if (!_rop.next ())
+							return PAST_END;
+				}
+
+				// create window starting at requested index
+				int end = -1;
+				for (int i = 0; i < _window.length; i++)
+				{
+					if (end == -1 && !_rop.next ())
+						end = i;
+					_window[i] = (end == -1) ? _rop.getResultObject () 
+						: PAST_END;
+				}
+				_pos = index;
+
+				// if the window spans the entire result list, free
+				if (end != -1 && _pos == 0)
+				{
+					_size = end;
+					free ();
+				}
+			}
+
+			// grab result from window
+			return _window[index - _pos];
+		}
+		catch (RuntimeException re)
+		{
+			close ();
+			throw re;
+		}
+		catch (Exception e)
+		{
+			close ();
+			_rop.handleCheckedException (e);
+			return null;
+		}
+	}
+
+
+	private void free ()
+	{
+		if (_state == OPEN)
+		{
+			try { _rop.close (); } catch (Exception e) {}
+			_state = FREED;
+		}
+	}
+
+
+	public Object writeReplace ()
+		throws ObjectStreamException
+	{
+		if (_state != OPEN)
+			return this;
+
+		// load results into list
+		List list = new ArrayList ();
+		for (Iterator itr = iterator (); itr.hasNext ();) 
+			list.add (itr.next ());
+		return list;
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/WindowResultList.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/package.html
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/package.html?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/package.html (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/package.html Sat May 13 20:25:56 2006
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+<html>
+<body>
+	<p><strong>Result Object Provider Framework</strong></p>
+	<p>
+		This package provides a framework for the lazy loading of potentially
+		large lists of data.
+	</p>
+</body>
+</html>

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/rop/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/AbstractEventManager.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/AbstractEventManager.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/AbstractEventManager.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/AbstractEventManager.java Sat May 13 20:25:56 2006
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+
+import java.util.*;
+
+
+/**
+ *	<p>Base event manager that handles adding/removing listeners
+ *	and firing events.  This class is reentrant-safe; listeners can be added
+ *	and removed by other listeners when they receive events.  The changes will
+ *	not be visible until the event fire that initiated the recursive sequence
+ *	of calls completes, however.</p>
+ *
+ *	@author		Abe White
+ */
+public abstract class AbstractEventManager
+{
+	private static Exception[] EMPTY_EXCEPTIONS = new Exception[0];
+
+	private boolean		_firing			= false;
+	private Collection 	_listeners 		= null;
+	private Collection	_newListeners	= null;
+
+
+	/**
+	 *	Register an event listener.
+	 */
+	public synchronized void addListener (Object listener)
+	{
+		if (listener == null)
+			return;
+		if (_firing)
+		{
+			if (_newListeners == null)
+				_newListeners = newListenerCollection ();
+			_newListeners.addAll (_listeners);
+			_newListeners.add (listener);
+		}
+		else
+		{
+			if (_listeners == null)
+				_listeners = newListenerCollection ();
+			_listeners.add (listener);
+		}
+	}
+
+
+	/**
+	 *	Remove an event listener.
+	 */
+	public synchronized boolean removeListener (Object listener)
+	{
+		if (listener == null)
+			return false;
+		if (_firing && _listeners.contains (listener))
+		{
+			if (_newListeners == null)
+				_newListeners = newListenerCollection ();
+			_newListeners.addAll (_listeners);
+			return _newListeners.remove (listener);
+		}
+		return _listeners != null && _listeners.remove (listener);
+	}
+
+
+	/**
+	 *	Return whether the given instance is in the list of listeners.
+	 */
+	public synchronized boolean hasListener (Object listener)
+	{
+		return _listeners != null && _listeners.contains (listener);
+	}
+
+
+	/**
+	 *	Return true if there are any registered listeners.
+	 */
+	public synchronized boolean hasListeners ()
+	{
+		return _listeners != null && !_listeners.isEmpty ();
+	}
+
+	
+	/**
+	 *	Return a read-only list of listeners.
+	 */
+	public synchronized Collection getListeners ()
+	{
+		return (_listeners == null) ? Collections.EMPTY_LIST
+			: Collections.unmodifiableCollection (_listeners);
+	}
+
+
+	/**
+	 *	Fire the given event to all listeners.
+	 */
+	public synchronized Exception[] fireEvent (Object event)
+	{
+		if (_listeners == null || _listeners.isEmpty ())
+			return EMPTY_EXCEPTIONS;
+
+		boolean reentrant = _firing;
+		_firing = true;
+		List exceptions = null;
+		for (Iterator itr = _listeners.iterator (); itr.hasNext ();)
+		{
+			try
+			{
+				fireEvent (event, itr.next ());
+			}
+			catch (Exception e)
+			{
+				if (exceptions == null)
+					exceptions = new LinkedList ();
+				exceptions.add (e);
+			}
+		}
+
+		// if this wasn't a reentrant call, record that we're no longer
+		// in the process of firing events and replace our initial listener
+		// list with the set of new listeners
+		if (!reentrant)
+		{
+			_firing = false;
+			if (_newListeners != null)
+				_listeners = _newListeners;
+			_newListeners = null;
+		}
+		
+		if (exceptions == null)
+			return EMPTY_EXCEPTIONS;
+		return (Exception[]) exceptions.toArray 
+			(new Exception[exceptions.size ()]);
+	}
+
+
+	/**
+	 *	Implement this method to fire the given event to the given listener.
+	 */
+	protected abstract void fireEvent (Object event, Object listener)
+		throws Exception;
+
+
+	/**
+	 *	Return a new container for listeners.  Uses a linked list by default.
+	 */
+	protected Collection newListenerCollection ()
+	{
+		return new LinkedList ();
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/AbstractEventManager.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Base16Encoder.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Base16Encoder.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Base16Encoder.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Base16Encoder.java Sat May 13 20:25:56 2006
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+
+/**
+ *	<p>Base 16 encoder.</p>
+ *
+ *	@author	Marc Prud'hommeaux
+ *	@nojavadoc
+ */
+public class Base16Encoder
+{
+	private final static char[] HEX = new char[] {
+		'0', '1', '2', '3', '4', '5', '6', '7',
+		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 
+	};
+
+
+	/**
+	 *	Convert bytes to a base16 string.
+	 */
+	public static String encode (byte[] byteArray)
+	{
+		StringBuffer hexBuffer = new StringBuffer (byteArray.length * 2);
+		for (int i = 0; i < byteArray.length; i++)
+			for (int j = 1; j >= 0; j--)
+				hexBuffer.append (HEX[(byteArray[i] >> (j * 4)) & 0xF]);
+		return hexBuffer.toString ();
+	}
+
+
+	/**
+	 *	Convert a base16 string into a byte array.
+	 */
+	public static byte[] decode (String s)
+	{
+		int len = s.length ();
+		byte[] r = new byte[len / 2];
+		for (int i = 0; i < r.length; i++)
+		{
+			int digit1 = s.charAt (i * 2), digit2 = s.charAt (i * 2 + 1);
+			if (digit1 >= '0' && digit1 <= '9')
+				digit1 -= '0';
+			else if (digit1 >= 'A' && digit1 <= 'F')
+				digit1 -= 'A' - 10;
+			if (digit2 >= '0' && digit2 <= '9')
+				digit2 -= '0';
+			else if (digit2 >= 'A' && digit2 <= 'F')
+				digit2 -= 'A' - 10;
+
+			r[i] = (byte) ((digit1 << 4) + digit2);
+		}
+		return r;
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Base16Encoder.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/BytecodeWriter.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/BytecodeWriter.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/BytecodeWriter.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/BytecodeWriter.java Sat May 13 20:25:56 2006
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+import java.io.*;
+
+import serp.bytecode.*;
+
+
+/**
+ *	Control how enhanced bytecode is written.
+ *	
+ *	@author	Steve Kim
+ */
+public interface BytecodeWriter
+{
+	public void write (BCClass type)
+		throws IOException;
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/BytecodeWriter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Closeable.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Closeable.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Closeable.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Closeable.java Sat May 13 20:25:56 2006
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+
+/**
+ *	<p>Generic interface for components that can be closed so that helpers
+ *	can treate them in a generic way.</p>
+ *
+ *	@author		Abe White
+ *	@published
+ */
+public interface Closeable
+{
+	public void close ()
+		throws Exception;
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/Closeable.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/CodeFormat.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/CodeFormat.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/CodeFormat.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/CodeFormat.java Sat May 13 20:25:56 2006
@@ -0,0 +1,700 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+
+/**
+ *	<p>Encapsulates some common Java source code formatting options.  The
+ *	class can also be used as a buffer for formatted Java code.</p>
+ *
+ *	@author		Abe White
+ */
+public final class CodeFormat
+	implements Cloneable
+{
+	private static final String _sep = System.getProperty ("line.separator");
+
+	private String	_tab					= "\t";
+	private boolean _spaceBeforeParen		= false;
+	private boolean _spaceInParen			= false;
+	private boolean _braceOnSameLine		= true;
+	private boolean _braceAtSameTabLevel	= false;
+	private boolean _scoreBeforeFieldName	= false;
+	private int		_linesBetweenSections	= 2;
+
+	private StringBuffer _buf = new StringBuffer ();
+
+
+	/**
+	 *	The number of spaces to use for tabs; 0 means to use actual tab 
+	 *	characters.  Defaults to 0.
+	 */
+	public int getTabSpaces ()
+	{
+		return (_tab.equals ("\t")) ? 0 : _tab.length ();
+	}
+
+
+	/**
+	 *	The number of spaces to use for tabs; 0 means to use actual tab 
+	 *	characters.  Defaults to 0.
+	 */
+	public void setTabSpaces (int tab)
+	{
+		if (tab == 0)
+			_tab = "\t";
+		else
+		{
+			StringBuffer tabs = new StringBuffer (tab);
+			for (int i = 0; i < tab; i++)
+				tabs.append (" ");
+			_tab = tabs.toString ();	
+		}
+	}
+
+
+	/**
+	 *	Whether to place a space before parentheses.  Defaults to false.
+	 */
+	public boolean getSpaceBeforeParen ()
+	{
+		return _spaceBeforeParen;
+	}
+
+
+	/**
+	 *	Whether to place a space before parentheses.  Defaults to false.
+	 */
+	public void setSpaceBeforeParen (boolean spaceBeforeParen)
+	{
+		_spaceBeforeParen = spaceBeforeParen;
+	}
+
+
+	/**
+	 *	Whether to place a space within parentheses.  Defaults to false.
+	 */
+	public boolean getSpaceInParen ()
+	{
+		return _spaceInParen;
+	}
+
+
+	/**
+	 *	Whether to place a space within parentheses.  Defaults to false.
+	 */
+	public void setSpaceInParen (boolean spaceInParen)
+	{
+		_spaceInParen = spaceInParen;
+	}
+
+
+	/**
+	 *	Whether to place opening braces on the same line as the 
+	 *	block declaration, or on the next line.  Defaults to same line.
+	 */
+	public boolean getBraceOnSameLine ()
+	{
+		return _braceOnSameLine;
+	}
+
+
+	/**
+	 *	Whether to place opening braces on the same line as the 
+	 *	block declaration, or on the next line.  Defaults to same line.
+	 */
+	public void setBraceOnSameLine (boolean braceOnSameLine)
+	{
+		_braceOnSameLine = braceOnSameLine;
+	}
+
+
+	/**
+	 *	Whether to place braces at the same tab level as the code within
+	 *	the block.  Defaults to false.
+	 */
+	public boolean getBraceAtSameTabLevel ()
+	{
+		return _braceAtSameTabLevel;
+	}
+
+
+	/**
+	 *	Whether to place braces at the same tab level as the code within
+	 *	the block.  Defaults to false.
+	 */
+	public void setBraceAtSameTabLevel (boolean braceAtSameTabLevel)
+	{
+		_braceAtSameTabLevel = braceAtSameTabLevel;
+	}
+
+
+	/**
+	 *	Whether to place an underscore before private field names.  Defaults
+	 *	to false.
+	 */
+	public boolean getScoreBeforeFieldName ()
+	{
+		return _scoreBeforeFieldName;
+	}
+
+
+	/**
+	 *	Whether to place an underscore before private field names.  Defaults
+	 *	to false.
+	 */
+	public void setScoreBeforeFieldName (boolean scoreBeforeFieldName)
+	{
+		_scoreBeforeFieldName = scoreBeforeFieldName;
+	}
+
+
+	/**
+	 *	The number of empty lines between code sections.  Defaults to 2.
+	 */
+	public int getLinesBetweenSections ()
+	{
+		return _linesBetweenSections;
+	}
+
+
+	/**
+	 *	The number of empty lines between sections.  Defaults to 2.
+	 */
+	public void setLinesBetweenSections (int linesBetweenSections)
+	{
+		_linesBetweenSections = linesBetweenSections;
+	}
+
+
+	/**
+	 *	Return a new line character.
+	 */
+	public String getEndl ()
+	{
+		return getEndl (1);
+	}
+
+
+	/**
+	 *	Return the given number of new line characters.
+	 */
+	public String getEndl (int num)
+	{
+		if (num == 0)
+			return "";
+		if (num == 1)
+			return _sep;
+
+		StringBuffer buf = new StringBuffer (_sep.length () * num);
+		for (int i = 0; i < num; i++)
+			buf.append (_sep);
+		return buf.toString ();
+	}
+
+
+	/**
+	 *	Return the given number of new line characters, followed by
+	 *	the given tab level indentation.
+	 */
+	public String getEndl (int num, int tabs)
+	{
+		return getEndl (num) + getTab (tabs);
+	}
+
+
+	/**
+	 *	Return {#getLinesBetweenSections} + 1 new line characters.
+	 */
+	public String getAfterSection ()
+	{
+		return getEndl (getLinesBetweenSections () + 1);
+	}
+
+
+	/**
+	 *	Open parentheses string.  Users can choose to place spaces before
+	 *	and within parentheses.
+	 */
+	public String getOpenParen (boolean methodOrIf)
+	{
+		if ((_spaceBeforeParen && methodOrIf) && _spaceInParen)
+			return " ( ";
+		if (_spaceBeforeParen && methodOrIf)
+			return " (";
+		if (_spaceInParen)
+			return "( ";
+		return "(";
+	}
+
+
+	/**
+	 *	Close parentheses string.  Users can choose to place spaces within
+	 *	parentheses.
+	 */
+	public String getCloseParen ()
+	{
+		if (_spaceInParen)
+			return " )";
+		return ")";
+	}
+
+
+	/**
+	 *	Paired parentheses for empty method parameters.  Users can choose
+	 *	to place spaces before parentheses.
+	 */
+	public String getParens ()
+	{
+		if (_spaceBeforeParen)
+			return " ()";
+		return "()";
+	}
+
+
+	/**
+	 *	Open brace string.  Users can choose to place braces on the same
+	 *	line, or on a new line, and can choose the indenting level.
+	 *	
+	 *	@param	tabLevel	the tab level of code within the brace
+	 */
+	public String getOpenBrace (int tabLevel)
+	{
+		if (_braceOnSameLine)
+			return " {";
+		if (_braceAtSameTabLevel)
+			return getEndl () + getTab (tabLevel) + "{";
+		return getEndl () + getTab (tabLevel - 1) + "{";
+	}
+
+
+	/**
+	 *	Close brace string.  Users can choose to place braces on the same
+	 *	line, or on a new line, and can choose the indenting level.
+	 *	
+	 *	@param	tabLevel	the tab level of code within the brace
+	 */
+	public String getCloseBrace (int tabLevel)
+	{
+		if (_braceAtSameTabLevel)
+			return getTab (tabLevel) + "}";
+		return getTab (tabLevel - 1) + "}";
+	}
+
+
+	/**
+	 *	Extends declaration.  Uses configuration of {@link #openBrace},
+	 *	but prints "extends" instead of a brace.
+	 */
+	public String getExtendsDec (int tabLevel)
+	{
+		if (_braceOnSameLine)
+			return " extends";
+		if (_braceAtSameTabLevel)
+			return getEndl () + getTab (tabLevel) + "extends";
+		return getEndl () + getTab (tabLevel) + "extends";
+	}
+
+
+	/**
+	 *	Implements declaration.  Uses configuration of {@link #openBrace},
+	 *	but prints "implements" instead of a brace.
+	 */
+	public String getImplementsDec (int tabLevel)
+	{
+		if (_braceOnSameLine)
+			return " implements";
+		if (_braceAtSameTabLevel)
+			return getEndl () + getTab (tabLevel) + "implements";
+		return getEndl () + getTab (tabLevel) + "implements";
+	}	
+
+
+	/**
+	 *	Throws declaration.  Uses configuration of {@link #openBrace},
+	 *	but prints "throws" instead of a brace.
+	 */
+	public String getThrowsDec (int tabLevel)
+	{
+		if (_braceOnSameLine)
+			return " throws";
+		if (_braceAtSameTabLevel)
+			return getEndl () + getTab (tabLevel) + "throws";
+		return getEndl () + getTab (tabLevel) + "throws";
+	}	
+
+
+	/**
+	 *	Tab string.  Users can choose to use spaces or tab characters.
+	 */
+	public String getTab ()
+	{
+		return getTab (1);
+	}
+ 
+
+	/**
+	 *	Tab string.  Users can choose to use spaces or tab characters.
+	 *	
+	 *	@param	tabLevel	the number of tabs
+	 */
+	public String getTab (int tabLevel)
+	{
+		if (tabLevel == 0)
+			return "";
+		if (tabLevel == 1)
+			return _tab;
+
+		StringBuffer tabs = new StringBuffer (_tab.length () * tabLevel);
+		for (int i = 0; i < tabLevel; i++)
+			tabs.append (_tab);
+		return tabs.toString ();	
+	}
+
+
+	/**
+	 *	Return the field name for given suggested name, possibly adding
+	 *	leading underscore.
+	 */
+	public String getFieldName (String fieldName)
+	{
+		return (_scoreBeforeFieldName) ? "_" + fieldName : fieldName;
+	}
+
+
+	/**
+	 *	Return the internal code buffer.
+	 */
+	public StringBuffer getBuffer ()
+	{
+		return _buf;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (boolean val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (byte val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (char val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (double val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (float val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (int val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (long val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (short val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 */
+	public CodeFormat append (Object val)
+	{
+		_buf.append (val);
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getEndl()
+	 */
+	public CodeFormat endl ()
+	{
+		_buf.append (getEndl ());
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getEndl(int)
+	 */
+	public CodeFormat endl (int num)
+	{
+		_buf.append (getEndl (num));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getEndl(int, int)
+	 */
+	public CodeFormat endl (int num, int tabs)
+	{
+		_buf.append (getEndl (num, tabs));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getAfterSection
+	 */
+	public CodeFormat afterSection ()
+	{
+		_buf.append (getAfterSection ());
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getOpenParen
+	 */
+	public CodeFormat openParen (boolean methodOrIf)
+	{
+		_buf.append (getOpenParen (methodOrIf));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getCloseParen
+	 */
+	public CodeFormat closeParen ()
+	{
+		_buf.append (getCloseParen ());
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getParens
+	 */
+	public CodeFormat parens ()
+	{
+		_buf.append (getParens ());
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getOpenBrace
+	 */
+	public CodeFormat openBrace (int tabLevel)
+	{
+		_buf.append (getOpenBrace (tabLevel));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getCloseBrace
+	 */
+	public CodeFormat closeBrace (int tabLevel)
+	{
+		_buf.append (getCloseBrace (tabLevel));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getExtendsDec
+	 */
+	public CodeFormat extendsDec (int tabLevel)
+	{
+		_buf.append (getExtendsDec (tabLevel));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getImplementsDec
+	 */
+	public CodeFormat implementsDec (int tabLevel)
+	{
+		_buf.append (getImplementsDec (tabLevel));
+		return this;
+	}	
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getThrowsDec
+	 */
+	public CodeFormat throwsDec (int tabLevel)
+	{
+		_buf.append (getThrowsDec (tabLevel));
+		return this;
+	}	
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getTab
+	 */
+	public CodeFormat tab ()
+	{
+		_buf.append (getTab ());
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getTab
+	 */
+	public CodeFormat tab (int tabLevel)
+	{
+		_buf.append (getTab (tabLevel));
+		return this;
+	}
+
+
+	/**
+	 *	Append the given value to the internal buffer.
+	 *
+	 *	@see	#getFieldName
+	 */
+	public CodeFormat fieldName (String name)
+	{
+		_buf.append (getFieldName (name));
+		return this;
+	}
+
+
+	/**
+	 *	Clear the internal code buffer.
+	 */
+	public void clear ()
+	{
+		_buf = new StringBuffer ();
+	}
+
+
+	/**
+	 *	Return the internal buffer as a string.
+	 */
+	public String toString ()
+	{
+		return _buf.toString ();
+	}
+
+
+	/**
+	 *	Return the length of the internal buffer.
+	 */
+	public int length ()
+	{
+		return _buf.length ();
+	}
+
+
+	/**
+	 *	Make a copy of this code format object with all the same formatting
+	 *	settings.
+	 */
+	public Object clone ()
+	{
+		CodeFormat format = new CodeFormat ();
+		format._tab = _tab;
+		format._spaceBeforeParen = _spaceBeforeParen;
+		format._spaceInParen = _spaceInParen;
+		format._braceOnSameLine = _braceOnSameLine;
+		format._braceAtSameTabLevel = _braceAtSameTabLevel;
+		format._scoreBeforeFieldName = _scoreBeforeFieldName;
+		format._linesBetweenSections = _linesBetweenSections;
+		return format;
+	}
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/CodeFormat.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/ConcurrentHashMap.java
URL: http://svn.apache.org/viewcvs/incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/ConcurrentHashMap.java?rev=406215&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/ConcurrentHashMap.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/ConcurrentHashMap.java Sat May 13 20:25:56 2006
@@ -0,0 +1,965 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openjpa.lib.util;
+
+
+/*
+ * @author Copyright (c) 1997 by WebLogic, Inc. All Rights Reserved.
+ */
+import java.io.*;
+import java.util.*;
+
+
+/** This class implements a HashMap which has limited synchronization.
+  * In particular mutators are generally synchronized while accessors
+  * are generally not.  Additionally the Iterators returned by this
+  * class are not "fail-fast", but instead try to continue to iterate
+  * over the data structure after changes have been made.
+  *
+  * The synchronization semantics are built right in to the
+  * implementation rather than using a delegating wrapper like the
+  * other collection classes do because it wasn't clear to me that the
+  * how the two should be seperated or that it would be useful to do
+  * so.  This can probably be a topic for further debate in the
+  * future.
+  *
+  * This class is based heavily on the HashMap class in the Java
+  * collections package. */
+public class ConcurrentHashMap extends AbstractMap
+	implements Map, Cloneable, Serializable 
+{
+	private static Localizer _loc = Localizer.forPackage
+		(ConcurrentHashMap.class);
+
+	/**
+	 * The default initial capacity - MUST be a power of two.
+	 */
+	private static final int DEFAULT_INITIAL_CAPACITY = 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.
+	 */
+	private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+	/**
+	 * The load fast used when none specified in constructor.
+	 **/
+	private static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+	/**
+	 * Value representing null keys inside tables.
+	 */
+	private static final Object NULL_KEY = new Object ();
+
+	/**
+	 * The table, resized as necessary. Length MUST Always be a power of two.
+	 */
+	private transient Entry[] table;
+
+	/**
+	 * The number of key-value mappings contained in this identity hash map.
+	 */
+	private transient int size;
+
+	/**
+	 * The next size value at which to resize (capacity * load factor).
+	 * @serial
+	 */
+	private int threshold;
+
+	/**
+	 * The load factor for the hash table.
+	 *
+	 * @serial
+	 */
+	private final float loadFactor;
+
+	/**
+	 * Constructs an empty <tt>ConcurrentHashMap</tt> with the specified initial
+	 * capacity and load factor.
+	 *
+	 * @param	initialCapacity The initial capacity.
+	 * @param	loadFactor			The load factor.
+	 * @throws IllegalArgumentException if the initial capacity is negative
+	 *				 or the load factor is nonpositive.
+	 */
+	public ConcurrentHashMap (int initialCapacity, float loadFactor) 
+	{
+		if (initialCapacity < 0) 
+		{
+			throw new IllegalArgumentException (_loc.get ("concurrent-initial",
+				initialCapacity + ""));
+		}
+		if (initialCapacity > MAXIMUM_CAPACITY)
+			initialCapacity = MAXIMUM_CAPACITY;
+		if (loadFactor <= 0 || loadFactor > 1) 
+		{
+			throw new IllegalArgumentException (_loc.get ("concurrent-load",
+				loadFactor + ""));
+		}
+
+		// Find a power of 2 >= initialCapacity
+		int capacity = 1;
+		while (capacity < initialCapacity) capacity <<= 1;
+
+		this.loadFactor = loadFactor;
+		threshold = (int) (capacity * loadFactor);
+		table = new Entry[capacity];
+	}
+
+
+	/**
+	 * Constructs an empty <tt>ConcurrentHashMap</tt> with the specified initial
+	 * capacity and the default load factor (0.75).
+	 *
+	 * @param	initialCapacity the initial capacity.
+	 * @throws IllegalArgumentException if the initial capacity is negative.
+	 */
+	public ConcurrentHashMap (int initialCapacity) 
+	{
+		this (initialCapacity, DEFAULT_LOAD_FACTOR);
+	}
+
+
+	/**
+	 * Constructs an empty <tt>ConcurrentHashMap</tt> with the default initial
+	 * capacity (16) and the default load factor (0.75).
+	 */
+	public ConcurrentHashMap () 
+	{
+		this (DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+	}
+
+
+	/**
+	 * Constructs a new <tt>ConcurrentHashMap</tt> with the same mappings as the
+	 * specified <tt>Map</tt>.	The <tt>ConcurrentHashMap</tt> is created with
+	 * default load factor (0.75) and an initial capacity sufficient to
+	 * hold the mappings in the specified <tt>Map</tt>.
+	 *
+	 * @param	 m the map whose mappings are to be placed in this map.
+	 * @throws	NullPointerException if the specified map is null.
+	 */
+	public ConcurrentHashMap (Map m) 
+	{
+		this (Math.max ( (int) (m.size () / DEFAULT_LOAD_FACTOR) + 1,
+			DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
+		putAll (m);
+	}
+
+
+	// internal utilities
+
+
+	/**
+	 * Returns internal representation for key. Use NULL_KEY if key is null.
+	 */
+	private static Object maskNull (Object key) 
+	{
+		return (key == null ? NULL_KEY : key);
+	}
+
+
+	/**
+	 * Returns key represented by specified internal representation.
+	 */
+	private static Object unmaskNull (Object key) 
+	{
+		return (key == NULL_KEY ? null : key);
+	}
+
+
+	/**
+	 * Returns a hash code for non-null Object x.
+	 */
+	private static int hash (Object x) 
+	{
+		int h = x.hashCode ();
+		return h - (h << 7);	// i.e., -127 * h
+	}
+
+
+	/**
+	 * Check for equality of non-null reference x and possibly-null y.
+	 */
+	private static boolean eq (Object x, Object y) 
+	{
+		return x == y || x.equals (y);
+	}
+
+
+	/**
+	 * Returns the current capacity of backing table in this map.
+	 *
+	 * @return the current capacity of backing table in this map.
+	 */
+	public final int capacity () 
+	{
+		return table.length;
+	}
+	
+	/**
+	 * Returns the load factor for this map.
+	 *
+	 * @return the load factor for this map.
+	 */
+	public final float loadFactor () 
+	{
+		return loadFactor;
+	}
+	
+	/**
+	 * Returns the number of key-value mappings in this map.
+	 *
+	 * @return the number of key-value mappings in this map.
+	 */
+	public final int size () 
+	{
+		return size;
+	}
+
+
+	/**
+	 * 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 final boolean isEmpty () 
+	{
+		return size == 0;
+	}
+
+
+	/**
+	 * Returns the value to which the specified key is mapped in this identity
+	 * hash map, or <tt>null</tt> if the map contains no mapping for this key.
+	 * A return value of <tt>null</tt> does not <i>necessarily</i> indicate
+	 * that the map contains no mapping for the key; it is also possible that
+	 * the map explicitly maps the key to <tt>null</tt>. The
+	 * <tt>containsKey</tt> method may be used to distinguish these two cases.
+	 *
+	 * @param	 key the key whose associated value is to be returned.
+	 * @return	the value to which this map maps the specified key, or
+	 *					<tt>null</tt> if the map contains no mapping for this 
+						key.
+	 * @see #put (Object, Object)
+	 */
+	public Object get (Object key) 
+	{
+		Entry e = getEntry (key);
+		return e == null? null: e.value;
+	}
+
+
+	/**
+	 * Returns <tt>true</tt> if this map contains a mapping for the
+	 * specified key.
+	 *
+	 * @param	 key	 The key whose presence in this map is to be tested
+	 * @return <tt>true</tt> if this map contains a mapping for the specified
+	 * key.
+	 */
+	public final boolean containsKey (Object key) 
+	{
+		return getEntry (key) != null;
+	}
+
+
+	/**
+	 * Returns the entry associated with the specified key in the
+	 * ConcurrentHashMap.	Returns null if the ConcurrentHashMap contains no
+	 * mapping for this key.
+	 */
+	protected Entry getEntry (Object key) 
+	{
+		Object k = maskNull (key);
+		int hash = hash (k);
+		Entry[] tab = table;
+		for (Entry e = tab[hash & (tab.length-1)]; e != null; e = e.next) 
+		{
+			if (e.hash == hash && eq (k, e.key)) return e;
+		}
+		return null;
+	}
+
+
+	/**
+	 * Associates the specified value with the specified key in this map.
+	 * If the map previously contained a mapping for this key, the old
+	 * value is replaced.
+	 *
+	 * @param key key with which the specified value is to be associated.
+	 * @param value value to be associated with the specified key.
+	 * @return previous value associated with specified key, or <tt>null</tt>
+	 *				 if there was no mapping for key.	A <tt>null</tt> return
+	 *				 can also indicate that the ConcurrentHashMap previously
+	 *				 associated
+	 *				 <tt>null</tt> with the specified key.
+	 */
+	public Object put (Object key, Object value) 
+	{
+		Object k = maskNull (key);
+		int hash = hash (k);
+		synchronized (this) 
+	{
+			int i = hash & (table.length - 1);
+
+			for (Entry e = table[i]; e != null; e = e.next) 
+			{
+				if (e.hash == hash && eq (k, e.key)) 
+				{
+					Object oldValue = e.value;
+					e.value = value;
+					return oldValue;
+				}
+			}
+
+			table[i] = createEntry (hash, k, value, table[i]);
+			if (size++ >= threshold) resize (2 * table.length);
+		}
+		return null;
+	}
+
+
+	public Object putIfAbsent (Object key, Object value) 
+	{
+		Object k = maskNull (key);
+		int hash = hash (k);
+		synchronized (this) 
+		{
+			int i = hash & (table.length - 1);
+
+			for (Entry e = table[i]; e != null; e = e.next) 
+			{
+				if (e.hash == hash && eq (k, e.key)) 
+				{
+					return e.value;
+				}
+			}
+
+			table[i] = createEntry (hash, k, value, table[i]);
+			if (size++ >= threshold) resize (2 * table.length);
+		}
+		return null;
+	}
+
+
+	/**
+	 * Rehashes the contents of this map into a new <tt>ConcurrentHashMap</tt>
+	 * instance with a larger capacity. This method is called automatically when
+	 * the number of keys in this map exceeds its capacity and load factor.
+	 *
+	 * @param newCapacity the new capacity, MUST be a power of two.
+	 */
+	private void resize (int newCapacity) 
+	{
+		// assert (newCapacity & -newCapacity) == newCapacity; // power of 2
+		Entry[] oldTable = table;
+		int oldCapacity = oldTable.length;
+
+		// check if needed
+		if (size < threshold || oldCapacity > newCapacity) return;
+
+		Entry[] newTable = new Entry[newCapacity];
+		int mask = newCapacity-1;
+		for (int i = oldCapacity; i-- > 0; ) 
+		{
+			for (Entry e = oldTable[i]; e != null; e = e.next) 
+			{
+				Entry clone = (Entry) e.clone ();
+				int j = clone.hash & mask;
+				clone.next = newTable[j];
+				newTable[j] = clone;
+			}
+		}
+		table = newTable;
+		threshold = (int) (newCapacity * loadFactor);
+	}
+
+
+	/**
+	 * Copies all of the mappings from the specified map to this map
+	 * These mappings will replace any mappings that
+	 * this map had for any of the keys currently in the specified map.
+	 *
+	 * @param t mappings to be stored in this map.
+	 * @throws NullPointerException if the specified map is null.
+	 */
+	public final synchronized void putAll (Map t) 
+	{
+		// Expand enough to hold t's elements without resizing.
+		int n = t.size ();
+		if (n == 0) return;
+		if (n >= threshold) 
+		{
+			n = (int) (n / loadFactor + 1);
+			if (n > MAXIMUM_CAPACITY) n = MAXIMUM_CAPACITY;
+			int capacity = table.length;
+			while (capacity < n) capacity <<= 1;
+			resize (capacity);
+		}
+
+		for (Iterator i = t.entrySet ().iterator (); i.hasNext (); ) 
+		{
+			Map.Entry e = (Map.Entry) i.next ();
+			put (e.getKey (), e.getValue ());
+		}
+	}
+
+
+	/**
+	 * Removes the mapping for this key from this map if present.
+	 *
+	 * @param	key key whose mapping is to be removed from the map.
+	 * @return previous value associated with specified key, or <tt>null</tt>
+	 *				 if there was no mapping for key.	A <tt>null</tt> return
+	 *				 can also indicate that the map previously associated
+	 *				 <tt>null</tt> with the specified key.
+	 */
+	public Object remove (Object key) 
+	{
+		Entry e = removeEntryForKey (key, null);
+		return (e == null ? e : e.value);
+	}
+
+
+	/**
+	 * Removes the mapping for this key from this map if present and value
+	 * equals the parameter value. If parameter value is null, behaves
+	 * exactly like <code>remove (Object key)</code>.
+	 *
+	 * @param	key key whose mapping is to be removed from the map.
+	 * @param	value value that is mapped to this key.
+	 * @return <tt>true</tt> if the entry was removed, or <tt>false</tt>
+	 *				 if there was no mapping for key or the key is not mapped to
+	 *					 the parameter value.
+	 */
+	public boolean remove (Object key, Object value) 
+	{
+		Entry e = removeEntryForKey (key, value);
+		return (e == null ? false : true);
+	}
+
+
+	/**
+	 * Removes and returns the entry associated with the specified key and value
+	 * in the ConcurrentHashMap. If value is null, only matches the key.
+	 * Returns null if the ConcurrentHashMap contains no mapping for this key or
+	 * key is not mapped to the input value.
+	 */
+	private Entry removeEntryForKey (Object key, Object v) 
+	{
+		Object k = maskNull (key);
+		int hash = hash (k);
+		synchronized (this) 
+		{
+			int i = hash & (table.length - 1);
+			Entry e = table[i];
+
+			if (e == null) return null;
+			if (e.hash == hash && eq (k, e.key) && 
+				(v == null || eq (v, e.value))) 
+			{
+				size--;
+				table[i] = e.next;
+				return e;
+			}
+
+			Entry prev = e;
+			for (e = e.next; e != null; prev = e, e = e.next) 
+			{
+				if (e.hash == hash && eq (k, e.key) && 
+					(v == null || eq (v, e.value))) 
+				{
+					size--;
+					prev.next = e.next;
+					return e;
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Special version of remove for EntrySet.
+	 */
+	private Entry removeMapping (Object o) 
+	{
+		if (! (o instanceof Map.Entry)) return null;
+
+		Map.Entry entry = (Map.Entry) o;
+		Object k = maskNull (entry.getKey ());
+		int hash = hash (k);
+		synchronized (this) 
+		{
+			int i = hash & (table.length - 1);
+			Entry e = table[i];
+
+			if (e == null) return null;
+			if (e.hash == hash && e.equals (entry)) 
+			{
+				size--;
+				table[i] = e.next;
+				return e;
+			}
+
+			Entry prev = e;
+			for (e = e.next; e != null; prev = e, e = e.next) 
+			{
+				if (e.hash == hash && e.equals (entry)) 
+				{
+					size--;
+					prev.next = e.next;
+					return e;
+				}
+			}
+		}
+		return null;
+	}
+
+
+	/**
+	 * Removes all mappings from this map.
+	 */
+	public synchronized void clear () 
+	{
+		table = new Entry[table.length];
+		size = 0;
+	}
+
+
+	/**
+	 * Returns <tt>true</tt> if this map maps one or more keys to the
+	 * specified value.
+	 *
+	 * @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.
+	 */
+	public final boolean containsValue (Object value) 
+	{
+		if (value == null) return containsNullValue ();
+
+		Entry tab[] = table;
+		for (int i = 0; i < tab.length ; i++) 
+		{
+			for (Entry e = tab[i] ; e != null ; e = e.next) 
+			{
+				if (value.equals (e.value)) return true;
+			}
+		}
+		return false;
+	}
+
+
+	/**
+	 * Special-case code for containsValue with null argument
+	 **/
+	private boolean containsNullValue () 
+	{
+		Entry tab[] = table;
+		for (int i = 0; i < tab.length ; i++) 
+		{
+			for (Entry e = tab[i] ; e != null ; e = e.next) 
+			{
+				if (e.value == null) return true;
+			}
+		}
+		return false;
+	}
+
+
+	/**
+	 * Returns a shallow copy of this <tt>ConcurrentHashMap</tt> instance: the
+	 * keys and values themselves are not cloned.
+	 *
+	 * @return a shallow copy of this map.
+	 */
+	public final Object clone () 
+	{
+		return new ConcurrentHashMap (this);
+	}
+
+
+	protected Entry createEntry (int h, Object k, Object v, Entry n) 
+	{
+		return new Entry (h, k, v, n);
+	}
+
+
+	protected static class Entry implements Map.Entry 
+	{
+
+		final Object key;
+		Object value;
+		final int hash;
+		Entry next;
+
+		/**
+		 * Create new entry.
+		 */
+		protected Entry (int h, Object k, Object v, Entry n) 
+		{
+			value = v;
+			next = n;
+			key = k;
+			hash = h;
+		}
+
+
+		public Object getKey () 
+		{
+			return unmaskNull (key);
+		}
+
+
+		public Object getValue () 
+		{
+			return value;
+		}
+
+
+		public Object setValue (Object newValue) 
+		{
+			Object oldValue = value;
+			value = newValue;
+			return oldValue;
+		}
+
+
+		public boolean equals (Object o) 
+		{
+			if (! (o instanceof Map.Entry)) return false;
+			Map.Entry e = (Map.Entry) o;
+			Object k1 = getKey ();
+			Object k2 = e.getKey ();
+			if (k1 == k2 || (k1 != null && k1.equals (k2))) 
+			{
+				Object v1 = getValue ();
+				Object v2 = e.getValue ();
+				if (v1 == v2 || (v1 != null && v1.equals (v2)))
+					return true;
+			}
+			return false;
+		}
+
+
+		public int hashCode () 
+		{
+			return (key==NULL_KEY ? 0 : key.hashCode ()) ^
+				 (value==null	 ? 0 : value.hashCode ());
+		}
+
+
+		protected Object clone () 
+		{
+			// It is the callers responsibility to set the next field
+			// correctly.
+			return new Entry (hash, key, value, null);
+		}
+	}
+
+
+	private abstract class HashIterator implements Iterator 
+	{
+		final Entry[] table = ConcurrentHashMap.this.table;
+		Entry next;									// next entry to return
+		int index;									 // current slot
+		Entry current;							 // current entry
+
+		HashIterator () 
+		{
+			if (size == 0) return;
+			Entry[] t = table;
+			int i = t.length-1;
+			Entry n = t[i];
+			while (n == null && i > 0) n = t[--i];
+			index = i;
+			next = n;
+		}
+
+
+		public final boolean hasNext () 
+		{
+			return next != null;
+		}
+
+
+		final Entry nextEntry () 
+		{
+			Entry e = next;
+			if (e == null) throw new NoSuchElementException ();
+
+			Entry n = e.next;
+			Entry[] t = table;
+			int i = index;
+			while (n == null && i > 0) n = t[--i];
+			index = i;
+			next = n;
+			return current = e;
+		}
+
+
+		public final void remove () 
+		{
+			if (current == null) throw new IllegalStateException ();
+			Object k = current.key;
+			current = null;
+			ConcurrentHashMap.this.removeEntryForKey (k, null);
+		}
+	}
+
+
+	private final class ValueIterator extends HashIterator 
+	{
+		public Object next () 
+		{
+			return nextEntry ().value;
+		}
+	}
+
+
+	private final class KeyIterator extends HashIterator 
+	{
+		public Object next () 
+		{
+			return nextEntry ().getKey ();
+		}
+	}
+
+
+	private final class EntryIterator extends HashIterator 
+	{
+		public Object next () 
+		{
+			return nextEntry ();
+		}
+	}
+
+
+	// Views
+
+	private transient Set entrySet = null;
+	private transient Set keySet = null;
+	private transient Collection values = null;
+
+	/**
+	 * Returns a 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.
+	 *
+	 * @return a set view of the keys contained in this map.
+	 */
+	public final Set keySet () 
+	{
+		Set ks = keySet;
+		return (ks != null ? ks : (keySet = new KeySet ()));
+	}
+
+
+	private final class KeySet extends AbstractSet 
+	{
+		public Iterator iterator () 
+		{
+			return new KeyIterator ();
+		}
+
+
+		public int size () 
+		{
+			return size;
+		}
+
+
+		public boolean contains (Object o) 
+		{
+			return containsKey (o);
+		}
+
+
+		public boolean remove (Object o) 
+		{
+			return ConcurrentHashMap.this.removeEntryForKey (o, null) != null;
+		}
+
+
+		public void clear () 
+		{
+			ConcurrentHashMap.this.clear ();
+		}
+	}
+
+
+	/**
+	 * Returns a 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.
+	 *
+	 * @return a collection view of the values contained in this map.
+	 */
+	public final Collection values () 
+	{
+		Collection vs = values;
+		return (vs != null ? vs : (values = new Values ()));
+	}
+
+
+	private final class Values extends AbstractCollection 
+	{
+		public Iterator iterator () 
+		{
+			return new ValueIterator ();
+		}
+		public int size () 
+		{
+			return size;
+		}
+		public boolean contains (Object o) 
+		{
+			return containsValue (o);
+		}
+		public void clear () 
+		{
+			ConcurrentHashMap.this.clear ();
+		}
+	}
+
+
+	/**
+	 * Returns a collection view of the mappings contained in this map.	Each
+	 * element in the returned collection is a <tt>Map.Entry</tt>.	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 the 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.
+	 *
+	 * @return a collection view of the mappings contained in this map.
+	 * @see Map.Entry
+	 */
+	public final Set entrySet () 
+	{
+		Set es = entrySet;
+		return (es != null ? es : (entrySet = new EntrySet ()));
+	}
+
+
+	private final class EntrySet extends AbstractSet 
+	{
+		public Iterator iterator () 
+		{
+			return new EntryIterator ();
+		}
+		public boolean contains (Object o) 
+		{
+			if (! (o instanceof Map.Entry)) return false;
+			Map.Entry e = (Map.Entry) o;
+			Entry candidate = getEntry (e.getKey ());
+			return candidate != null && candidate.equals (e);
+		}
+		public boolean remove (Object o) 
+		{
+			return removeMapping (o) != null;
+		}
+		public int size () 
+		{
+			return size;
+		}
+		public void clear () 
+		{
+			ConcurrentHashMap.this.clear ();
+		}
+	}
+
+
+	/**
+	 * Save the state of the <tt>ConcurrentHashMap</tt> instance to a stream
+	 * (i.e., serialize it).
+	 *
+	 * @serialData The <i>capacity</i> of the ConcurrentHashMap (the length of
+	 * the bucket array) is emitted (int), followed by the <i>size</i> of the
+	 * ConcurrentHashMap (the number of key-value mappings), followed by the key
+	 * (Object) and value (Object) for each key-value mapping represented by the
+	 * ConcurrentHashMap The key-value mappings are emitted in the order that
+	 * they are returned by <tt>entrySet ().iterator ()</tt>.
+	 *
+	 */
+	private void writeObject (ObjectOutputStream s)
+		throws IOException
+	
+	{
+		// Write out the threshold, loadfactor, and any hidden stuff
+		s.defaultWriteObject ();
+
+		// Write out number of buckets
+		s.writeInt (table.length);
+
+		// Write out size (number of Mappings)
+		s.writeInt (size);
+
+		// Write out keys and values (alternating)
+		for (Iterator i = entrySet ().iterator (); i.hasNext (); ) 
+		{
+			Map.Entry e = (Map.Entry) i.next ();
+			s.writeObject (e.getKey ());
+			s.writeObject (e.getValue ());
+		}
+	}
+
+
+	private static final long serialVersionUID = -6452706556724125778L;
+
+	/**
+	 * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a stream (i.e.,
+	 * deserialize it).
+	 */
+	private void readObject (ObjectInputStream s)
+		throws IOException, ClassNotFoundException
+	
+	{
+		// Read in the threshold, loadfactor, and any hidden stuff
+		s.defaultReadObject ();
+
+		// Read in number of buckets and allocate the bucket array;
+		int numBuckets = s.readInt ();
+		table = new Entry[numBuckets];
+
+		// Read in size (number of Mappings)
+		int size = s.readInt ();
+
+		// Read the keys and values, and put the mappings in the 
+		// ConcurrentHashMap
+		for (int i=0; i<size; i++) 
+		{
+			Object key = s.readObject ();
+			Object value = s.readObject ();
+			put (key, value);
+		}
+	}
+
+
+}

Propchange: incubator/openjpa/trunk/openjpa-lib/java/org/apache/openjpa/lib/util/ConcurrentHashMap.java
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message