001    /*
002     * Copyright 2002-2005 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.binding.value.support;
017    
018    import java.io.ByteArrayInputStream;
019    import java.io.ByteArrayOutputStream;
020    import java.io.IOException;
021    import java.io.NotSerializableException;
022    import java.io.ObjectInputStream;
023    import java.io.ObjectOutputStream;
024    import java.util.ArrayList;
025    import java.util.Collection;
026    
027    import org.springframework.binding.value.ValueModel;
028    
029    /**
030     * Implementation of a BufferedCollectionValueModel that performs a deep copy on the
031     * elements of the collection.
032     * 
033     * @author Larry Streepy
034     * 
035     */
036    public class DeepCopyBufferedCollectionValueModel extends BufferedCollectionValueModel {
037    
038        /**
039         * Constructs a new DeepCopyBufferedCollectionValueModel.
040         * 
041         * @param wrappedModel the value model to wrap
042         * @param wrappedType the class of the value contained by wrappedModel; this must be
043         *            assignable to <code>java.util.Collection</code> or
044         *            <code>Object[]</code>.
045         */
046        public DeepCopyBufferedCollectionValueModel(ValueModel wrappedModel, Class wrappedType) {
047            super( wrappedModel, wrappedType );
048        }
049    
050        /**
051         * Prepare the backing collection for installation into the listListModel. Create a
052         * new collection that contains a deep copy of the elements in the given collection.
053         * 
054         * @param col The collection of objects to process
055         * @return processed collection
056         */
057        protected Collection prepareBackingCollection(Collection col) {
058            ArrayList list = new ArrayList(col);
059            for( int i=0; i < list.size(); i++ ) {
060                list.set(i, deepCopy(list.get(i)));
061            }
062            return list;
063        }
064    
065        /**
066         * Create a new object that is a deep copy of the given object. This copy is created
067         * using serialization, so the object to be copied must implement Serializable. If it
068         * does not, then the original object will be returned. Any other error results in
069         * null being returned.
070         * 
071         * @param value
072         * @return deep copy
073         */
074        protected Object deepCopy(Object value) {
075            try {
076                // Write to new byte array to clone.
077                ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 );
078                ObjectOutputStream oos = new ObjectOutputStream( baos );
079                try {
080                    oos.writeObject( value );
081                } catch( NotSerializableException e ) {
082                    return value;
083                } finally {
084                    oos.close();
085                }
086    
087                // Read it back and return a true copy.
088                ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() );
089                ObjectInputStream ois = new ObjectInputStream( bais );
090                try {
091                    return ois.readObject();
092                } finally {
093                    ois.close();
094                }
095            } catch( ClassNotFoundException ex ) {
096                ex.printStackTrace();
097            } catch( IOException ex ) {
098                ex.printStackTrace();
099            }
100            return null;
101        }
102    }