Author: peter_firmstone Date: Sun Oct 9 04:07:07 2011 New Revision: 1180542
URL: http://svn.apache.org/viewvc?rev=1180542&view=rev Log: Adding support for Serialization in ReferenceCollections Added: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferrerWrapper.java (with props) Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractSerializationOfRC.java river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceSerializedForm.java river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerialDataReferenceCollection.java river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerializationOfReferenceCollection.java Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractSerializationOfRC.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractSerializationOfRC.java?rev=1180542&r1=1180541&r2=1180542&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractSerializationOfRC.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/AbstractSerializationOfRC.java Sun Oct 9 04:07:07 2011 @@ -39,7 +39,11 @@ import java.util.concurrent.BlockingQueu import java.util.concurrent.TimeUnit; /** - * + * The purpose of this class is to implement all the possible interfaces + * that subclasses of ReferenceCollection may implement. This is designed + * to fix the readResolve issue that occurs in object graphs containing + * circular references. + * * @author Peter Firmstone. */ abstract class AbstractSerializationOfRC<T> extends SerializationOfReferenceCollection<T> @@ -47,15 +51,15 @@ implements Serializable, List<T>, Set<T> Queue<T>, Deque<T>, BlockingQueue<T>, BlockingDeque<T>{ private static final long serialVersionUID = 1L; - // This abstract class must not hold any serial data. + // This abstract class must not hold any serial data. - // Builder created List on deserialization - private volatile transient Collection<T> serialBuilt = null; - private volatile transient boolean built = false; - + // Builder created List on deserialization + private volatile transient Collection<T> serialBuilt = null; + private volatile transient boolean built = false; @Override - Collection<T> build() throws InstantiationException, IllegalAccessException { + Collection<T> build() throws InstantiationException, IllegalAccessException, + ObjectStreamException { if (isBuilt()) return getSerialBuilt(); setBuilt(); /* Traverse Inheritance heirarchy in reverse order */ Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java?rev=1180542&r1=1180541&r2=1180542&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceFactory.java Sun Oct 9 04:07:07 2011 @@ -40,11 +40,15 @@ class ReferenceFactory<T> { static <T> Referrer<T> create(T t, ReferenceQueue<? super T> queue, Ref type ){ switch (type){ - case WEAK_IDENTITY: return new WeakIdentityReferenceKey<T>(t, queue); - case SOFT_IDENTITY: return new SoftIdentityReferenceKey<T>(t, queue); - case WEAK: return new WeakReferenceKey<T>(t, queue); - case SOFT: return new SoftReferenceKey<T>(t, queue); - default: return new StrongReferenceKey<T>(t, queue); + case WEAK_IDENTITY: + return new ReferrerWrapper<T>(new WeakIdentityReferenceKey<T>(t, queue)); + case SOFT_IDENTITY: + return new ReferrerWrapper<T>(new SoftIdentityReferenceKey<T>(t, queue)); + case WEAK: + return new ReferrerWrapper<T>(new WeakReferenceKey<T>(t, queue)); + case SOFT: + return new ReferrerWrapper<T>(new SoftReferenceKey<T>(t, queue)); + default: return new ReferrerWrapper<T>(new StrongReferenceKey<T>(t, queue)); } } Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceSerializedForm.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceSerializedForm.java?rev=1180542&r1=1180541&r2=1180542&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceSerializedForm.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferenceSerializedForm.java Sun Oct 9 04:07:07 2011 @@ -64,10 +64,7 @@ class ReferenceSerializedForm<T> extends return false; } - /* ReferenceQueue is not compared, because a lookup key is used to locate - * an existing key and ReferenceQueue is null in lookup key's. - * - * ReferenceQueue is not part of hashCode or equals. + /* In this case we're using Identity */ @Override public boolean equals(Object o) { @@ -75,7 +72,7 @@ class ReferenceSerializedForm<T> extends if (!(o instanceof Referrer)) return false; Object k1 = get(); Object k2 = ((Referrer) o).get(); - if ( k1 != null && k1.equals(k2)) return true; + if ( k1 != null && k1 == k2) return true; return ( k1 == null && k2 == null && hashCode() == o.hashCode()); // Both objects were collected. } Added: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferrerWrapper.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferrerWrapper.java?rev=1180542&view=auto ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferrerWrapper.java (added) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferrerWrapper.java Sun Oct 9 04:07:07 2011 @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.river.impl.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * + * @author peter + */ +final class ReferrerWrapper<T> implements Referrer<T>, Serializable{ + private static final long serialVersionUID = 1L; + + /** + * @serialField + */ + private volatile Referrer<T> reference; + + ReferrerWrapper(Referrer<T> ref){ + if (ref == null) throw new NullPointerException("Referrer cannot be null"); + reference = ref; + } + + void refresh(ReferenceQueuingFactory<T, Referrer<T>> rqf){ + T object = get(); + if (object != null){ + Referrer<T> newRef = rqf.referenced(object, true); + synchronized (this){ + reference = newRef; + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; // Same reference. + if (!(o instanceof Referrer)) return false; + return reference.equals(o); + } + + @Override + public int hashCode() { + return reference.hashCode(); + } + + @Override + public T get() { + return reference.get(); + } + + @Override + public void clear() { + reference.clear(); + } + + @Override + public boolean isEnqueued() { + return reference.isEnqueued(); + } + + @Override + public boolean enqueue() { + return reference.enqueue(); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + if (reference == null) throw new IOException("Attempt to write null Referrer"); + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + +} Propchange: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/ReferrerWrapper.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerialDataReferenceCollection.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerialDataReferenceCollection.java?rev=1180542&r1=1180541&r2=1180542&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerialDataReferenceCollection.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerialDataReferenceCollection.java Sun Oct 9 04:07:07 2011 @@ -19,33 +19,46 @@ package org.apache.river.impl.util; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; import java.util.Collection; +import java.util.Iterator; /** - * + * This class is the serial form of ReferenceCollection and all it's subclasses. + * + * While the serial form of this class will remain compatible with itself, + * ReferenceCollection may replace this implementation with another + * at some point in the future. + * + * This class will still be able to deserialize into a ReferenceCollection. + * * @author peter */ public class SerialDataReferenceCollection<T> extends AbstractSerializationOfRC<T> { private static final long serialVersionUID = 1L; - /** @serialData */ - private Ref type = null; - /** @serialData */ + /** @serialField */ + private Ref type; + /** @serialField */ private Collection<Referrer<T>> collection; - /** @serialData */ + /** @serialField */ private Class clazz; @SuppressWarnings("unchecked") SerialDataReferenceCollection( Class clazz, Collection<Referrer<T>> underlyingCollection, Ref type) throws InstantiationException, IllegalAccessException{ - // Create a new instance of the underlying collection and - // add all objects. - this.collection = underlyingCollection; - this.type = type; - this.clazz = clazz; + // Create a new instance of the underlying collection and + // add all objects. + if ( clazz == null || underlyingCollection == null || type == null){ + throw new NullPointerException("null parameters prohibited"); + } + this.collection = underlyingCollection; + this.type = type; + this.clazz = clazz; } @Override @@ -64,15 +77,36 @@ public class SerialDataReferenceCollecti } @Override - Collection<T> build() throws InstantiationException, IllegalAccessException{ + final Collection<T> build() throws InstantiationException, IllegalAccessException, + ObjectStreamException{ Collection<T> result = super.build(); - // What if the underlying collection is immutable? + /* What if the underlying collection is immutable? + * The ReferenceQueuingFactory is unknown until the ReferenceCollection + * has been built. + */ + if ( result instanceof ReferenceCollection){ + ReferenceCollection<T> refCol = (ReferenceCollection<T>) result; + ReferenceQueuingFactory<T, Referrer<T>> rqf = refCol.getRQF(); + Iterator<Referrer<T>> colIt = collection.iterator(); + while (colIt.hasNext()){ + Referrer<T> ref = colIt.next(); + if ( ref == null ) continue; + if (ref instanceof ReferrerWrapper){ + ((ReferrerWrapper<T>) ref).refresh(rqf); + } else { + throw new InvalidObjectException("Referrer's must be a ReferrerWraper for ReferenceCollection"); + } + } + } return result; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if ( clazz == null || collection == null || type == null){ + throw new InvalidObjectException("null fields found after deserialization"); + } } private void writeObject(ObjectOutputStream out) throws IOException { Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerializationOfReferenceCollection.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerializationOfReferenceCollection.java?rev=1180542&r1=1180541&r2=1180542&view=diff ============================================================================== --- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerializationOfReferenceCollection.java (original) +++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/util/SerializationOfReferenceCollection.java Sun Oct 9 04:07:07 2011 @@ -18,6 +18,7 @@ package org.apache.river.impl.util; +import java.io.ObjectStreamException; import java.util.AbstractCollection; import java.util.Collection; @@ -34,6 +35,7 @@ abstract class SerializationOfReferenceC return new SerialDataReferenceCollection<T>(clazz, refCol, type); } - abstract Collection<T> build() throws InstantiationException, IllegalAccessException; + abstract Collection<T> build() throws InstantiationException, + IllegalAccessException, ObjectStreamException; }
