org.apache.cayenne.access.util.BatchQueryUtils 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.access.util;
import java.sql.Types;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.Factory;
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataObject;
import org.apache.cayenne.DataRow;
import org.apache.cayenne.Fault;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.Entity;
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.query.BatchQuery;
import org.apache.cayenne.query.InsertBatchQuery;
import org.apache.cayenne.query.UpdateBatchQuery;
import org.apache.cayenne.util.Util;
/**
* Collection of utility methods to work with BatchQueries.
*
* @deprecated since 1.2 - this class is made non-public and moved to the access package.
* @author Andriy Shapochka, Andrus Adamchik
*/
public class BatchQueryUtils {
// not for instantiation...
private BatchQueryUtils() {
}
/**
* Utility method that returns true
if the query will update at least
* one BLOB or CLOB DbAttribute.
*
* @deprecated since 1.2
*/
public static boolean updatesLOBColumns(BatchQuery query) {
boolean isInsert = query instanceof InsertBatchQuery;
boolean isUpdate = query instanceof UpdateBatchQuery;
if (!isInsert && !isUpdate) {
return false;
}
List updatedAttributes = (isInsert)
? query.getDbAttributes()
: ((UpdateBatchQuery) query).getUpdatedAttributes();
Iterator it = updatedAttributes.iterator();
while (it.hasNext()) {
int type = ((DbAttribute) it.next()).getType();
if (type == Types.CLOB || type == Types.BLOB) {
return true;
}
}
return false;
}
/**
* @deprecated since 1.2 - unused.
*/
public static Map buildSnapshotForUpdate(DataObject o) {
DataContext context = o.getDataContext();
Map committedSnapshot = context.getObjectStore().getSnapshot(o.getObjectId());
Map currentSnapshot = o.getDataContext().currentSnapshot(o);
if (committedSnapshot == null || committedSnapshot.isEmpty()) {
return currentSnapshot;
}
Map snapshot = new HashMap(currentSnapshot.size());
Iterator it = currentSnapshot.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String attrName = (String) entry.getKey();
Object newValue = entry.getValue();
// if snapshot exists, compare old values and new values,
// only add attribute to the update clause if the value has changed
Object oldValue = committedSnapshot.get(attrName);
if (!Util.nullSafeEquals(oldValue, newValue))
snapshot.put(attrName, newValue);
}
// original snapshot can have extra keys that are missing in current snapshot
// process those
Iterator origit = committedSnapshot.entrySet().iterator();
while (origit.hasNext()) {
Map.Entry entry = (Map.Entry) origit.next();
String attrName = (String) entry.getKey();
Object oldValue = entry.getValue();
if (oldValue == null || currentSnapshot.containsKey(attrName))
continue;
snapshot.put(attrName, null);
}
return snapshot;
}
/**
* Creates a snapshot of inserted columns for a given object.
*
* @deprecated since 1.2
*/
public static Map buildSnapshotForInsert(
ObjEntity entity,
DataObject o,
DbRelationship masterDependentRel) {
return buildSnapshotForInsert(entity, o, masterDependentRel, false);
}
/**
* Creates a snapshot of inserted columns for a given object. Supports deferring value
* resolution by putting factories in the snapshot instead of real values if the value
* is not known yet.
*
* @since 1.2
*/
public static Map buildSnapshotForInsert(
ObjEntity entity,
DataObject o,
DbRelationship masterDependentRel,
boolean supportsGeneratedKeys) {
boolean isMasterDbEntity = (masterDependentRel == null);
Map map = new HashMap();
// add object attributes
Map attrMap = entity.getAttributeMap();
Iterator attributes = attrMap.entrySet().iterator();
while (attributes.hasNext()) {
Map.Entry entry = (Map.Entry) attributes.next();
String attrName = (String) entry.getKey();
ObjAttribute objAttr = (ObjAttribute) entry.getValue();
if (isMasterDbEntity && !objAttr.isCompound()) {
map.put(objAttr.getDbAttributePath(), o.readPropertyDirectly(attrName));
}
else if (!isMasterDbEntity && objAttr.isCompound()) {
DbAttribute dbAttr = objAttr.getDbAttribute();
if (dbAttr.getEntity() == masterDependentRel.getTargetEntity())
map.put(dbAttr.getName(), o.readPropertyDirectly(attrName));
}
}
// infer keys from relationships
Iterator relationships = entity.getRelationshipMap().entrySet().iterator();
while (relationships.hasNext()) {
Map.Entry entry = (Map.Entry) relationships.next();
String relName = (String) entry.getKey();
ObjRelationship rel = (ObjRelationship) entry.getValue();
if (rel.isSourceIndependentFromTargetChange()) {
continue;
}
DataObject target = (DataObject) o.readPropertyDirectly(relName);
if (target == null) {
continue;
}
Map targetKeyMap = target.getObjectId().getIdSnapshot();
// this may happen in uncommitted objects
if (targetKeyMap == null) {
continue;
}
DbRelationship dbRel;
if (isMasterDbEntity) {
dbRel = (DbRelationship) rel.getDbRelationships().get(0);
}
else {
dbRel = (DbRelationship) rel.getDbRelationships().get(1);
if (dbRel.getSourceEntity() != masterDependentRel.getTargetEntity()) {
continue;
}
}
// support deferred propagated values...
// stick a Factory in the snapshot if the value is not available yet.
Iterator joins = dbRel.getJoins().iterator();
while (joins.hasNext()) {
DbJoin join = (DbJoin) joins.next();
Object value = targetKeyMap.get(join.getTargetName());
if (value == null) {
if (supportsGeneratedKeys && join.getTarget().isGenerated()) {
// setup a factory
value = new PropagatedValueFactory(target.getObjectId(), join
.getTargetName());
}
else {
throw new CayenneRuntimeException(
"Some parts of FK are missing in snapshot, join: " + join);
}
}
map.put(join.getSourceName(), value);
}
}
// process object id map
// we should ignore any object id values if a corresponding attribute
// is a part of relationship "toMasterPK", since those values have been
// set above when db relationships where processed.
Map thisIdParts = o.getObjectId().getIdSnapshot();
if (thisIdParts != null) {
if (!isMasterDbEntity) {
thisIdParts = masterDependentRel
.targetPkSnapshotWithSrcSnapshot(thisIdParts);
}
// put only thise that do not exist in the map
Iterator itm = thisIdParts.entrySet().iterator();
while (itm.hasNext()) {
Map.Entry entry = (Map.Entry) itm.next();
Object nextKey = entry.getKey();
if (!map.containsKey(nextKey))
map.put(nextKey, entry.getValue());
}
}
return map;
}
private static String getTargetDbAttributeName(
String srcDbAttributeName,
DbRelationship masterDependentRel) {
for (Iterator i = masterDependentRel.getJoins().iterator(); i.hasNext();) {
DbJoin join = (DbJoin) i.next();
if (srcDbAttributeName.equals(join.getSourceName()))
return join.getTargetName();
}
return null;
}
/**
* Creates a snapshot of updated columns for a given object.
*
* @deprecated since 1.2 - unused.
*/
public static Map buildSnapshotForUpdate(
ObjEntity entity,
DataObject o,
DbRelationship masterDependentRel) {
return buildSnapshotForUpdate(entity, o, masterDependentRel, false);
}
/**
* Creates a snapshot of updated columns for a given object.
*
* @since 1.2
*/
public static Map buildSnapshotForUpdate(
ObjEntity entity,
DataObject o,
DbRelationship masterDependentRel,
boolean supportsGeneratedKeys) {
boolean isMasterDbEntity = (masterDependentRel == null);
DataContext context = o.getDataContext();
DataRow committedSnapshot = context.getObjectStore().getSnapshot(o.getObjectId());
DataRow currentSnapshot = o.getDataContext().currentSnapshot(o);
Map snapshot = new HashMap(currentSnapshot.size());
// no committed snapshot (why?) - just use values from current snapshot
if (committedSnapshot == null || committedSnapshot.isEmpty()) {
Iterator i = currentSnapshot.entrySet().iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
String dbAttrPath = (String) entry.getKey();
boolean compoundDbAttr = dbAttrPath.indexOf(Entity.PATH_SEPARATOR) > 0;
Object newValue = entry.getValue();
if (isMasterDbEntity && !compoundDbAttr) {
snapshot.put(dbAttrPath, newValue);
}
else if (!isMasterDbEntity && compoundDbAttr) {
Iterator pathIterator = entity.getDbEntity().resolvePathComponents(
dbAttrPath);
if (pathIterator.hasNext()
&& masterDependentRel.equals(pathIterator.next())) {
DbAttribute dbAttr = (DbAttribute) pathIterator.next();
snapshot.put(dbAttr.getName(), newValue);
}
}
else if (!isMasterDbEntity && !compoundDbAttr) {
String pkAttrName = getTargetDbAttributeName(
dbAttrPath,
masterDependentRel);
if (pkAttrName != null)
snapshot.put(pkAttrName, newValue);
}
}
return snapshot;
}
Iterator it = currentSnapshot.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String dbAttrPath = (String) entry.getKey();
boolean compoundDbAttr = dbAttrPath.indexOf(Entity.PATH_SEPARATOR) > 0;
Object newValue = entry.getValue();
// ... if not for flattened attributes, we could've used
// DataRow.createDiff()..
// if snapshot exists, compare old values and new values,
// only add attribute to the update clause if the value has changed
Object oldValue = committedSnapshot.get(dbAttrPath);
if (!Util.nullSafeEquals(oldValue, newValue)) {
if (!isMasterDbEntity) {
if (compoundDbAttr) {
Iterator pathIterator = entity
.getDbEntity()
.resolvePathComponents(dbAttrPath);
if (pathIterator.hasNext()
&& masterDependentRel.equals(pathIterator.next())) {
DbAttribute dbAttr = (DbAttribute) pathIterator.next();
snapshot.put(dbAttr.getName(), newValue);
}
}
else {
String pkAttrName = getTargetDbAttributeName(
dbAttrPath,
masterDependentRel);
if (pkAttrName != null)
snapshot.put(pkAttrName, newValue);
}
}
else if (!compoundDbAttr) {
snapshot.put(dbAttrPath, newValue);
}
}
}
// original snapshot can have extra keys that are missing in current snapshot
// process those
Iterator origit = committedSnapshot.entrySet().iterator();
while (origit.hasNext()) {
Map.Entry entry = (Map.Entry) origit.next();
String dbAttrPath = (String) entry.getKey();
if (entry.getValue() == null || currentSnapshot.containsKey(dbAttrPath)) {
continue;
}
boolean compoundDbAttr = dbAttrPath.indexOf(Entity.PATH_SEPARATOR) > 0;
if (isMasterDbEntity && !compoundDbAttr) {
snapshot.put(dbAttrPath, null);
}
else if (!isMasterDbEntity && compoundDbAttr) {
Iterator pathIterator = entity.getDbEntity().resolvePathComponents(
dbAttrPath);
if (pathIterator.hasNext()
&& masterDependentRel.equals(pathIterator.next())) {
DbAttribute dbAttr = (DbAttribute) pathIterator.next();
snapshot.put(dbAttr.getName(), null);
}
}
else if (!isMasterDbEntity && !compoundDbAttr) {
String pkAttrName = getTargetDbAttributeName(
dbAttrPath,
masterDependentRel);
if (pkAttrName != null)
snapshot.put(pkAttrName, null);
}
}
// there may be FKs with deferred propagation. They will be present as nulls in
// the snapshot.... need to setup factories to resolve such values on later on
// demand
if (supportsGeneratedKeys) {
Iterator relationships = entity.getRelationships().iterator();
while (relationships.hasNext()) {
ObjRelationship rel = (ObjRelationship) relationships.next();
if (rel.isSourceIndependentFromTargetChange()) {
continue;
}
Object target = o.readPropertyDirectly(rel.getName());
if (target == null || target instanceof Fault) {
continue;
}
ObjectId targetId = ((DataObject) target).getObjectId();
Map targetKeyMap = targetId.getIdSnapshot();
// this may happen in uncommitted objects
if (targetKeyMap == null) {
continue;
}
DbRelationship dbRel;
if (isMasterDbEntity) {
dbRel = (DbRelationship) rel.getDbRelationships().get(0);
}
else {
dbRel = (DbRelationship) rel.getDbRelationships().get(1);
if (dbRel.getSourceEntity() != masterDependentRel.getTargetEntity()) {
continue;
}
}
// support deferred propagated values...
// stick a Factory in the snapshot if the value is not available yet.
Iterator joins = dbRel.getJoins().iterator();
while (joins.hasNext()) {
DbJoin join = (DbJoin) joins.next();
if (snapshot.get(join.getSourceName()) == null) {
if (join.getTarget().isGenerated()) {
// setup a factory
Object value = new PropagatedValueFactory(targetId, join
.getTargetName());
snapshot.put(join.getSourceName(), value);
}
}
}
}
}
return snapshot;
}
final static class PropagatedValueFactory implements Factory {
ObjectId masterID;
String masterKey;
PropagatedValueFactory(ObjectId masterID, String masterKey) {
this.masterID = masterID;
this.masterKey = masterKey;
}
public Object create() {
if (!masterID.isReplacementIdAttached()) {
throw new CayenneRuntimeException("Deferred propagated key ("
+ masterKey
+ ") wasn't generated for object with ID "
+ masterID);
}
Map replacementId = masterID.getReplacementIdMap();
Object value = replacementId.get(masterKey);
if (value == null) {
throw new CayenneRuntimeException("Deferred propagated key ("
+ masterKey
+ ") wasn't generated for object with ID "
+ masterID);
}
return value;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy