Package org.apache.ojb.otm.copy

Source Code of org.apache.ojb.otm.copy.MetadataObjectCopyStrategy

package org.apache.ojb.otm.copy;

/* Copyright 2003-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.
*/

import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.metadata.*;
import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
import org.apache.ojb.broker.core.proxy.ProxyHelper;
import org.apache.ojb.broker.util.ConstructorHelper;
import org.apache.ojb.broker.util.IdentityMapFactory;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Collection;
import java.util.Iterator;

/**
* recursively copies an object based on the ClassDescriptor
* User: matthew.baird
* Date: Jul 7, 2003
* Time: 1:41:58 PM
*/
public final class MetadataObjectCopyStrategy implements ObjectCopyStrategy
{
    private static final ReflectiveObjectCopyStrategy _reflective = new ReflectiveObjectCopyStrategy();
    private static final SerializeObjectCopyStrategy _serialize = new SerializeObjectCopyStrategy();

    /**
     * Uses an IdentityMap to make sure we don't recurse infinitely on the same object in a cyclic object model.
     * Proxies
     * @param obj
     * @return
     */
    public Object copy(final Object obj, final PersistenceBroker broker)
    {
        return clone(obj, IdentityMapFactory.getIdentityMap(), broker);
    }

    private static Object clone(final Object toCopy, final Map objMap, final PersistenceBroker broker)
    {
        /**
         * first, check to make sure we aren't recursing to some object that we've already copied.
         * if the toCopy is in the objMap, just return it.
         */
        if (objMap.containsKey(toCopy)) return objMap.get(toCopy);
        /**
         * if null, return null, duh
         */
        if (toCopy == null)
            return null;

        /**
         * if this is a proxy, just copy the proxy, don't materialize it, and stop recursing
         */
        if (ProxyHelper.isVirtualOjbProxy(toCopy))
        {
            return _reflective.copy(toCopy, null);
        }
        else if (ProxyHelper.isNormalOjbProxy(toCopy))
        {
            return _serialize.copy(toCopy, null);
        }

        /**
         * if no classdescriptor exists for this object, just return this object, we
         * can't copy it.
         */
        final ClassDescriptor cld = broker.getClassDescriptor(toCopy.getClass());
        if (cld == null)
        {
            return _reflective.copy(toCopy, null);
        }

        final Object retval;
        try
        {
            final Constructor con = cld.getZeroArgumentConstructor();
            retval = ConstructorHelper.instantiate(con);
            objMap.put(toCopy,retval);
        }
        catch (InstantiationException e)
        {
            throw new ObjectCopyException("InstantiationException", e);
        }

        /**
         * first copy all the fields
         * fields are not mapped objects (ie ObjectReferenceDescriptors)
         */
        final FieldDescriptor[] fieldDescs = cld.getFieldDescriptions();
//        final BrokerHelper brokerHelper = broker.serviceBrokerHelper();
        for (int i = 0; i < fieldDescs.length; i++)
        {
            final FieldDescriptor fd = fieldDescs[i];
            final PersistentField f = fd.getPersistentField();
            Object fieldValue = f.get(toCopy);
/*
arminw:
TODO: ensure that the autoincrement values be assigned before the copy was done
If possible we should avoid to declare BrokerHelper#getAutoIncrementValue public and
if we copy an object user don't expect the change of fields.
*/
//            // If the field is auto increment, assign its value before copying!
//            if (fd.isAutoIncrement())
//            {
//                fieldValue = brokerHelper.getAutoIncrementValue(fd, toCopy, fieldValue);
//            }

            f.set(retval, fieldValue);
        }

        /**
         * then copy all the 1:1 references
         */
        final Collection refDescsCol = cld.getObjectReferenceDescriptors();
        final ObjectReferenceDescriptor[] rds = (ObjectReferenceDescriptor[]) refDescsCol.toArray(new ObjectReferenceDescriptor[refDescsCol.size()]);
        for (int i = 0; i < rds.length; i++)
        {
            final ObjectReferenceDescriptor rd = rds[i];
            final PersistentField f = rd.getPersistentField();
            /**
             * recursively copy the referenced objects
             * register in the objMap first
             */
            final Object object = f.get(toCopy);
            final Object clone = clone(object, objMap, broker);
            objMap.put(object, clone);
            f.set(retval, clone);
        }
        /**
         * then copy all the 1:M and M:N references
         */
        final Collection colDescsCol = cld.getCollectionDescriptors();
        final Iterator it = colDescsCol.iterator();
        while (it.hasNext())
        {
            final CollectionDescriptor cd = (CollectionDescriptor) it.next();
            final PersistentField f = cd.getPersistentField();
            final Object collection = f.get(toCopy);
            /**
             * handle collection proxies where the entire Collection is a big proxy
             * (vs all the elements in the collection are proxies
             */
            if (collection == null)
            {
                f.set(retval, null);
            }
            else if (collection instanceof CollectionProxyDefaultImpl)
            {
                f.set(retval, _reflective.copy(collection, null));
            }
            else if (collection instanceof Collection)
            {
                try
                {
                    final Collection newCollection = (Collection) collection.getClass().newInstance();
                    final Iterator tempIter = ((Collection) collection).iterator();
                    Object obj;
                    while (tempIter.hasNext())
                    {
                        obj = tempIter.next();
                        /**
                        * if this is a proxy, just copy the proxy, don't materialize it, and stop recursing
                        */
                        if (ProxyHelper.isNormalOjbProxy(obj))  // tomdz: what about VirtualProxy ?
                        {
                            newCollection.add(obj);
                        }
                        else
                        {
                            final Object clone = clone(obj, objMap, broker);
                            objMap.put(obj, clone);
                            newCollection.add(clone);
                        }
                    }
                    f.set(retval, newCollection);
                }
                catch (InstantiationException e)
                {
                    throw new ObjectCopyException("InstantiationException", e);
                }
                catch (IllegalAccessException e)
                {
                    throw new ObjectCopyException("IllegalAccessException", e);
                }
            }
            else
            {
                throw new java.lang.UnsupportedOperationException("MetadataObjectCopyStrategy cannot handle Collection of type: " + collection.getClass().getName());
            }
        }
        return retval;
    }
}
TOP

Related Classes of org.apache.ojb.otm.copy.MetadataObjectCopyStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.