001: package org.apache.ojb.otm.copy;
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 org.apache.ojb.broker.PersistenceBroker;
019: import org.apache.ojb.broker.metadata.*;
020: import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
021: import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
022: import org.apache.ojb.broker.core.proxy.ProxyHelper;
023: import org.apache.ojb.broker.util.ConstructorHelper;
024: import org.apache.ojb.broker.util.IdentityMapFactory;
025:
026: import java.lang.reflect.Constructor;
027: import java.util.Map;
028: import java.util.Collection;
029: import java.util.Iterator;
030:
031: /**
032: * recursively copies an object based on the ClassDescriptor
033: * User: matthew.baird
034: * Date: Jul 7, 2003
035: * Time: 1:41:58 PM
036: */
037: public final class MetadataObjectCopyStrategy implements
038: ObjectCopyStrategy {
039: private static final ReflectiveObjectCopyStrategy _reflective = new ReflectiveObjectCopyStrategy();
040: private static final SerializeObjectCopyStrategy _serialize = new SerializeObjectCopyStrategy();
041:
042: /**
043: * Uses an IdentityMap to make sure we don't recurse infinitely on the same object in a cyclic object model.
044: * Proxies
045: * @param obj
046: * @return
047: */
048: public Object copy(final Object obj, final PersistenceBroker broker) {
049: return clone(obj, IdentityMapFactory.getIdentityMap(), broker);
050: }
051:
052: private static Object clone(final Object toCopy, final Map objMap,
053: final PersistenceBroker broker) {
054: /**
055: * first, check to make sure we aren't recursing to some object that we've already copied.
056: * if the toCopy is in the objMap, just return it.
057: */
058: if (objMap.containsKey(toCopy))
059: return objMap.get(toCopy);
060: /**
061: * if null, return null, duh
062: */
063: if (toCopy == null)
064: return null;
065:
066: /**
067: * if this is a proxy, just copy the proxy, don't materialize it, and stop recursing
068: */
069: if (ProxyHelper.isVirtualOjbProxy(toCopy)) {
070: return _reflective.copy(toCopy, null);
071: } else if (ProxyHelper.isNormalOjbProxy(toCopy)) {
072: return _serialize.copy(toCopy, null);
073: }
074:
075: /**
076: * if no classdescriptor exists for this object, just return this object, we
077: * can't copy it.
078: */
079: final ClassDescriptor cld = broker.getClassDescriptor(toCopy
080: .getClass());
081: if (cld == null) {
082: return _reflective.copy(toCopy, null);
083: }
084:
085: final Object retval;
086: try {
087: final Constructor con = cld.getZeroArgumentConstructor();
088: retval = ConstructorHelper.instantiate(con);
089: objMap.put(toCopy, retval);
090: } catch (InstantiationException e) {
091: throw new ObjectCopyException("InstantiationException", e);
092: }
093:
094: /**
095: * first copy all the fields
096: * fields are not mapped objects (ie ObjectReferenceDescriptors)
097: */
098: final FieldDescriptor[] fieldDescs = cld.getFieldDescriptions();
099: // final BrokerHelper brokerHelper = broker.serviceBrokerHelper();
100: for (int i = 0; i < fieldDescs.length; i++) {
101: final FieldDescriptor fd = fieldDescs[i];
102: final PersistentField f = fd.getPersistentField();
103: Object fieldValue = f.get(toCopy);
104: /*
105: arminw:
106: TODO: ensure that the autoincrement values be assigned before the copy was done
107: If possible we should avoid to declare BrokerHelper#getAutoIncrementValue public and
108: if we copy an object user don't expect the change of fields.
109: */
110: // // If the field is auto increment, assign its value before copying!
111: // if (fd.isAutoIncrement())
112: // {
113: // fieldValue = brokerHelper.getAutoIncrementValue(fd, toCopy, fieldValue);
114: // }
115: f.set(retval, fieldValue);
116: }
117:
118: /**
119: * then copy all the 1:1 references
120: */
121: final Collection refDescsCol = cld
122: .getObjectReferenceDescriptors();
123: final ObjectReferenceDescriptor[] rds = (ObjectReferenceDescriptor[]) refDescsCol
124: .toArray(new ObjectReferenceDescriptor[refDescsCol
125: .size()]);
126: for (int i = 0; i < rds.length; i++) {
127: final ObjectReferenceDescriptor rd = rds[i];
128: final PersistentField f = rd.getPersistentField();
129: /**
130: * recursively copy the referenced objects
131: * register in the objMap first
132: */
133: final Object object = f.get(toCopy);
134: final Object clone = clone(object, objMap, broker);
135: objMap.put(object, clone);
136: f.set(retval, clone);
137: }
138: /**
139: * then copy all the 1:M and M:N references
140: */
141: final Collection colDescsCol = cld.getCollectionDescriptors();
142: final Iterator it = colDescsCol.iterator();
143: while (it.hasNext()) {
144: final CollectionDescriptor cd = (CollectionDescriptor) it
145: .next();
146: final PersistentField f = cd.getPersistentField();
147: final Object collection = f.get(toCopy);
148: /**
149: * handle collection proxies where the entire Collection is a big proxy
150: * (vs all the elements in the collection are proxies
151: */
152: if (collection == null) {
153: f.set(retval, null);
154: } else if (collection instanceof CollectionProxyDefaultImpl) {
155: f.set(retval, _reflective.copy(collection, null));
156: } else if (collection instanceof Collection) {
157: try {
158: final Collection newCollection = (Collection) collection
159: .getClass().newInstance();
160: final Iterator tempIter = ((Collection) collection)
161: .iterator();
162: Object obj;
163: while (tempIter.hasNext()) {
164: obj = tempIter.next();
165: /**
166: * if this is a proxy, just copy the proxy, don't materialize it, and stop recursing
167: */
168: if (ProxyHelper.isNormalOjbProxy(obj)) // tomdz: what about VirtualProxy ?
169: {
170: newCollection.add(obj);
171: } else {
172: final Object clone = clone(obj, objMap,
173: broker);
174: objMap.put(obj, clone);
175: newCollection.add(clone);
176: }
177: }
178: f.set(retval, newCollection);
179: } catch (InstantiationException e) {
180: throw new ObjectCopyException(
181: "InstantiationException", e);
182: } catch (IllegalAccessException e) {
183: throw new ObjectCopyException(
184: "IllegalAccessException", e);
185: }
186: } else {
187: throw new java.lang.UnsupportedOperationException(
188: "MetadataObjectCopyStrategy cannot handle Collection of type: "
189: + collection.getClass().getName());
190: }
191: }
192: return retval;
193: }
194: }
|