svn commit: r158176 [44/79] - in incubator/jdo/trunk/ri11: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/ejb/ src/java/org/apache/jdo/enhancer/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/enhancer/ src/java/org/apache/jdo/impl/enhancer/classfile/ src/java/org/apache/jdo/impl/enhancer/core/ src/java/org/apache/jdo/impl/enhancer/generator/ src/java/org/apache/jdo/impl/enhancer/meta/ src/java/org/apache/jdo/impl/enhancer/meta/model/ src/java/org/apache/jdo/impl/enhancer/meta/prop/ src/java/org/apache/jdo/impl/enhancer/meta/util/ src/java/org/apache/jdo/impl/enhancer/util/ src/java/org/apache/jdo/impl/fostore/ src/java/org/apache/jdo/impl/jdoql/ src/java/org/apache/jdo/impl/jdoql/jdoqlc/ src/java/org/apache/jdo/impl/jdoql/scope/ src/java/org/apache/jdo/impl/jdoql/tree/ src/java/org/apache/jdo/impl/model/ src/java/org/apache/jdo/impl/model/java/ src/java/org/apache/jdo/impl/model/java/runtime/ src/java/org/apache/jdo/impl/model/jdo/ src/java/org/apache/jdo/impl/model/jdo/caching/ src/java/org/apache/jdo/impl/model/jdo/util/ src/java/org/apache/jdo/impl/model/jdo/xml/ src/java/org/apache/jdo/impl/pm/ src/java/org/apache/jdo/impl/sco/ src/java/org/apache/jdo/impl/state/ src/java/org/apache/jdo/jdoql/ src/java/org/apache/jdo/jdoql/tree/ src/java/org/apache/jdo/model/ src/java/org/apache/jdo/model/java/ src/java/org/apache/jdo/model/jdo/ src/java/org/apache/jdo/pm/ src/java/org/apache/jdo/sco/ src/java/org/apache/jdo/state/ src/java/org/apache/jdo/store/ src/java/org/apache/jdo/util/ test/ test/conf/ test/enhancer/ test/enhancer/sempdept/ test/enhancer/sempdept/src/ test/enhancer/sempdept/src/empdept/ test/fsuid2/ test/fsuid2/org/ test/fsuid2/org/apache/ test/fsuid2/org/apache/jdo/ test/fsuid2/org/apache/jdo/pc/ test/java/ test/java/org/ test/java/org/apache/ test/java/org/apache/jdo/ test/java/org/apache/jdo/impl/ test/java/org/apache/jdo/impl/fostore/ test/java/org/apache/jdo/pc/ test/java/org/apache/jdo/pc/appid/ test/java/org/apache/jdo/pc/empdept/ test/java/org/apache/jdo/pc/serializable/ test/java/org/apache/jdo/pc/xempdept/ test/java/org/apache/jdo/test/ test/java/org/apache/jdo/test/query/ test/java/org/apache/jdo/test/util/ test/jdo/ test/jdo/org/ test/jdo/org/apache/ test/jdo/org/apache/jdo/ test/jdo/org/apache/jdo/pc/ test/jdo/org/apache/jdo/pc/appid/ test/jdo/org/apache/jdo/pc/empdept/ test/jdo/org/apache/jdo/pc/serializable/ test/jdo/org/apache/jdo/pc/xempdept/ xdocs/

19 Mar 2005 05:31:47 -0000

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Date.java
URL: 
http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Date.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Date.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Date.java Fri Mar 
18 17:02:29 2005
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2005 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.jdo.impl.sco;
+
+import javax.jdo.JDOHelper;
+
+import org.apache.jdo.sco.SCO;
+import org.apache.jdo.sco.SCODate;
+import org.apache.jdo.state.StateManagerInternal;
+
+
+
+/**
+ * A mutable 2nd class object that represents java.util.Date.
+ * @author Marina Vatkina
+ * @version 1.0
+ * @see java.util.Date
+ */
+public class Date extends java.util.Date implements SCODate {
+
+    private transient StateManagerInternal owner;
+
+    private transient int fieldNumber = -1;
+
+    private final static String _Date = "Date"; // NOI18N
+
+    /**
+     * Creates a <code>Date</code> object that represents the time at which
+     * it was allocated.
+     */
+    public Date() {
+        super();
+    }
+
+    /**
+     * Creates a <code>Date</code> object that represents the given time
+     * in milliseconds.
+     * @param date      the number of milliseconds
+     */
+    public Date(long date) {
+        super(date);
+    }
+
+    /**
+     * Sets the <tt>Date</tt> object to represent a point in time that is
+     * <tt>time</tt> milliseconds after January 1, 1970 00:00:00 GMT.
+     *   
+     * @param   time   the number of milliseconds.
+     * @see     java.util.Date
+     */  
+    public void setTime(long time) {
+        SCOHelper.debug(_Date, "setTime"); // NOI18N
+
+        this.makeDirty();
+        super.setTime(time);
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     *
+     * <P>Mutable Second Class Objects are required to provide a public
+     * clone method in order to allow for copying PersistenceCapable
+     * objects. In contrast to Object.clone(), this method must not throw a
+     * CloneNotSupportedException.
+     */
+    public Object clone() {
+        SCOHelper.debug(_Date, "clone"); // NOI18N
+
+        Object obj = super.clone();
+        if (obj instanceof SCO) 
+            ((SCO)obj).unsetOwner(owner, fieldNumber);
+
+        return obj;
+    }
+
+    /** -----------Depricated Methods------------------*/
+
+    /**
+     * Sets the year of this <tt>Date</tt> object to be the specified
+     * value plus 1900. 
+     *   
+     * @param   year    the year value.
+     * @see     java.util.Calendar
+     * @see     java.util.Date
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
+     */  
+    public void setYear(int year) {
+        SCOHelper.debug(_Date, "setYear"); // NOI18N
+
+        this.makeDirty();
+        super.setYear(year);
+    }  
+
+    /**
+     * Sets the month of this date to the specified value.      
+     * @param   month   the month value between 0-11.
+     * @see     java.util.Calendar
+     * @see     java.util.Date
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
+     */
+    public void setMonth(int month) {
+        SCOHelper.debug(_Date, "setMonth"); // NOI18N
+
+        this.makeDirty();
+        super.setMonth(month);
+    }    
+
+    /**
+     * Sets the day of the month of this <tt>Date</tt> object to the
+     * specified value. 
+     *   
+     * @param   date   the day of the month value between 1-31.
+     * @see     java.util.Calendar
+     * @see     java.util.Date
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
+     */  
+    public void setDate(int date) {
+        SCOHelper.debug(_Date, "setDate"); // NOI18N
+
+        this.makeDirty();
+        super.setDate(date);
+    } 
+
+    /**
+     * Sets the hour of this <tt>Date</tt> object to the specified value.
+     *   
+     * @param   hours   the hour value.
+     * @see     java.util.Calendar
+     * @see     java.util.Date
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
+     */  
+    public void setHours(int hours) {
+        SCOHelper.debug(_Date, "setHours"); // NOI18N
+
+        this.makeDirty();
+        super.setHours(hours);
+    }  
+
+    /**
+     * Sets the minutes of this <tt>Date</tt> object to the specified value.
+     *   
+     * @param   minutes   the value of the minutes.
+     * @see     java.util.Calendar
+     * @see     java.util.Date
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
+     */
+    public void setMinutes(int minutes) {
+        SCOHelper.debug(_Date, "setMinutes"); // NOI18N
+
+        this.makeDirty();
+        super.setMinutes(minutes);
+    }   
+ 
+    /**
+     * Sets the seconds of this <tt>Date</tt> to the specified value.
+     *   
+     * @param   seconds   the seconds value.
+     * @see     java.util.Calendar
+     * @see     java.util.Date
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
+     */  
+    public void setSeconds(int seconds) {
+        SCOHelper.debug(_Date, "setSeconds"); // NOI18N
+
+        this.makeDirty();
+        super.setSeconds(seconds);
+    } 
+
+    /** ---------------- internal methods ------------------- */
+
+    /**
+     * Sets the <tt>Date</tt> object without notification of the Owner
+     * field. Used internaly to populate date from DB
+     *   
+     * @param   time   the number of milliseconds.
+     * @see     java.util.Date
+     */  
+    public void setTimeInternal(long time) {
+        super.setTime(time);
+    }
+
+    /**
+     * @see SCO#unsetOwner(Object owner, int fieldNumber)
+     */
+    public void unsetOwner(Object owner, int fieldNumber) { 
+        // Unset only if owner and fieldNumber match.
+        if (this.owner == owner && this.fieldNumber == fieldNumber) {
+            this.owner = null; 
+            this.fieldNumber = -1;
+        }
+    }
+
+    /**
+     * @see SCO#setOwner (Object owner, int fieldNumber)
+     */
+    public void setOwner (Object owner, int fieldNumber) {
+        // Set only if it was not set before.
+        if (this.owner == null && owner instanceof StateManagerInternal) {
+            this.owner = (StateManagerInternal)owner;    
+            this.fieldNumber = fieldNumber;
+        }
+    }
+
+    /** 
+     * @see SCO#getOwner ()
+     */   
+    public Object getOwner() {   
+        return SCOHelper.getOwner(owner);
+    } 
+ 
+    /**  
+     * @see SCO#getOwner ()
+     */   
+    public String getFieldName() {
+        return SCOHelper.getFieldName(owner, fieldNumber);   
+    }
+
+    /**
+     * Marks object dirty
+     */
+    private void makeDirty() {
+        if (owner != null) {
+            owner.makeDirty(fieldNumber); //
+        } 
+     }   
+    
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Freezer.java
URL: 
http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Freezer.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Freezer.java 
(added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Freezer.java Fri 
Mar 18 17:02:29 2005
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/*
+ * Freezer.java
+ *
+ */
+
+package org.apache.jdo.impl.sco;
+
+import java.io.PrintStream;
+
+import java.lang.Comparable;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.jdo.JDOFatalInternalException;
+import javax.jdo.JDOUserException;
+import javax.jdo.JDOHelper;
+
+import javax.jdo.spi.PersistenceCapable;
+
+import org.apache.jdo.sco.SCO;
+import org.apache.jdo.sco.SCOCollection;
+import org.apache.jdo.sco.SCOMap;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+
+/** Freezer is a helper class with static methods to assist
+ * transcribing non-ordered collection and map classes.
+ * When an unordered collection or map is written to the datastore
+ * and subsequently fetched, the order of elements can change.
+ * This causes optimistic failures for persistent instances that
+ * contain unordered collections even if the collection has not
+ * changed.
+ * Another issue solved by the Freezer is that if the user defines
+ * an ordering or hashing based on persistent values of the
+ * elements, during transcribing while fetching the instance from
+ * the datastore the persistent instance must be fetched.  This
+ * causes recursion in the fetch process.
+ * Freezing is the process of iterating the elements of a collection
+ * or iterating the entrySet elements of a map and constructing an
+ * array of elements in an absolute ordering.  Freezing is done
+ * during transcribing for storage.
+ * Thawing is the process of iterating the frozen elements and
+ * storing them in their user-visible order or using their
+ * user-visible hashCode.
+ * A collection or map is frozen when read from the datastore,
+ * and thawed upon first application use.
+ * @author Craig Russell
+ * @version 1.0.2
+ * @since 1.0.1
+ */
+public class Freezer {
+    
+    /** This class currently is not used as a class but only as a helper.
+     * This constructor is for future use if needed.
+     */
+    protected Freezer() {
+    }
+    
+    /** 
+     * Holds a mapping of java.util and java.sql type names to the names 
+     * of their corresponding SCO types. 
+     */
+    static Map convertedClassNames;
+
+    /** Initialize convertedClassNames map. */
+    static {
+        convertedClassNames = new HashMap(12);
+        convertedClassNames.put("java.util.ArrayList", 
"org.apache.jdo.impl.sco.ArrayList"); // NOI18N
+        convertedClassNames.put("java.util.Date", 
"org.apache.jdo.impl.sco.Date"); // NOI18N
+        convertedClassNames.put("java.util.HashMap", 
"org.apache.jdo.impl.sco.HashMap"); // NOI18N
+        convertedClassNames.put("java.util.HashSet", 
"org.apache.jdo.impl.sco.HashSet"); // NOI18N
+        convertedClassNames.put("java.util.Hashtable", 
"org.apache.jdo.impl.sco.Hashtable"); // NOI18N
+        convertedClassNames.put("java.util.LinkedList", 
"org.apache.jdo.impl.sco.LinkedList"); // NOI18N
+        convertedClassNames.put("java.sql.Date", 
"org.apache.jdo.impl.sco.SqlDate"); // NOI18N
+        convertedClassNames.put("java.sql.Time", 
"org.apache.jdo.impl.sco.SqlTime"); // NOI18N
+        convertedClassNames.put("java.sql.Timestamp", 
"org.apache.jdo.impl.sco.SqlTimestamp"); // NOI18N
+        convertedClassNames.put("java.util.TreeMap", 
"org.apache.jdo.impl.sco.TreeMap"); // NOI18N
+        convertedClassNames.put("java.util.TreeSet", 
"org.apache.jdo.impl.sco.TreeSet"); // NOI18N
+        convertedClassNames.put("java.util.Vector", 
"org.apache.jdo.impl.sco.Vector"); // NOI18N
+    }
+
+    /**
+     * I18N message handler
+     */  
+    private final static I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.sco.Bundle"); // NOI18N
+
+    /** Provide a frozen array of elements from a Set. This method
+     * does not actually freeze the Set but simply calculates the
+     * frozen elements.
+     * @return the Object[] containing the frozen elements.
+     * @param size the number of elements in the collection.
+     * @param set the Set whose elements are to be ordered.
+     */    
+    static public Object[] freeze(Collection set, int size) {
+        Object[] result = new Object[size];
+        Iterator it;
+        if (set instanceof SCOCollection) {
+            it = ((SCOCollection)set).eitherIterator();
+        } else {
+            it = set.iterator();
+        }
+        TreeSet ts = new TreeSet(new AbsoluteOrdering());
+        while (it.hasNext()) {
+            ts.add(it.next());
+        }
+        return ts.toArray(result);
+    }
+    
+    /** Provide a frozen array of elements from the entrySet of a Map.
+     * This method
+     * does not actually freeze the Map but simply calculates the
+     * frozen elements.
+     * @return the Map.Entry[] of elements in the map.
+     * @param size the number of entries in the map.
+     * @param map the Map whose entrySet elements are to be calculated.
+     */    
+    static public Map.Entry[] freeze(Map map, int size) {
+        Map.Entry[] result = new Map.Entry[size];
+        if (size != 0) {
+            TreeMap tm = new TreeMap(new AbsoluteOrdering());
+            Iterator it;
+            if (map instanceof SCOMap) {
+                it = ((SCOMap)map).eitherIterator();
+            } else {
+                it = map.entrySet().iterator();
+            }
+            while (it.hasNext()) {
+                Map.Entry me = (Map.Entry)it.next();
+                tm.put(me.getKey(), me.getValue());
+            }
+            return (Map.Entry[])tm.entrySet().toArray(result);
+        } else {
+            return result;
+        }
+    }
+    
+    /** Provide a frozen iterator of elements from the entrySet of a Map.
+     * This method
+     * does not actually freeze the Map but simply calculates the
+     * frozen elements and returns an iterator over them.
+     * @return an iterator over Map.Entry[] of elements in the map.
+     * @param size the number of entries in the map.
+     * @param map the Map whose entrySet elements are to be calculated.
+     */    
+    static public Iterator frozenIterator(Map map, int size) {
+        TreeMap tm = new TreeMap(new AbsoluteOrdering());
+        if (size != 0) {
+            Iterator it;
+            if (map instanceof SCOMap) {
+                it = ((SCOMap)map).eitherIterator();
+            } else {
+                it = map.entrySet().iterator();
+            }
+            while (it.hasNext()) {
+                Map.Entry me = (Map.Entry)it.next();
+                tm.put(me.getKey(), me.getValue());
+            }
+        }
+        return tm.entrySet().iterator();
+    }
+    
+    /** Create a map whose elements are ordered according to an
+     * absolute ordering.
+     * @return the map with an absolute ordering Comparator.
+     */    
+    static public Map createAbsoluteOrderMap() {
+        return new TreeMap(new AbsoluteOrdering());
+    }
+    
+    /** Create an iterator over frozen elements or entries.
+     * @param frozen the array of frozen entries or elements.
+     * @return the iterator over the entries or elements.
+     */
+    static public Iterator createFrozenIterator(Object[] frozen) {
+        return new FrozenIterator(frozen);
+    }
+    
+    /** Thaw the frozen elements of a map. If the elements are frozen,
+     * retrieve them from the datastore and internally add them. Then return
+     * the frozen state since they're not frozen any more.
+     * @param map the Map to be thawed.
+     * @param owner the StateManager that owns this Map.
+     * @param frozenEntries the frozen entries to be thawed.
+     * @return the new contents of frozenEntries.
+     */
+    static public Map.Entry[] thaw(SCOMap map, StateManagerInternal owner,
+            Map.Entry[] frozenEntries) {
+        if (frozenEntries == null || frozenEntries.length == 0) {
+            return null;
+        }
+        int length = frozenEntries.length;
+        if (owner != null) {
+            // only fetch PC elements from the store
+            ArrayList persistenceCapables = new ArrayList();
+            for (int i = 0; i < length; ++i) {
+                Map.Entry mapEntry = frozenEntries[i];
+                Object key = mapEntry.getKey();
+                Object value = mapEntry.getValue();
+                if (key instanceof PersistenceCapable) {
+                    persistenceCapables.add(key);
+                }
+                if (value instanceof PersistenceCapable) {
+                    persistenceCapables.add(value);
+                }
+            }
+            try {
+                owner.getPersistenceManager().retrieveAll(persistenceCapables);
+            } catch (JDOUserException ex) {
+                // if objects don't exist, this exception is expected.
+                // this will be handled later when the user iterates the 
+                // collection if values are needed.
+            }
+        }
+        for (int i = 0; i < length; ++i) {
+            Map.Entry mapEntry = (Map.Entry)frozenEntries[i];
+            Object key = mapEntry.getKey();
+            Object value = mapEntry.getValue();
+            map.putInternal(key, value);
+        }
+        // reset the caller's frozenEntries.
+        return null;
+    }
+    
+    /** Thaw the frozen elements of a collection. If the elements are frozen,
+     * retrieve them from the datastore and internally add them. Then reset
+     * the frozen state since they're not frozen any more.
+     * @param sco the frozen collection to be thawed.
+     * @param owner the StateManager that owns this collection.
+     * @param frozenElements the elements to be thawed.
+     * @return the new contents of frozenElements.
+     */
+    static public Object[] thaw(SCOCollection sco, StateManagerInternal owner,
+            Object[] frozenElements) {
+        if (frozenElements == null || frozenElements.length == 0) {
+            return null;
+        }
+        int length = frozenElements.length;
+        if (owner != null) {
+            // only fetch PC elements from the store
+            ArrayList persistenceCapables = new ArrayList();
+            for (int i = 0; i < length; ++i) {
+                Object element = frozenElements[i];
+                if (element instanceof PersistenceCapable) {
+                    persistenceCapables.add(element);
+                }
+            }
+            try {
+                owner.getPersistenceManager().retrieveAll(persistenceCapables);
+            } catch (JDOUserException ex) {
+                // if objects don't exist, this exception is expected.
+                // this will be handled later when the user iterates the 
+                // collection if values are needed.
+            }
+        }
+        for (int i = 0; i < length; ++i) {
+            sco.addInternal(frozenElements[i]);
+        }
+        // reset the caller's frozenElements.
+        return null;
+    }
+    
+    /** This class is the Comparator to impose an absolute ordering
+     * on instances of PersistenceCapable, wrapper, and mutable sco types.
+     */    
+    static class AbsoluteOrdering implements Comparator {
+        /** Implement an absolute ordering comparison for persistence
+         * capable, wrapper, and mutable sco types.
+         * @return -1, 0, or 1 if the first parameter is less that, equal to, 
or greater than the second parameter.
+         * @param o1 the first parameter.
+         * @param o2 the second parameter. */        
+        public int compare(Object o1, Object o2) {
+            String className1 = convertClassName(o1.getClass().getName());
+            String className2 = convertClassName(o2.getClass().getName());
+            if (className1!=className2) {
+                // order by class names
+                return className1.compareTo(className2);
+            } else {
+                // class names are the same (modulo sco Date types)
+                if (o1 instanceof PersistenceCapable) {
+                    // compare oids
+                    Object oid1 = JDOHelper.getObjectId(o1);
+                    Object oid2 = JDOHelper.getObjectId(o2);
+                    if (oid1 instanceof Comparable) {
+                        if (oid1 != null) {
+                            return ((Comparable)oid1).compareTo(oid2);
+                        } else if (o1 instanceof Comparable) {
+                            return ((Comparable)o1).compareTo(o2);
+                        } else {
+                            return o1.hashCode() - o2.hashCode();
+                        }
+                    } else {
+                        throw new 
JDOFatalInternalException(msg.msg("EXC_OidNotComparable", // NOI18N
+                            oid1.getClass().getName()));
+                    }
+                } else if (o1 instanceof Comparable) {
+                    // immutables (String, Integer, etc.) and Date use this 
code path
+                    return ((Comparable)o1).compareTo(o2);
+                } else {
+                    // give up! compare instance.toString().
+                    // this is used by java.util.Locale that doesn't implement 
Comparable.
+                    return (o1.toString().compareTo(o2.toString()));
+                }
+            }
+        }
+    }
+    
+    /** Convert the class name to make non sco types compare to
+     * their corresponding sco types.
+     * @param className the actual class name.
+     * @return the corresponding sco class name.
+     */    
+    static String convertClassName(String className) {
+        String converted = (String)convertedClassNames.get(className);
+        if (converted == null)
+            converted = className;
+        return converted;
+    }
+    
+    /** This class iterates over an array.
+     */    
+    protected static class FrozenIterator implements Iterator {
+        /** The array over which to iterate.
+         */        
+        Object[] frozen;
+        int idx = 0;
+        int length = 0;
+        FrozenIterator(Object[] frozen) {
+            this.frozen = frozen;
+            length = frozen.length;
+        }
+        /** Return the next entry of the iteration.
+         * @return the next entry of the iteration.
+         */        
+        public Object next() {return frozen[idx++];}
+        /** Return true if the iteration is not complete.
+         * @return true if the iteration is not complete.
+         */        
+        public boolean hasNext() {return idx < length;}
+        /** This operation is not supported.
+         */        
+        public void remove() {throw new JDOFatalInternalException(
+            msg.msg("EXC_RemoveNotSupported"));} // NOI18N
+    }
+
+    /** For debugging, print the contents of a frozen entrySet.
+     * @param p where to write the output.
+     * @param s an identifying string.
+     * @param entries the Map.Entry[] to print.
+     */    
+    static public void printEntries(PrintStream p, String s, Map.Entry[] 
entries) {
+        p.println(s);
+        for (int i = 0; i < entries.length; ++i) {
+            Map.Entry entry = entries[i];
+            Object key = entry.getKey();
+            Object value = entry.getValue();
+            Object keyoid = JDOHelper.getObjectId(key);
+            Object valueoid = JDOHelper.getObjectId(value);
+            p.println("Key: " + key.toString() + " OID: " + 
keyoid.toString()); // NOI18N
+            p.println("Value: " + value.toString() + " OID: " + 
valueoid.toString()); // NOI18N
+        }
+    }
+    
+    /** For debugging, print the contents of a frozen collection.
+     * @param p where to write the output.
+     * @param s an identifying string.
+     * @param elements the Object[] to print.
+     */    
+    static public void printElements(PrintStream p, String s, Object[] 
elements) {
+        p.println(s);
+        for (int i = 0; i < elements.length; ++i) {
+            Object element = elements[i];
+            Object oid = JDOHelper.getObjectId(element);
+            p.println("Element: " + oid); // NOI18N
+        }
+    }
+    
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashMap.java
URL: 
http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashMap.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashMap.java 
(added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashMap.java Fri 
Mar 18 17:02:29 2005
@@ -0,0 +1,607 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* 
+ * sco.HashMap.java
+ */
+ 
+package org.apache.jdo.impl.sco;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jdo.JDOFatalInternalException;
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOUserException;
+
+import org.apache.jdo.sco.SCO;
+import org.apache.jdo.sco.SCOMap;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+ * A mutable 2nd class object that represents HashMap.
+ * @author Marina Vatkina
+ * @version 1.0.1
+ * @see java.util.HashMap
+ */
+public class HashMap extends java.util.HashMap implements SCOMap {
+
+    private transient StateManagerInternal owner;
+
+    private transient int fieldNumber = -1;
+
+    private transient   Class keyType;
+
+    private transient   Class valueType;
+
+    private transient boolean allowNulls;
+
+    private transient java.util.ArrayList addedKeys = new 
java.util.ArrayList();
+    private transient java.util.ArrayList addedValues = new 
java.util.ArrayList();
+
+    private transient java.util.ArrayList removedKeys = new 
java.util.ArrayList();
+    private transient java.util.ArrayList removedValues = new 
java.util.ArrayList();
+
+    private transient Map.Entry[] frozenEntries = null;
+    
+    /** 
+     * I18N message handler 
+     */ 
+    private final static I18NHelper msg = I18NHelper.getInstance( 
+        "org.apache.jdo.impl.sco.Bundle");  // NOI18N
+
+    private final static String _HashMap = "HashMap"; // NOI18N
+
+    /**   
+     * Creates a new empty <code>HashMap</code> object.
+     *    
+     * @param keyType the type of the keys allowed.
+     * @param valueType the type of the values allowed.
+     * @param allowNulls true if nulls are allowed.
+     * @see java.util.HashMap
+     */  
+    public HashMap(Class keyType, Class valueType, boolean allowNulls) {
+        super(); 
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.allowNulls = allowNulls;
+    } 
+
+    /**   
+     * Creates a new empty <code>HashMap</code> object that has 
+     * the specified initial capacity.
+     *    
+     * @param keyType the type of the keys allowed.
+     * @param valueType the type of the values allowed.
+     * @param allowNulls true if nulls are allowed
+     * @param      initialCapacity   the initial capacity of the hash map. 
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero.
+     * @see java.util.HashMap
+     */  
+    public HashMap(Class keyType, Class valueType, boolean allowNulls, 
+        int initialCapacity) {
+
+        super(initialCapacity); 
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.allowNulls = allowNulls;
+    } 
+
+    /**   
+     * Creates a new empty <code>HashMap</code> object that has 
+     * the specified initial capacity..
+     *    
+     * @param keyType the type of the keys allowed.
+     * @param valueType the type of the values allowed.
+     * @param allowNulls true if nulls are allowed
+     * @param      initialCapacity   the initial capacity of the hash map. 
+     * @param      loadFactor        the load factor of the hash map.
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero.
+     * @see java.util.HashMap
+     */  
+    public HashMap(Class keyType, Class valueType, boolean allowNulls, 
+        int initialCapacity, float loadFactor) {
+
+        super(initialCapacity, loadFactor); 
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.allowNulls = allowNulls;
+    } 
+
+    // -------------------------Public Methods------------------
+
+    /**
+     * 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 HashMap previously associated
+     *         <tt>null</tt> with the specified key.
+     * @see java.util.HashMap
+     */
+    public Object put(Object key, Object value) {
+        SCOHelper.debug(_HashMap, "put"); // NOI18N
+
+        // Check both the key and the value:
+        Throwable[] err = new Throwable[2];
+        int l = 0;
+
+        try {
+            SCOHelper.assertNullKeysAllowed(key, allowNulls);
+            SCOHelper.assertKeyType(key, keyType);
+        } catch (Throwable ex) {
+            err[l++] = ex;
+        }
+        try {
+            SCOHelper.assertNullValuesAllowed(value, allowNulls);
+            SCOHelper.assertValueType(value, valueType);
+        } catch (Throwable ex) {
+            err[l++] = ex;
+        }
+        SCOHelper.validateResult(l, err);
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        Object o = process(key, value);
+
+        // Apply updates
+        this.trackUpdates(true);
+
+        return o;
+    }  
+
+    /**
+    * 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 t Mappings to be stored in this map.
+     * @see java.util.HashMap
+     */  
+    public void putAll(Map t) {
+        SCOHelper.debug(_HashMap, "putAll"); // NOI18N
+
+        // iterate the collection and make a list of wrong elements.
+        Throwable[] err = new Throwable[2*t.size()];
+        int l = 0;
+
+        Iterator i = t.entrySet().iterator();
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry) i.next();
+            Object k = e.getKey();
+            Object v = e.getValue();
+
+            // Check both the key and the value:
+            try {
+                SCOHelper.assertNullKeysAllowed(k, allowNulls);
+                SCOHelper.assertKeyType(k, keyType);
+            } catch (Throwable ex) {
+                err[l++] = ex;
+            }
+            try {
+                SCOHelper.assertNullValuesAllowed(v, allowNulls);
+                SCOHelper.assertValueType(v, valueType);
+            } catch (Throwable ex) {
+                err[l++] = ex;
+            }
+        }
+        SCOHelper.validateResult(l, err);
+
+        boolean modified = false;
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        for (i = t.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next(); 
+            process(e.getKey(), e.getValue());
+        }
+
+        // Apply updates
+        this.trackUpdates(true);
+    } 
+
+     /**
+     * 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.
+     * @see java.util.HashMap
+     */  
+    public Object remove(Object key) {
+        SCOHelper.debug(_HashMap, "remove"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        boolean removed = false;
+
+        // Nothing is added to the removed collections if the key has not
+        // been in the map before:
+        if (super.containsKey(key)) {
+            if (addedKeys.remove(key) == false) {
+                removedKeys.add(key);
+            }
+            removed = true;
+        }
+
+        Object o = super.remove(key);
+
+        // Remove old value if there was one:
+        if (removed && addedValues.remove(o) == false) {
+            removedValues.add(o);
+        }
+
+        // Apply updates
+        this.trackUpdates(removed);
+
+        return o;
+    }    
+
+
+    /**
+     * Removes all of the elements from this map.
+     * @see java.util.HashMap
+     */  
+    public void clear() {
+        SCOHelper.debug(_HashMap, "clear"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        for (Iterator i = super.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next();
+            removedKeys.add(e.getKey());
+            removedValues.add(e.getValue());
+        }
+
+        super.clear();
+        addedKeys.clear();
+        addedValues.clear();
+
+        // Apply updates
+        this.trackUpdates(true);
+
+    }     
+ 
+    /**
+     * Creates and returns a copy of this object.
+     *   
+     * <P>Mutable Second Class Objects are required to provide a public
+     * clone method in order to allow for copying PersistenceCapable
+     * objects. In contrast to Object.clone(), this method must not throw a
+     * CloneNotSupportedException.
+     */  
+    public Object clone() {
+        SCOHelper.debug(_HashMap, "clone"); // NOI18N
+
+        Object obj = super.clone();
+        if (obj instanceof SCO) {
+            ((SCO)obj).unsetOwner(owner, fieldNumber);
+        }
+        return obj;
+    }
+
+    /** These methods need to thaw the map before performing the operation.
+     */
+    public boolean containsKey(Object key) {
+        thaw();
+        return super.containsKey(key);
+    }
+    public boolean containsValue(Object value) {
+        thaw();
+        return super.containsValue(value);
+    }
+    public Set entrySet() {
+        thaw();
+        return super.entrySet();
+    }
+    public boolean equals(Object o) {
+        thaw();
+        return super.equals(o);
+    }
+    public Object get(Object key) {
+        thaw();
+        return super.get(key);
+    }
+    public int hashCode() {
+        thaw();
+        return super.hashCode();
+    }
+    public boolean isEmpty() {
+        thaw();
+        return super.isEmpty();
+    }
+    public Set keySet() {
+        thaw();
+        return super.keySet();
+    }
+    public int size() {
+        if (isFrozen()) {
+            return frozenEntries.length;
+        } else {
+            return super.size();
+        }
+    }
+    public Collection values() {
+        thaw();
+        return super.values();
+    }
+    public String toString() {
+        thaw();
+        return super.toString();
+    }
+    
+    /**
+     * @see SCOMap#reset()
+     */  
+    public void reset() {
+        addedKeys.clear();
+        addedValues.clear();
+        removedKeys.clear();
+        removedValues.clear();
+    }
+
+    /**
+     * @see SCOMap#putInternal(Object key, Object value)
+     */  
+    public void putInternal(Object key, Object value) {
+        super.put(key, value);
+    }
+
+
+    /**
+     * @see SCOMap#putAllInternal(Map t)
+     */  
+    public void putAllInternal(Map t) {
+        for (Iterator i = t.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next();
+            super.put(e.getKey(), e.getValue());
+        }
+    }    
+
+    /** 
+     * @see SCOMap#getAddedKeys()
+     */  
+    public Collection getAddedKeys() { 
+        return (Collection)addedKeys; 
+    }     
+ 
+    /** 
+     * @see SCOMap#getAddedValues()
+     */  
+    public Collection getAddedValues() { 
+        return (Collection)addedValues; 
+    }     
+ 
+    /**  
+     * @see SCOMap#getRemovedKeys()
+     */  
+    public Collection getRemovedKeys()  {  
+        return (Collection)removedKeys;  
+    }      
+
+    /**  
+     * @see SCOMap#getRemovedValues()
+     */  
+    public Collection getRemovedValues()  {  
+        return (Collection)removedValues;  
+    }      
+
+    /** 
+     * @see SCOMap#clearInternal()
+     */   
+    public void clearInternal() {    
+        super.clear(); 
+        this.reset(); 
+    }  
+
+    /**
+     * @see SCOMap#removeInternal(Object key)
+     */  
+    public void removeInternal(Object key) {
+        super.remove(key);
+    }
+
+    /**
+     * @see SCO#unsetOwner(Object owner, int fieldNumber)
+     */
+    public void unsetOwner(Object owner, int fieldNumber) { 
+        // Unset only if owner and fieldNumber match.
+        if (this.owner == owner && this.fieldNumber == fieldNumber) {
+            this.owner = null; 
+            this.fieldNumber = -1;
+        }
+    }
+
+    /**
+     * @see SCO#setOwner (Object owner, int fieldNumber)
+     */
+    public void setOwner (Object owner, int fieldNumber) {
+        // Set only if it was not set before.
+        if (this.owner == null && owner instanceof StateManagerInternal) {
+            this.owner = (StateManagerInternal)owner;    
+            this.fieldNumber = fieldNumber;
+        }
+    }
+
+    /** 
+     * @see SCO#getOwner()
+     */   
+    public Object getOwner() {   
+        return SCOHelper.getOwner(owner);
+    } 
+ 
+    /**  
+     * @see SCO#getFieldName()
+     */   
+    public String getFieldName() {
+        return SCOHelper.getFieldName(owner, fieldNumber);   
+    }
+
+    /**
+     * Notify StateManager to mark field as dirty.
+     */
+    private void makeDirty() {
+        if (owner != null) {
+            owner.makeDirty(fieldNumber); //
+        }
+     }   
+    /**
+     * Notify StateManager to process the changes.
+     */  
+    private void trackUpdates(boolean modified) {
+        if (modified && owner != null) {
+               owner.trackUpdates(fieldNumber, this);
+        }
+    }
+
+    /**
+     * @see SCOMap#getKeyType() {
+     */  
+    public Class getKeyType() {
+        return keyType;
+    }
+
+    /**
+     * @see SCOMap#getValueType() {
+     */  
+    public Class getValueType() {
+        return valueType;
+    }
+
+    /**
+     * @see SCOMap#allowNulls() {
+     */  
+    public boolean allowNulls() {
+        return allowNulls;
+    }
+
+    /**
+     * Processes single put operation in this map.
+     * @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. 
+     */
+    private Object process(Object key, Object value) {
+        thaw();
+        // Key is added to the addedKeys collection only if it has not
+        // been in the map before:
+        if (!super.containsKey(key)) {
+            if (removedKeys.remove(key) == false) {
+                addedKeys.add(key);
+            }
+        }
+
+        Object o = super.put(key, value);
+
+        // Remove old value:
+        if (addedValues.remove(o) == false) {
+            removedValues.add(o);
+        }
+
+        // Add new value:
+        if (removedValues.remove(value) == false) {
+            addedValues.add(value);
+        }
+
+        return o;
+    }
+    
+    /** Returns the frozen state of this Map.
+     * @since 1.0.1
+     * @return the frozen state.
+     */    
+    private boolean isFrozen() {
+        return frozenEntries != null;
+    }
+    
+    /** Returns the frozen contents of this Map as a Map.Entry[].
+     * @return the frozen entries.
+     * @since 1.0.1
+     */
+    private Map.Entry[] getFrozen() {
+        if (!isFrozen()) {
+            frozenEntries = Freezer.freeze(this, super.size());
+        }
+        return frozenEntries;
+    }
+    
+    /** Set the contents of this Map from the frozen entries.
+     * @since 1.0.1
+     * @param entries the frozen entries
+     */
+    public void setFrozen(Map.Entry[] entries) {
+        frozenEntries = entries;
+    }
+    
+    /** Get an iterator regardless of whether the map is frozen.
+     * If frozen, get a frozen iterator.
+     * If thawed, get a regular iterator.
+     * @since 1.0.1
+     * @return the iterator.
+     */
+    public Iterator eitherIterator() {
+        if (isFrozen()) {
+            return frozenIterator();
+        } else {
+            return super.entrySet().iterator();
+        }
+    }
+    
+    /** Get an iterator over the frozen elements of this map. This allows
+     * iteration of the elements without thawing them, as is needed for
+     * transcription.
+     * @since 1.0.1
+     * @return the iterator.
+     */
+    public Iterator frozenIterator() {
+        return Freezer.createFrozenIterator(getFrozen());
+    }
+    
+    /**
+     * Thaw the frozen elements of this map. If the elements are frozen,
+     * retrieve them from the datastore and internally add them. Then reset
+     * the frozen state since they're not frozen any more.
+     * @since 1.0.1
+     */
+    private void thaw() {
+        if (isFrozen()) {
+            frozenEntries = Freezer.thaw(this, owner, frozenEntries);
+        }
+    }
+    
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashSet.java
URL: 
http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashSet.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashSet.java 
(added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/HashSet.java Fri 
Mar 18 17:02:29 2005
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* 
+ * sco.HashSet.java
+ */
+ 
+package org.apache.jdo.impl.sco;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.jdo.sco.SCO;
+import org.apache.jdo.sco.SCOCollection;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+
+
+/**
+ * A mutable 2nd class object that represents HashSet.
+ * @author Marina Vatkina
+ * @version 1.0.1
+ * @see java.util.HashSet
+ */
+public class HashSet extends java.util.HashSet implements SCOCollection {
+
+    private transient StateManagerInternal owner;
+
+    private transient int fieldNumber = -1;
+
+    private transient   Class elementType;
+
+    private transient boolean allowNulls;
+
+    private transient java.util.HashSet added = new java.util.HashSet();
+
+    private transient java.util.HashSet removed = new java.util.HashSet();
+
+    private transient Object[] frozenElements = null;
+    
+    /** 
+     * I18N message handler 
+     */ 
+    private final static I18NHelper msg = I18NHelper.getInstance( 
+        "org.apache.jdo.impl.sco.Bundle");  // NOI18N
+
+    private final static String _HashSet = "HashSet"; // NOI18N
+
+    /**   
+     * Creates a new empty <code>HashSet</code> object.
+     *    
+     * @param elementType the element types allowed
+     * @param allowNulls true if nulls are allowed
+     * @see java.util.HashSet
+     */  
+    public HashSet(Class elementType, boolean allowNulls) {
+        super(); 
+        this.elementType = elementType;
+        this.allowNulls = allowNulls;
+    } 
+
+    /**   
+     * Creates a new empty <code>HashSet</code> object that has 
+     * the specified initial capacity.
+     *    
+     * @param elementType the element types allowed
+     * @param allowNulls true if nulls are allowed
+     * @param      initialCapacity   the initial capacity of the hash map. 
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero.
+     * @see java.util.HashSet
+     */  
+    public HashSet(Class elementType, boolean allowNulls, int initialCapacity) 
{
+        super(initialCapacity); 
+        this.elementType = elementType;
+        this.allowNulls = allowNulls;
+    } 
+
+    /**   
+     * Creates a new empty <code>HashSet</code> object that has 
+     * the specified initial capacity..
+     *    
+     * @param elementType the element types allowed
+     * @param allowNulls true if nulls are allowed
+     * @param      initialCapacity   the initial capacity of the hash map. 
+     * @param      loadFactor        the load factor of the hash map.
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero.
+     * @see java.util.HashSet
+     */  
+    public HashSet(Class elementType, boolean allowNulls, int initialCapacity, 
+        float loadFactor) {
+        super(initialCapacity, loadFactor); 
+        this.elementType = elementType;
+        this.allowNulls = allowNulls;
+    } 
+
+    // -------------------------Public Methods------------------
+
+    /**
+     * Adds the specified element to this set if it is not already
+     * present.
+     *   
+     * @param o element to be added to this set.
+     * @return <tt>true</tt> if the set did not already contain the specified
+     * element.
+     * @see java.util.HashSet
+     */
+    public boolean add(Object o) {
+        SCOHelper.debug(_HashSet, "add"); // NOI18N
+
+        SCOHelper.assertNullsAllowed(o, allowNulls);
+        SCOHelper.assertElementType(o, elementType);
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        
+        boolean modified = super.add(o); 
+        if (modified) {
+            if (removed.remove(o) == false) {
+                added.add(o);
+            }
+        }
+
+        // Apply updates
+        this.trackUpdates(modified);
+
+        return modified;
+    }  
+
+    /**
+     * Adds all of the elements in the specified collection to this collection
+     *   
+     * @param c collection whose elements are to be added to this collection.
+     * @return <tt>true</tt> if this collection changed as a result of the
+     * call.
+     * @throws UnsupportedOperationException if the <tt>addAll</tt> method is
+     *            not supported by this collection.
+     *   
+     * @see java.util.AbstractCollection
+     * @see java.util.HashSet
+     */  
+    public boolean addAll(Collection c) {
+        SCOHelper.debug(_HashSet, "addAll"); // NOI18N
+
+        // iterate the collection and make a list of wrong elements.
+        Throwable[] err = new Throwable[c.size()];
+        int l = 0;
+
+        Iterator i = c.iterator();
+        while (i.hasNext()) {
+            Object o = i.next();
+            try {
+                SCOHelper.assertNullsAllowed(o, allowNulls);
+                SCOHelper.assertElementType(o, elementType);
+            } catch (Throwable e) {
+                err[l++] = e;
+            }
+        }
+        SCOHelper.validateResult(l, err);
+
+        boolean modified = false;
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        
+        for (Iterator iter = c.iterator(); iter.hasNext();) {
+            Object o = iter.next();
+            if (!super.contains(o)) {
+                if (removed.remove(o) == false) {
+                    added.add(o);
+                }
+                super.add(o);
+                modified = true;
+            }
+        }
+
+        // Apply updates
+        this.trackUpdates(modified);
+
+        return modified;
+    } 
+
+    /**
+     * Removes the given element from this set if it is present.
+     *   
+     * @param o object to be removed from this set, if present.
+     * @return <tt>true</tt> if the set contained the specified element.
+     * @see java.util.HashSet
+     */  
+    public boolean remove(Object o) {
+        SCOHelper.debug(_HashSet, "remove"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        
+        boolean modified = super.remove(o);
+        if (modified) { 
+            if (added.remove(o) == false) { 
+                removed.add(o);
+            } 
+        } 
+
+        // Apply updates
+        this.trackUpdates(modified);
+
+        return modified;
+    }    
+
+
+    /**
+     * Removes from this collection all of its elements that are contained in
+     * the specified collection (optional operation). <p>
+     * Processes each element remove internally not to have call backs
+     * into #remove(Object). 
+     *   
+     * @param c elements to be removed from this collection.
+     * @return <tt>true</tt> if this collection changed as a result of the
+     * call.
+     *   
+     * @throws    UnsupportedOperationException removeAll is not supported
+     *            by this collection.
+     *   
+     * @see java.util.HashSet
+     * @see java.util.AbstractCollection
+     */  
+    public boolean removeAll(Collection c) {
+        SCOHelper.debug(_HashSet, "removeAll"); // NOI18N
+
+        boolean modified = false;
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        
+        for (Iterator iter = c.iterator(); iter.hasNext();) {
+            Object o = iter.next();
+            if (super.contains(o)) {
+                removeInternal(o);
+                modified = true;
+                if (added.remove(o) == false) {
+                    removed.add(o);
+                }
+            }
+        }
+
+        // Apply updates
+        this.trackUpdates(modified);
+
+        return modified;
+    }
+
+    /**
+     * Retains only the elements in this collection that are contained in the
+     * specified collection (optional operation). 
+     *
+     * @return <tt>true</tt> if this collection changed as a result of the
+     *         call.
+     *
+     * @throws UnsupportedOperationException if the <tt>retainAll</tt> method
+     *            is not supported by this collection.
+     *
+     * @see java.util.HashSet
+     * @see java.util.AbstractCollection
+     */  
+    public boolean retainAll(Collection c) {
+        SCOHelper.debug(_HashSet, "retainAll"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+        
+        thaw();
+
+        for (Iterator iter = super.iterator(); iter.hasNext();) {
+            Object o = iter.next();
+            if (!c.contains(o)) { 
+                if (added.remove(o) == false) { 
+                    removed.add(o); 
+                } 
+            } 
+        }
+
+        boolean modified = super.retainAll(c);
+
+        // Apply updates
+        this.trackUpdates(modified);
+
+        return modified;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * @see java.util.HashSet
+     */  
+    public void clear() {
+        SCOHelper.debug(_HashSet, "clear"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        removed.clear();
+        added.clear();
+
+        for (Iterator iter = super.iterator(); iter.hasNext();) {
+            removed.add(iter.next());
+        }
+
+        super.clear();
+
+        // Apply updates
+        this.trackUpdates(true);
+
+    }     
+ 
+    /**
+     * Creates and returns a copy of this object.
+     *   
+     * <P>Mutable Second Class Objects are required to provide a public
+     * clone method in order to allow for copying PersistenceCapable
+     * objects. In contrast to Object.clone(), this method must not throw a
+     * CloneNotSupportedException.
+     */  
+    public Object clone() {
+        SCOHelper.debug(_HashSet, "clone"); // NOI18N
+
+        Object obj = super.clone();
+        if (obj instanceof SCO) {
+            ((SCO)obj).unsetOwner(owner, fieldNumber);
+        }
+        return obj;
+    }
+
+    /**
+     * @see SCOCollection#reset()
+     */  
+    public void reset() {
+        added.clear();
+        removed.clear();
+        frozenElements = null;
+    }
+
+    /**
+     * @see SCOCollection#addInternal(Object o)
+     */  
+    public void addInternal(Object o) {
+        super.add(o);
+    }
+
+
+    /**
+     * @see SCOCollection#addAllInternal(Collection c)
+     */  
+    public void addAllInternal(Collection c) {
+        for (Iterator iter = c.iterator(); iter.hasNext();) {
+            super.add(iter.next());
+        }
+    }    
+
+    /** 
+     * @see SCOCollection#getAdded()
+     */  
+    public Collection getAdded() { 
+        return (Collection)added; 
+    }     
+ 
+    /**  
+     * @see SCOCollection#getRemoved()
+     */  
+    public Collection getRemoved()  {  
+        return (Collection)removed;  
+    }      
+
+
+    /** 
+     * @see SCOCollection#clearInternal()
+     */   
+    public void clearInternal() {    
+        super.clear(); 
+        this.reset(); 
+    }  
+
+    /**
+     * @see SCOCollection#removeInternal(Object o)
+     */  
+    public void removeInternal(Object o) {
+        super.remove(o);
+    }
+
+    /**
+     * @see SCO#unsetOwner(Object owner, int fieldNumber)
+     */
+    public void unsetOwner(Object owner, int fieldNumber) { 
+        // Unset only if owner and fieldNumber match.
+        if (this.owner == owner && this.fieldNumber == fieldNumber) {
+            this.owner = null; 
+            this.fieldNumber = -1;
+        }
+    }
+
+    /**
+     * @see SCO#setOwner (Object owner, int fieldNumber)
+     */
+    public void setOwner (Object owner, int fieldNumber) {
+        // Set only if it was not set before.
+        if (this.owner == null && owner instanceof StateManagerInternal) {
+            this.owner = (StateManagerInternal)owner;    
+            this.fieldNumber = fieldNumber;
+        }
+    }
+
+    /** 
+     * @see SCO#getOwner()
+     */   
+    public Object getOwner() {   
+        return SCOHelper.getOwner(owner);
+    } 
+ 
+    /**  
+     * @see SCO#getFieldName()
+     */   
+    public String getFieldName() {
+        return SCOHelper.getFieldName(owner, fieldNumber);   
+    }
+
+    /**
+     * Notify StateManager to mark field as dirty.
+     */
+    private void makeDirty() {
+        if (owner != null) {
+            owner.makeDirty(fieldNumber); //
+        }
+     }   
+    /**
+     * Notify StateManager to process the changes.
+     */  
+    private void trackUpdates(boolean modified) {
+        if (modified && owner != null) {
+               owner.trackUpdates(fieldNumber, this);
+        }
+    }
+
+    /**
+     * @see SCOCollection#getElementType() {
+     */  
+    public Class getElementType() {
+        return elementType;
+    }
+
+    /**
+     * @see SCOCollection#allowNulls() {
+     */  
+    public boolean allowNulls() {
+        return allowNulls;
+    }
+
+    public boolean contains(Object o) {
+        thaw();
+        return super.contains(o);
+    }
+    
+    public boolean containsAll(Collection c) {
+        thaw();
+        return super.containsAll(c);
+    }
+    
+    public boolean isEmpty() {
+        thaw();
+        return super.isEmpty();
+    }
+    
+    public Iterator iterator() {
+        thaw();
+        return super.iterator();
+    }
+    
+    public int size() {
+        thaw();
+        return super.size();
+    }
+    
+    public boolean equals(Object o) {
+        thaw();
+        return super.equals(o);
+    }
+    
+    public int hashCode() {
+        thaw();
+        return super.hashCode();
+    }
+    
+    public String toString() {
+        thaw();
+        return super.toString();
+    }
+    
+    public Object[] toArray() {
+        thaw();
+        return super.toArray();
+    }
+    
+    public Object[] toArray(Object[] a) {
+        thaw();
+        return super.toArray(a);
+    }
+    
+    /** Returns the frozen state of this set.
+     * @since 1.0.1
+     */
+    private boolean isFrozen() {
+        return frozenElements != null;
+    }
+    
+    /** Returns the frozen contents of this Collection, if this Collection
+     * is implicitly user-orderable.  If the collection is not frozen already,
+     * freeze it first.
+     * @since 1.0.1
+     * @return the frozen elements of this collection.
+     */
+    private Object[] getFrozen() {
+        if (!isFrozen()) {
+            frozenElements = Freezer.freeze(this, super.size());
+        }
+        return frozenElements;
+    }
+    
+    /** Set the contents of this Collection from the frozen elements, if this 
Collection
+     * is implicitly user-orderable.
+     * @since 1.0.1
+     * @param elements the frozen elements of this set.
+     */
+    public void setFrozen(Object[] elements) {
+        frozenElements = elements;
+    }
+    
+    /**
+     * Thaw the frozen elements of this collection. If the elements are frozen,
+     * retrieve them from the datastore and internally add them. Then reset
+     * the frozen state since they're not frozen any more.
+     * @since 1.0.1
+     */
+    private void thaw() {
+        if (isFrozen()) {
+            frozenElements = Freezer.thaw(this, owner, frozenElements);
+        }
+    }
+    
+    /** Create a new iterator over the frozen elements without thawing.
+     * @since 1.0.1
+     * @return the frozen iterator.
+     */    
+    public Iterator frozenIterator() {
+        return Freezer.createFrozenIterator(getFrozen());
+    }
+    
+    /** Create an iterator regardless whether the collection is frozen. 
+     * If frozen, don't thaw the collection, but get a frozen iterator. 
+     * If thawed, get a regular iterator.
+     * @since 1.0.1
+     * @return the iterator.
+     */
+    public Iterator eitherIterator() {
+        if (isFrozen()) {
+            return frozenIterator();
+        } else {
+            return super.iterator();
+        }
+    }
+    
+}

Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Hashtable.java
URL: 
http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Hashtable.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Hashtable.java 
(added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/sco/Hashtable.java 
Fri Mar 18 17:02:29 2005
@@ -0,0 +1,614 @@
+/*
+ * Copyright 2005 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.
+ */
+
+/* 
+ * sco.Hashtable.java
+ */
+ 
+package org.apache.jdo.impl.sco;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Enumeration;
+
+import org.apache.jdo.sco.SCO;
+import org.apache.jdo.sco.SCOMap;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+ * A mutable 2nd class object that represents Hashtable.
+ * @author Marina Vatkina
+ * @version 1.0.1
+ * @see java.util.Hashtable
+ */
+public class Hashtable extends java.util.Hashtable implements SCOMap {
+
+    private transient StateManagerInternal owner;
+
+    private transient int fieldNumber = -1;
+
+    private transient   Class keyType;
+
+    private transient   Class valueType;
+
+    private transient boolean allowNulls;
+
+    private transient java.util.ArrayList addedKeys = new 
java.util.ArrayList();
+    private transient java.util.ArrayList addedValues = new 
java.util.ArrayList();
+
+    private transient java.util.ArrayList removedKeys = new 
java.util.ArrayList();
+    private transient java.util.ArrayList removedValues = new 
java.util.ArrayList();
+
+    private transient Map.Entry[] frozenEntries = null;
+    /** 
+     * I18N message handler 
+     */ 
+    private final static I18NHelper msg = I18NHelper.getInstance( 
+        "org.apache.jdo.impl.sco.Bundle");  // NOI18N
+
+    private final static String _Hashtable = "Hashtable"; // NOI18N
+
+    /**   
+     * Creates a new empty <code>Hashtable</code> object.
+     *    
+     * @param keyType the type of the keys allowed.
+     * @param valueType the type of the values allowed.
+     * @param allowNulls true if nulls are allowed.
+     * @see java.util.Hashtable
+     */  
+    public Hashtable(Class keyType, Class valueType, boolean allowNulls) {
+        super(); 
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.allowNulls = allowNulls;
+    } 
+
+    /**   
+     * Creates a new empty <code>Hashtable</code> object that has 
+     * the specified initial capacity.
+     *    
+     * @param keyType the type of the keys allowed.
+     * @param valueType the type of the values allowed.
+     * @param allowNulls true if nulls are allowed
+     * @param      initialCapacity   the initial capacity of the hash map. 
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero.
+     * @see java.util.Hashtable
+     */  
+    public Hashtable(Class keyType, Class valueType, boolean allowNulls, 
+        int initialCapacity) {
+
+        super(initialCapacity); 
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.allowNulls = allowNulls;
+    } 
+
+    /**   
+     * Creates a new empty <code>Hashtable</code> object that has 
+     * the specified initial capacity..
+     *    
+     * @param keyType the type of the keys allowed.
+     * @param valueType the type of the values allowed.
+     * @param allowNulls true if nulls are allowed
+     * @param      initialCapacity   the initial capacity of the hash map. 
+     * @param      loadFactor        the load factor of the hash map.
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero.
+     * @see java.util.Hashtable
+     */  
+    public Hashtable(Class keyType, Class valueType, boolean allowNulls, 
+        int initialCapacity, float loadFactor) {
+
+        super(initialCapacity, loadFactor); 
+        this.keyType = keyType;
+        this.valueType = valueType;
+        this.allowNulls = allowNulls;
+    } 
+
+    // -------------------------Public Methods------------------
+
+    /**
+     * 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 Hashtable previously associated
+     *         <tt>null</tt> with the specified key.
+     * @see java.util.Hashtable
+     */
+    public Object put(Object key, Object value) {
+        SCOHelper.debug(_Hashtable, "put"); // NOI18N
+
+        // Check both the key and the value:
+        Throwable[] err = new Throwable[2];
+        int l = 0;
+
+        try {
+            SCOHelper.assertNullKeysAllowed(key, allowNulls);
+            SCOHelper.assertKeyType(key, keyType);
+        } catch (Throwable ex) {
+            err[l++] = ex;
+        }
+        try {
+            SCOHelper.assertNullValuesAllowed(value, allowNulls);
+            SCOHelper.assertValueType(value, valueType);
+        } catch (Throwable ex) {
+            err[l++] = ex;
+        }
+
+        SCOHelper.validateResult(l, err);
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        Object o = process(key, value);
+
+        // Apply updates
+        this.trackUpdates(true);
+
+        return o;
+    }  
+
+    /**
+    * 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 t Mappings to be stored in this map.
+     * @see java.util.HashSet
+     */  
+    public void putAll(Map t) {
+        SCOHelper.debug(_Hashtable, "putAll"); // NOI18N
+
+        // iterate the collection and make a list of wrong elements.
+        Throwable[] err = new Throwable[2*t.size()];
+        int l = 0;
+
+        Iterator i = t.entrySet().iterator();
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry) i.next();
+            Object k = e.getKey();
+            Object v = e.getValue();
+
+            // Check both the key and the value:
+            try {
+                SCOHelper.assertNullKeysAllowed(k, allowNulls);
+                SCOHelper.assertKeyType(k, keyType);
+            } catch (Throwable ex) {
+                err[l++] = ex;
+            }
+            try {
+                SCOHelper.assertNullValuesAllowed(v, allowNulls);
+                SCOHelper.assertValueType(v, valueType);
+            } catch (Throwable ex) {
+                err[l++] = ex;
+            }
+        }
+        SCOHelper.validateResult(l, err);
+
+        boolean modified = false;
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        for (i = t.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next(); 
+            process(e.getKey(), e.getValue());
+        }
+
+        // Apply updates
+        this.trackUpdates(true);
+    } 
+
+     /**
+     * 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.
+     * @see java.util.HashSet
+     */  
+    public Object remove(Object key) {
+        SCOHelper.debug(_Hashtable, "remove"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        boolean removed = false;
+
+        // Nothing is added to the removed collections if the key has not
+        // been in the map before:
+        if (super.containsKey(key)) {
+            if (addedKeys.remove(key) == false) {
+                removedKeys.add(key);
+            }
+            removed = true;
+        }
+
+        Object o = super.remove(key);
+
+        // Remove old value if there was one:
+        if (removed && addedValues.remove(o) == false) {
+            removedValues.add(o);
+        }
+
+        // Apply updates
+        this.trackUpdates(removed);
+
+        return o;
+    }    
+
+
+    /**
+     * Removes all of the elements from this map.
+     * @see java.util.HashMap
+     */  
+    public void clear() {
+        SCOHelper.debug(_Hashtable, "clear"); // NOI18N
+
+        // Mark the field as dirty
+        this.makeDirty();
+
+        thaw();
+        for (Iterator i = super.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next();
+            removedKeys.add(e.getKey());
+            removedValues.add(e.getValue());
+        }
+
+        super.clear();
+        addedKeys.clear();
+        addedValues.clear();
+
+        // Apply updates
+        this.trackUpdates(true);
+
+    }     
+ 
+    /** Creates and returns a copy of this object.
+     *
+     * <P>Mutable Second Class Objects are required to provide a public
+     * clone method in order to allow for copying PersistenceCapable
+     * objects. In contrast to Object.clone(), this method must not throw a
+     * CloneNotSupportedException.
+     * @return the clone.
+     */  
+    public Object clone() {
+        SCOHelper.debug(_Hashtable, "clone"); // NOI18N
+
+        Object obj = super.clone();
+        if (obj instanceof SCO) {
+            ((SCO)obj).unsetOwner(owner, fieldNumber);
+        }
+        return obj;
+    }
+
+    /** These methods need to thaw the map before performing the operation.
+     */
+    public boolean containsKey(Object key) {
+        thaw();
+        return super.containsKey(key);
+    }
+    public boolean containsValue(Object value) {
+        thaw();
+        return super.containsValue(value);
+    }
+    public Set entrySet() {
+        thaw();
+        return super.entrySet();
+    }
+    public boolean equals(Object o) {
+        thaw();
+        return super.equals(o);
+    }
+    public Object get(Object key) {
+        thaw();
+        return super.get(key);
+    }
+    public int hashCode() {
+        thaw();
+        return super.hashCode();
+    }
+    public boolean isEmpty() {
+        thaw();
+        return super.isEmpty();
+    }
+    public Set keySet() {
+        thaw();
+        return super.keySet();
+    }
+    public int size() {
+        thaw();
+        return super.size();
+    }
+    public Collection values() {
+        thaw();
+        return super.values();
+    }
+    public String toString() {
+        thaw();
+        return super.toString();
+    }
+    public boolean contains(Object value) {
+        thaw();
+        return super.contains(value);
+    }
+    public Enumeration elements() {
+        thaw();
+        return super.elements();
+    }
+    public Enumeration keys() {
+        thaw();
+        return super.keys();
+    }
+    // Note, no need to redefine the protected method rehash. 
+    // Actually redefining rehash lead to an endless recursion.
+    
+    /**
+     * @see SCOMap#reset()
+     */  
+    public void reset() {
+        addedKeys.clear();
+        addedValues.clear();
+        removedKeys.clear();
+        removedValues.clear();
+        frozenEntries = null;
+    }
+
+    /**
+     * @see SCOMap#putInternal(Object key, Object value)
+     */  
+    public void putInternal(Object key, Object value) {
+        super.put(key, value);
+    }
+
+
+    /**
+     * @see SCOMap#putAllInternal(Map t)
+     */  
+    public void putAllInternal(Map t) {
+        for (Iterator i = t.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next();
+            super.put(e.getKey(), e.getValue());
+        }
+    }    
+
+    /** 
+     * @see SCOMap#getAddedKeys()
+     */  
+    public Collection getAddedKeys() { 
+        return (Collection)addedKeys; 
+    }     
+ 
+    /** 
+     * @see SCOMap#getAddedValues()
+     */  
+    public Collection getAddedValues() { 
+        return (Collection)addedValues; 
+    }     
+ 
+    /**  
+     * @see SCOMap#getRemovedKeys()
+     */  
+    public Collection getRemovedKeys()  {  
+        return (Collection)removedKeys;  
+    }      
+
+    /**  
+     * @see SCOMap#getRemovedValues()
+     */  
+    public Collection getRemovedValues()  {  
+        return (Collection)removedValues;  
+    }      
+
+    /** 
+     * @see SCOMap#clearInternal()
+     */   
+    public void clearInternal() {    
+        super.clear(); 
+        this.reset(); 
+    }  
+
+    /**
+     * @see SCOMap#removeInternal(Object key)
+     */  
+    public void removeInternal(Object key) {
+        super.remove(key);
+    }
+
+    /**
+     * @see SCO#unsetOwner(Object owner, int fieldNumber)
+     */
+    public void unsetOwner(Object owner, int fieldNumber) { 
+        // Unset only if owner and fieldNumber match.
+        if (this.owner == owner && this.fieldNumber == fieldNumber) {
+            this.owner = null; 
+            this.fieldNumber = -1;
+        }
+    }
+
+    /**
+     * @see SCO#setOwner (Object owner, int fieldNumber)
+     */
+    public void setOwner (Object owner, int fieldNumber) {
+        // Set only if it was not set before.
+        if (this.owner == null && owner instanceof StateManagerInternal) {
+            this.owner = (StateManagerInternal)owner;    
+            this.fieldNumber = fieldNumber;
+        }
+    }
+
+    /** 
+     * @see SCO#getOwner()
+     */   
+    public Object getOwner() {   
+        return SCOHelper.getOwner(owner);
+    } 
+ 
+    /**  
+     * @see SCO#getFieldName()
+     */   
+    public String getFieldName() {
+        return SCOHelper.getFieldName(owner, fieldNumber);   
+    }
+
+    /**
+     * Notify StateManager to mark field as dirty.
+     */
+    private void makeDirty() {
+        if (owner != null) {
+            owner.makeDirty(fieldNumber); //
+        }
+     }   
+    /**
+     * Notify StateManager to process the changes.
+     */  
+    private void trackUpdates(boolean modified) {
+        if (modified && owner != null) {
+               owner.trackUpdates(fieldNumber, this);
+        }
+    }
+
+    /**
+     * @see SCOMap#getKeyType() {
+     */  
+    public Class getKeyType() {
+        return keyType;
+    }
+
+    /**
+     * @see SCOMap#getValueType() {
+     */  
+    public Class getValueType() {
+        return valueType;
+    }
+
+    /**
+     * @see SCOMap#allowNulls() {
+     */  
+    public boolean allowNulls() {
+        return allowNulls;
+    }
+
+    /**
+     * Processes single put operation in this map.
+     * @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. 
+     */
+    private Object process(Object key, Object value) {
+        // Key is added to the addedKeys collection only if it has not
+        // been in the map before:
+        if (!super.containsKey(key)) {
+            if (removedKeys.remove(key) == false) {
+                addedKeys.add(key);
+            }
+        }
+
+        Object o = super.put(key, value);
+
+        // Remove old value:
+        if (addedValues.remove(o) == false) {
+            removedValues.add(o);
+        }
+
+        // Add new value:
+        if (removedValues.remove(value) == false) {
+            addedValues.add(value);
+        }
+
+        return o;
+    }
+    
+    /** Returns the frozen state of this Map.
+     * @since 1.0.1
+     * @return the frozen state.
+     */
+    private boolean isFrozen() {
+        return frozenEntries != null;
+    }
+    
+    /** Returns the frozen contents of this Map as a Map.Entry[].
+     * @since 1.0.1
+     * @return the frozen entries.
+     */
+    private Map.Entry[] getFrozen() {
+        if (!isFrozen()) {
+            frozenEntries = Freezer.freeze(this, super.size());
+        }
+        return frozenEntries;
+    }
+    
+    /** Set the contents of this Map from the frozen entries.
+     * @since 1.0.1
+     * @param entries the frozen entries.
+     */
+    public void setFrozen(Map.Entry[] entries) {
+        frozenEntries = entries;
+    }
+    
+    /** Get an iterator regardless of whether the map is frozen.
+     * If frozen, get a frozen iterator.
+     * If thawed, get a regular iterator.
+     * @since 1.0.1
+     * @return the iterator.
+     */
+    public Iterator eitherIterator() {
+        if (isFrozen()) {
+            return frozenIterator();
+        } else {
+            return super.entrySet().iterator();
+        }
+    }
+    
+    /** Get an iterator over the frozen elements of this map. This allows
+     * iteration of the elements without thawing them, as is needed for
+     * transcription.
+     * @since 1.0.1
+     * @return the iterator.
+     */
+    public Iterator frozenIterator() {
+        return Freezer.createFrozenIterator(getFrozen());
+    }
+    
+    /**
+     * Thaw the frozen elements of this map. If the elements are frozen,
+     * retrieve them from the datastore and internally add them. Then reset
+     * the frozen state since they're not frozen any more.
+     * @since 1.0.1
+     */
+    private void thaw() {
+        if (isFrozen()) {
+            frozenEntries = Freezer.thaw(this, owner, frozenEntries);
+        }
+    }
+    
+}


Reply via email to