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);
+ }
+ }
+
+}
|