org.apache.cayenne.DataRow Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cayenne-client-nodeps
Show all versions of cayenne-client-nodeps
Cayenne Object Persistence Framework
/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
****************************************************************/
package org.apache.cayenne;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.util.Util;
/**
* DataRow a map that holds values retrieved from the database for a given query row.
* DataRows are used to cache raw database data and as a reference point for tracking
* DataObject changes.
*
* @author Andrus Adamchik
* @since 1.1
*/
public class DataRow extends HashMap {
// "volatile" is supposed to ensure consistency in read and increment operations;
// is this universally true?
// make sure the starting value is different from DataObject default version value
private static volatile long currentVersion = DataObject.DEFAULT_VERSION + 1;
protected long version = currentVersion++;
protected long replacesVersion = DataObject.DEFAULT_VERSION;
public DataRow(Map map) {
super(map);
}
public DataRow(int initialCapacity) {
super(initialCapacity);
}
public long getVersion() {
return version;
}
public long getReplacesVersion() {
return replacesVersion;
}
/**
* Sets the version of DataRow replaced by this one in the store.
*/
public void setReplacesVersion(long replacesVersion) {
this.replacesVersion = replacesVersion;
}
/**
* Builds a new DataRow, merging changes from diff
parameter with data
* contained in this DataRow.
*/
public DataRow applyDiff(DataRow diff) {
DataRow merged = new DataRow(this);
Iterator it = diff.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
merged.put(entry.getKey(), entry.getValue());
}
return merged;
}
/**
* Creates a DataRow that contains only the keys that have values that differ between
* this object and row
parameter. Diff values are taken from the
* row
parameter. It is assumed that key sets are compatible in both
* rows (e.g. they represent snapshots for the same entity). Returns null if no
* differences are found.
*/
public DataRow createDiff(DataRow row) {
// build a diff...
DataRow diff = null;
Iterator entries = entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
Object key = entry.getKey();
Object currentValue = entry.getValue();
Object rowValue = row.get(key);
if (!Util.nullSafeEquals(currentValue, rowValue)) {
if (diff == null) {
diff = new DataRow(this.size());
}
diff.put(key, rowValue);
}
}
return diff;
}
/**
* Creates an ObjectId from the values in the snapshot. If needed attributes are
* missing in a snapshot, CayenneRuntimeException is thrown.
*/
// TODO: andrus, 5/25/2006 - deprecate this method - it is unused
public ObjectId createObjectId(ObjEntity entity) {
return createObjectId(entity.getName(), entity.getDbEntity());
}
/**
* @deprecated since 1.2, as new portable ObjectIds can't store Java Class and store
* entity name instead. Now this method relies on default CayenneModeler
* naming convention to figure out entity name from class name. This may
* not work if the classes where mapped differently.
*/
public ObjectId createObjectId(Class objectClass, DbEntity entity) {
return createObjectId(ObjectId.entityNameFromClass(objectClass), entity);
}
/**
* @deprecated since 1.2, as new portable ObjectIds can't store Java Class and store
* entity name instead. Now this method relies on default CayenneModeler
* naming convention to figure out entity name from class name. This may
* not work if the classes where mapped differently.
*/
public ObjectId createTargetObjectId(Class targetClass, DbRelationship relationship) {
return createTargetObjectId(
ObjectId.entityNameFromClass(targetClass),
relationship);
}
// TODO: andrus, 5/25/2006 - deprecate this method - it is unused
public ObjectId createObjectId(String entityName, DbEntity entity) {
return createObjectId(entityName, entity, null);
}
/**
* Returns an ObjectId of an object on the other side of the to-one relationship, for
* this DataRow representing a source of relationship. Returns null if snapshot FK
* columns indicate a null to-one relationship.
*/
public ObjectId createTargetObjectId(String entityName, DbRelationship relationship) {
if (relationship.isToMany()) {
throw new CayenneRuntimeException("Only 'to one' can have a target ObjectId.");
}
Map target = relationship.targetPkSnapshotWithSrcSnapshot(this);
return (target != null) ? new ObjectId(entityName, target) : null;
}
/**
* Extracts PK columns prefixed with some path. If namePrefix is null or empty, no
* prefixing is done.
*
* Prefixing is useful when extracting an ObjectId of a target row from a row obtained
* via prefetching. namePrefix must omit the "db:" prefix and must end with ".", e.g.
* "TO_ARTIST.PAINTING_ARRAY."
*
*
* @since 1.2
*/
// TODO: andrus, 5/25/2006 - deprecate this method - it is unused
public ObjectId createObjectId(String entityName, DbEntity entity, String namePrefix) {
boolean prefix = namePrefix != null && namePrefix.length() > 0;
// ... handle special case - PK.size == 1
// use some not-so-significant optimizations...
List pk = entity.getPrimaryKey();
if (pk.size() == 1) {
DbAttribute attribute = (DbAttribute) pk.get(0);
String key = (prefix) ? namePrefix + attribute.getName() : attribute
.getName();
Object val = this.get(key);
if (val == null) {
throw new CayenneRuntimeException("Null value for '"
+ key
+ "'. Snapshot: "
+ this
+ ". Prefix: "
+ namePrefix);
}
// PUT without a prefix
return new ObjectId(entityName, attribute.getName(), val);
}
// ... handle generic case - PK.size > 1
Map idMap = new HashMap(pk.size() * 2);
Iterator it = pk.iterator();
while (it.hasNext()) {
DbAttribute attribute = (DbAttribute) it.next();
String key = (prefix) ? namePrefix + attribute.getName() : attribute
.getName();
Object val = this.get(key);
if (val == null) {
throw new CayenneRuntimeException("Null value for '"
+ key
+ "'. Snapshot: "
+ this
+ ". Prefix: "
+ namePrefix);
}
// PUT without a prefix
idMap.put(attribute.getName(), val);
}
return new ObjectId(entityName, idMap);
}
public String toString() {
return new ToStringBuilder(this).append("values", super.toString()).append(
" version",
version).append(" replaces", replacesVersion).toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy