001    package org.apache.ojb.otm.swizzle;
002    
003    /* Copyright 2003-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import java.lang.reflect.Array;
019    import java.util.Collection;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Set;
023    import org.apache.ojb.broker.Identity;
024    import org.apache.ojb.broker.PersistenceBroker;
025    import org.apache.ojb.broker.cache.ObjectCache;
026    import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
027    import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
028    import org.apache.ojb.broker.core.proxy.SetProxyDefaultImpl;
029    import org.apache.ojb.broker.metadata.ClassDescriptor;
030    import org.apache.ojb.broker.metadata.CollectionDescriptor;
031    import org.apache.ojb.broker.metadata.FieldDescriptor;
032    import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
033    import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
034    
035    public class CopySwizzling implements Swizzling
036    {
037    
038        /**
039         * @see org.apache.ojb.otm.swizzle.Swizzling#swizzle(Object, Object, PersistenceBroker, ObjectCache)
040         */
041        public Object swizzle(Object newObj, Object oldObj, PersistenceBroker pb,
042                              ObjectCache cache)
043        {
044            if (newObj == null) // invalidating
045            {
046                return null;
047            }
048    
049            if (oldObj == null)
050            {
051                return newObj;
052            }
053    
054            if (!newObj.getClass().equals(oldObj.getClass()))
055            {
056                System.err.println("Cannot swizzle objects of different classes: "
057                        + newObj.getClass() + " and " + oldObj.getClass());
058                return newObj;
059            }
060    
061            ClassDescriptor mif = pb.getClassDescriptor(newObj.getClass());
062            FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
063    
064            for (int i = 0; i < fieldDescs.length; i++)
065            {
066                FieldDescriptor fd = fieldDescs[i];
067                PersistentField f = fd.getPersistentField();
068                f.set(oldObj, f.get(newObj));
069            }
070    
071            // N:1 relations
072            Iterator iter = mif.getObjectReferenceDescriptors().iterator();
073            ObjectReferenceDescriptor rds;
074            PersistentField field;
075            Object newRelObj;
076            Identity newRelOid;
077            Object oldRelObj;
078    
079            while (iter.hasNext())
080            {
081                rds = (ObjectReferenceDescriptor) iter.next();
082                field = rds.getPersistentField();
083                newRelObj = field.get(newObj);
084                oldRelObj = field.get(oldObj);
085                if ((newRelObj == null) && (oldRelObj != null))
086                {
087                    field.set(oldObj, null);
088                }
089                else if (newRelObj != null)
090                {
091                    newRelOid = new Identity(newRelObj, pb);
092                    if ((oldRelObj == null) ||
093                            !newRelOid.equals(new Identity(oldRelObj, pb)))
094                    {
095                        // seek for existing old object with the new identity
096                        oldRelObj = cache.lookup(newRelOid);
097                        if (oldRelObj == null)
098                        {
099                            throw new IllegalStateException("Related object not found in the context: " + newRelOid);
100                        }
101                        field.set(oldObj, oldRelObj);
102                    }
103                }
104            }
105    
106            // 1:N relations
107            Iterator collections = mif.getCollectionDescriptors().iterator();
108            CollectionDescriptor collectionDescriptor;
109    
110            while (collections.hasNext())
111            {
112                collectionDescriptor = (CollectionDescriptor) collections.next();
113                field = collectionDescriptor.getPersistentField();
114                if (Collection.class.isAssignableFrom(field.getType()))
115                {
116                    Collection newCol;
117                    Collection oldCol;
118    
119                    newCol = (Collection) field.get(newObj);
120                    if (newCol == null)
121                    {
122                        field.set(oldObj, null);
123                        continue;
124                    }
125    
126                    oldCol = (Collection) field.get(oldObj);
127                    if (newCol instanceof CollectionProxyDefaultImpl)
128                    {
129                        CollectionProxyDefaultImpl cp = (CollectionProxyDefaultImpl) newCol;
130                        if (newCol instanceof List)
131                        {
132                            oldCol = new ListProxyDefaultImpl(pb.getPBKey(), cp.getCollectionClass(), cp.getQuery());
133                        }
134                        else if (newCol instanceof Set)
135                        {
136                            oldCol = new SetProxyDefaultImpl(pb.getPBKey(), cp.getCollectionClass(), cp.getQuery());
137                        }
138                        else
139                        {
140                            oldCol = new CollectionProxyDefaultImpl(pb.getPBKey(), cp.getCollectionClass(), cp.getQuery());
141                        }
142                        if (!((CollectionProxyDefaultImpl) newCol).isLoaded())
143                        {
144                            field.set(oldObj, oldCol);
145                            continue;
146                        }
147                        oldCol.clear();
148                    }
149                    else
150                    {
151                        try
152                        {
153                            oldCol = (Collection) newCol.getClass().newInstance();
154                        }
155                        catch (Exception ex)
156                        {
157                            System.err.println("Cannot instantiate collection field which is neither Collection nor array: " + field);
158                            ex.printStackTrace();
159                            return newObj;
160                        }
161                    }
162                    field.set(oldObj, oldCol);
163                    for (Iterator it = newCol.iterator(); it.hasNext(); )
164                    {
165                        newRelObj = it.next();
166                        newRelOid = new Identity(newRelObj, pb);
167                        oldRelObj = cache.lookup(newRelOid);
168                        if (oldRelObj == null)
169                        {
170                            oldRelObj = newRelObj;
171                        }
172                        oldCol.add(oldRelObj);
173                    }
174                }
175                else if (field.getType().isArray())
176                {
177                    Object newArray = field.get(newObj);
178                    int length = Array.getLength(newArray);
179                    Object oldArray =
180                            Array.newInstance(field.getType().getComponentType(), length);
181    
182                    for (int i = 0; i < length; i++)
183                    {
184                        newRelObj = Array.get(newArray, i);
185                        newRelOid = new Identity(newRelObj, pb);
186                        oldRelObj = cache.lookup(newRelOid);
187                        if (oldRelObj == null)
188                        {
189                            throw new IllegalStateException("Related object not found for swizzle: " + newRelOid);
190                        }
191                        Array.set(oldArray, i, oldRelObj);
192                    }
193                    field.set(oldObj, oldArray);
194                }
195                else
196                {
197                    throw new IllegalStateException("Cannot swizzle collection field: " + field);
198                }
199            }
200    
201            return oldObj;
202        }
203    
204        /**
205         * @see org.apache.ojb.otm.swizzle.Swizzling#isSameInstance(Object, Object)
206         */
207        public boolean isSameInstance(Object swizzledObject, Object object)
208        {
209            return (swizzledObject == object);
210        }
211    
212        /**
213         * @see org.apache.ojb.otm.swizzle.Swizzling#getRealTarget(Object)
214         */
215        public Object getRealTarget(Object swizzledObject)
216        {
217            return swizzledObject;
218        }
219    
220    }