KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > util > ObjectDetachOperation


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.util;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.ObjectId;
30 import org.apache.cayenne.Persistent;
31 import org.apache.cayenne.map.EntityResolver;
32 import org.apache.cayenne.query.PrefetchTreeNode;
33 import org.apache.cayenne.reflect.AttributeProperty;
34 import org.apache.cayenne.reflect.ClassDescriptor;
35 import org.apache.cayenne.reflect.Property;
36 import org.apache.cayenne.reflect.PropertyVisitor;
37 import org.apache.cayenne.reflect.ToManyProperty;
38 import org.apache.cayenne.reflect.ToOneProperty;
39
40 /**
41  * An operation that creates a subgraph of detached objects, using the PrefetchTree to
42  * delineate the graph boundaries. Target objects can be described by a different set of
43  * descriptors, thus allowing server-to-client conversion to happen in the process.
44  *
45  * @since 1.2
46  * @author Andrus Adamchik
47  */

48 public class ObjectDetachOperation {
49
50     protected EntityResolver targetResolver;
51     protected Map JavaDoc seen;
52
53     public ObjectDetachOperation(EntityResolver targetResolver) {
54         this.targetResolver = targetResolver;
55         this.seen = new HashMap JavaDoc();
56     }
57
58     public void reset() {
59         seen.clear();
60     }
61
62     /**
63      * "Detaches" an object from its context by creating an unattached copy. The copy is
64      * created using target descriptor of this operation that may be different from the
65      * object descriptor passed to this method.
66      */

67     public Object JavaDoc detach(
68             Object JavaDoc object,
69             ClassDescriptor descriptor,
70             final PrefetchTreeNode prefetchTree) {
71         if (!(object instanceof Persistent)) {
72             throw new CayenneRuntimeException("Expected Persistent, got: " + object);
73         }
74
75         final Persistent source = (Persistent) object;
76         ObjectId id = source.getObjectId();
77
78         // sanity check
79
if (id == null) {
80             throw new CayenneRuntimeException("Server returned an object without an id: "
81                     + source);
82         }
83
84         Object JavaDoc seenTarget = seen.get(id);
85         if (seenTarget != null) {
86             return seenTarget;
87         }
88
89         descriptor = descriptor.getSubclassDescriptor(source.getClass());
90
91         // presumably id's entity name should be of the right subclass.
92
final ClassDescriptor targetDescriptor = targetResolver.getClassDescriptor(id
93                 .getEntityName());
94
95         final Persistent target = (Persistent) targetDescriptor.createObject();
96         target.setObjectId(id);
97         seen.put(id, target);
98
99         descriptor.visitProperties(new PropertyVisitor() {
100
101             public boolean visitToOne(ToOneProperty property) {
102                 if (prefetchTree != null) {
103
104                     PrefetchTreeNode child = prefetchTree.getNode(property.getName());
105
106                     if (child != null) {
107                         Object JavaDoc destinationSource = property.readProperty(source);
108
109                         Object JavaDoc destinationTarget = destinationSource != null ? detach(
110                                 destinationSource,
111                                 property.getTargetDescriptor(),
112                                 child) : null;
113
114                         ToOneProperty targetProperty = (ToOneProperty) targetDescriptor
115                                 .getProperty(property.getName());
116                         Object JavaDoc oldTarget = targetProperty.isFault(target)
117                                 ? null
118                                 : targetProperty.readProperty(target);
119                         targetProperty
120                                 .writeProperty(target, oldTarget, destinationTarget);
121                     }
122                 }
123
124                 return true;
125             }
126
127             public boolean visitToMany(ToManyProperty property) {
128                 if (prefetchTree != null) {
129                     PrefetchTreeNode child = prefetchTree.getNode(property.getName());
130
131                     if (child != null) {
132                         Collection JavaDoc collection = (Collection JavaDoc) property
133                                 .readProperty(source);
134
135                         Collection JavaDoc targetCollection = new ArrayList JavaDoc(collection.size());
136
137                         Iterator JavaDoc it = collection.iterator();
138                         while (it.hasNext()) {
139                             Object JavaDoc destinationSource = it.next();
140                             Object JavaDoc destinationTarget = destinationSource != null
141                                     ? detach(destinationSource, property
142                                             .getTargetDescriptor(), child)
143                                     : null;
144
145                             targetCollection.add(destinationTarget);
146                         }
147
148                         ToManyProperty targetProperty = (ToManyProperty) targetDescriptor
149                                 .getProperty(property.getName());
150                         targetProperty.writeProperty(target, null, targetCollection);
151                     }
152                 }
153
154                 return true;
155             }
156
157             public boolean visitAttribute(AttributeProperty property) {
158                 Property targetProperty = targetDescriptor
159                         .getProperty(property.getName());
160                 targetProperty.writeProperty(target, null, property.readProperty(source));
161                 return true;
162             }
163         });
164
165         return target;
166     }
167 }
168
Popular Tags