KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > DataRow


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne;
57
58 import java.util.HashMap JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.List JavaDoc;
61 import java.util.Map JavaDoc;
62
63 import org.apache.commons.lang.builder.ToStringBuilder;
64 import org.objectstyle.cayenne.conf.Configuration;
65 import org.objectstyle.cayenne.map.DbAttribute;
66 import org.objectstyle.cayenne.map.DbEntity;
67 import org.objectstyle.cayenne.map.DbRelationship;
68 import org.objectstyle.cayenne.map.ObjEntity;
69 import org.objectstyle.cayenne.util.Util;
70
71 /**
72  * DataRow is a map that holds values retrieved from the database for a
73  * given query row. DataRows are used to cache database data snapshots,
74  * and as a reference point for tracking DataObject changes.
75  *
76  * @author Andrei Adamchik
77  * @since 1.1
78  */

79
80 // TODO: Maybe implement "locking" of snapshot after it has been created,
81
// since snapshots are expected to be immutable
82
public class DataRow extends HashMap JavaDoc {
83
84     // "volatile" is supposed to ensure consistency in read and increment operations;
85
// is this universally true?
86

87     // make sure the starting value is different from DataObject default version value
88
private static volatile long currentVersion = DataObject.DEFAULT_VERSION + 1;
89
90     protected long version = currentVersion++;
91     protected long replacesVersion = DataObject.DEFAULT_VERSION;
92
93     public DataRow(Map JavaDoc map) {
94         super(map);
95     }
96
97     public DataRow(int initialCapacity) {
98         super(initialCapacity);
99     }
100
101     public long getVersion() {
102         return version;
103     }
104
105     public long getReplacesVersion() {
106         return replacesVersion;
107     }
108
109     /**
110      * Sets the version of DataRow replaced by this one in the store.
111      */

112     public void setReplacesVersion(long replacesVersion) {
113         this.replacesVersion = replacesVersion;
114     }
115
116     /**
117      * Builds a new DataRow, merging changes from <code>diff</code>
118      * parameter with data contained in this DataRow.
119      */

120     public DataRow applyDiff(DataRow diff) {
121         DataRow merged = new DataRow(this);
122
123         Iterator JavaDoc it = diff.entrySet().iterator();
124         while (it.hasNext()) {
125             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
126             merged.put(entry.getKey(), entry.getValue());
127         }
128
129         return merged;
130     }
131
132     /**
133       * Creates a DataRow that contains only the keys that have values that differ
134       * between this object and <code>row</code> parameter. Diff values are taken from the
135       * <code>row</code> parameter. It is assumed that key
136       * sets are compatible in both rows (e.g. they represent
137       * snapshots for the same entity). Returns null if no differences are found.
138       */

139     public DataRow createDiff(DataRow row) {
140
141         // build a diff...
142
DataRow diff = null;
143
144         Iterator JavaDoc entries = entrySet().iterator();
145         while (entries.hasNext()) {
146             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
147
148             Object JavaDoc key = entry.getKey();
149             Object JavaDoc currentValue = entry.getValue();
150             Object JavaDoc rowValue = row.get(key);
151
152             if (!Util.nullSafeEquals(currentValue, rowValue)) {
153                 if (diff == null) {
154                     diff = new DataRow(this.size());
155                 }
156                 diff.put(key, rowValue);
157             }
158         }
159
160         return diff;
161     }
162
163     /**
164       * Creates an ObjectId from the values in the snapshot.
165       * If needed attributes are missing in a snapshot,
166       * CayenneRuntimeException is thrown.
167       */

168     public ObjectId createObjectId(ObjEntity entity) {
169         return createObjectId(
170             entity.getJavaClass(Configuration.getResourceLoader()),
171             entity.getDbEntity());
172     }
173
174     public ObjectId createObjectId(Class JavaDoc objectClass, DbEntity entity) {
175
176         // ... handle special case - PK.size == 1
177
// use some not-so-significant optimizations...
178

179         List JavaDoc pk = entity.getPrimaryKey();
180         if (pk.size() == 1) {
181             DbAttribute attr = (DbAttribute) pk.get(0);
182             Object JavaDoc val = this.get(attr.getName());
183             if (val == null) {
184                 throw new CayenneRuntimeException(
185                     "Null value for '" + attr.getName() + "'. Snapshot: " + this);
186             }
187             
188             return new ObjectId(objectClass, attr.getName(), val);
189         }
190
191         // ... handle generic case - PK.size > 1
192

193         Map JavaDoc idMap = new HashMap JavaDoc(pk.size() * 2);
194         Iterator JavaDoc it = pk.iterator();
195         while (it.hasNext()) {
196             DbAttribute attr = (DbAttribute) it.next();
197             Object JavaDoc val = this.get(attr.getName());
198             if (val == null) {
199                 throw new CayenneRuntimeException(
200                     "Null value for '" + attr.getName() + "'. Snapshot: " + this);
201             }
202
203             idMap.put(attr.getName(), val);
204         }
205
206         return new ObjectId(objectClass, idMap);
207     }
208
209     /**
210      * Returns an ObjectId of an object on the other side of the to-one relationship,
211      * for this DataRow representing a source of relationship. Returns null if snapshot
212      * FK columns indicate a null to-one relationship.
213      */

214     public ObjectId createTargetObjectId(
215         Class JavaDoc targetClass,
216         DbRelationship relationship) {
217
218         if (relationship.isToMany()) {
219             throw new CayenneRuntimeException("Only 'to one' can have a target ObjectId.");
220         }
221
222         Map JavaDoc target = relationship.targetPkSnapshotWithSrcSnapshot(this);
223         return (target != null) ? new ObjectId(targetClass, target) : null;
224     }
225
226     public String JavaDoc toString() {
227         return new ToStringBuilder(this).append("version", version).append(
228                 " replaces",
229                 replacesVersion).append(" values", super.toString()).toString();
230     }
231 }
232
Popular Tags