Search in sources :

Example 21 with PropertyVisitor

use of org.apache.cayenne.reflect.PropertyVisitor in project cayenne by apache.

the class ObjectContextDeleteAction method processDeleteRules.

private void processDeleteRules(final Persistent object, int oldState) throws DeleteDenyException {
    ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(object.getObjectId().getEntityName());
    for (final ObjRelationship relationship : descriptor.getEntity().getRelationships()) {
        boolean processFlattened = relationship.isFlattened() && relationship.isToDependentEntity() && !relationship.isReadOnly();
        // first check for no action... bail out if no flattened processing is needed
        if (relationship.getDeleteRule() == DeleteRule.NO_ACTION && !processFlattened) {
            continue;
        }
        ArcProperty property = (ArcProperty) descriptor.getProperty(relationship.getName());
        final Collection<Persistent> relatedObjects = toCollection(property.readProperty(object));
        // no related object, bail out
        if (relatedObjects.size() == 0) {
            continue;
        }
        // process DENY rule first...
        if (relationship.getDeleteRule() == DeleteRule.DENY) {
            object.setPersistenceState(oldState);
            String message = relatedObjects.size() == 1 ? "1 related object" : relatedObjects.size() + " related objects";
            throw new DeleteDenyException(object, relationship.getName(), message);
        }
        // object graph
        if (processFlattened) {
            for (Persistent relatedObject : relatedObjects) {
                context.getGraphManager().arcDeleted(object.getObjectId(), relatedObject.getObjectId(), relationship.getName());
            }
        }
        // process remaining rules
        switch(relationship.getDeleteRule()) {
            case DeleteRule.NO_ACTION:
                break;
            case DeleteRule.NULLIFY:
                ArcProperty reverseArc = property.getComplimentaryReverseArc();
                if (reverseArc == null) {
                    // nothing we can do here
                    break;
                }
                reverseArc.visit(new PropertyVisitor() {

                    public boolean visitAttribute(AttributeProperty property) {
                        return false;
                    }

                    public boolean visitToMany(ToManyProperty property) {
                        for (Persistent relatedObject : relatedObjects) {
                            property.removeTarget(relatedObject, object, true);
                        }
                        return false;
                    }

                    public boolean visitToOne(ToOneProperty property) {
                        // nullify the reverse relationship
                        for (Persistent relatedObject : relatedObjects) {
                            property.setTarget(relatedObject, null, true);
                        }
                        return false;
                    }
                });
                break;
            case DeleteRule.CASCADE:
                // Delete all related objects
                for (Persistent relatedObject : relatedObjects) {
                    performDelete(relatedObject);
                }
                break;
            default:
                object.setPersistenceState(oldState);
                throw new CayenneRuntimeException("Invalid delete rule %s", relationship.getDeleteRule());
        }
    }
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ArcProperty(org.apache.cayenne.reflect.ArcProperty) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor)

Example 22 with PropertyVisitor

use of org.apache.cayenne.reflect.PropertyVisitor in project cayenne by apache.

the class DataContext method currentSnapshot.

/**
 * Returns a DataRow reflecting current, possibly uncommitted, object state.
 * <p>
 * <strong>Warning:</strong> This method will return a partial snapshot if
 * an object or one of its related objects that propagate their keys to this
 * object have temporary ids. DO NOT USE this method if you expect a DataRow
 * to represent a complete object state.
 * </p>
 *
 * @since 1.1
 */
public DataRow currentSnapshot(final Persistent object) {
    // for a HOLLOW object return snapshot from cache
    if (object.getPersistenceState() == PersistenceState.HOLLOW && object.getObjectContext() != null) {
        return getObjectStore().getSnapshot(object.getObjectId());
    }
    ObjEntity entity = getEntityResolver().getObjEntity(object);
    final ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(entity.getName());
    final DataRow snapshot = new DataRow(10);
    snapshot.setEntityName(entity.getName());
    descriptor.visitProperties(new PropertyVisitor() {

        public boolean visitAttribute(AttributeProperty property) {
            ObjAttribute objAttr = property.getAttribute();
            // processing compound attributes correctly
            snapshot.put(objAttr.getDbAttributePath(), property.readPropertyDirectly(object));
            return true;
        }

        public boolean visitToMany(ToManyProperty property) {
            // do nothing
            return true;
        }

        public boolean visitToOne(ToOneProperty property) {
            ObjRelationship rel = property.getRelationship();
            // if target doesn't propagates its key value, skip it
            if (rel.isSourceIndependentFromTargetChange()) {
                return true;
            }
            Object targetObject = property.readPropertyDirectly(object);
            if (targetObject == null) {
                return true;
            }
            // to avoid unneeded fault triggering
            if (targetObject instanceof Fault) {
                DataRow storedSnapshot = getObjectStore().getSnapshot(object.getObjectId());
                if (storedSnapshot == null) {
                    throw new CayenneRuntimeException("No matching objects found for ObjectId %s" + ". Object may have been deleted externally.", object.getObjectId());
                }
                DbRelationship dbRel = rel.getDbRelationships().get(0);
                for (DbJoin join : dbRel.getJoins()) {
                    String key = join.getSourceName();
                    snapshot.put(key, storedSnapshot.get(key));
                }
                return true;
            }
            // target is resolved and we have an FK->PK to it,
            // so extract it from target...
            Persistent target = (Persistent) targetObject;
            Map<String, Object> idParts = target.getObjectId().getIdSnapshot();
            // this method.
            if (idParts.isEmpty()) {
                return true;
            }
            DbRelationship dbRel = rel.getDbRelationships().get(0);
            Map<String, Object> fk = dbRel.srcFkSnapshotWithTargetSnapshot(idParts);
            snapshot.putAll(fk);
            return true;
        }
    });
    // 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<String, Object> thisIdParts = object.getObjectId().getIdSnapshot();
    if (thisIdParts != null) {
        // put only those that do not exist in the map
        for (Map.Entry<String, Object> entry : thisIdParts.entrySet()) {
            String nextKey = entry.getKey();
            if (!snapshot.containsKey(nextKey)) {
                snapshot.put(nextKey, entry.getValue());
            }
        }
    }
    return snapshot;
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ClassDescriptor(org.apache.cayenne.reflect.ClassDescriptor) ObjAttribute(org.apache.cayenne.map.ObjAttribute) CayenneRuntimeException(org.apache.cayenne.CayenneRuntimeException) Fault(org.apache.cayenne.Fault) Persistent(org.apache.cayenne.Persistent) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) DataRow(org.apache.cayenne.DataRow) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty) ObjEntity(org.apache.cayenne.map.ObjEntity) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) DbRelationship(org.apache.cayenne.map.DbRelationship) DbJoin(org.apache.cayenne.map.DbJoin) DataObject(org.apache.cayenne.DataObject) Map(java.util.Map) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor)

Example 23 with PropertyVisitor

use of org.apache.cayenne.reflect.PropertyVisitor in project cayenne by apache.

the class DataContextMergeHandler method arcChanged.

// works the same for add and remove as long as we don't get too smart per TODO below.
private void arcChanged(Object nodeId, Object targetNodeId, Object arcId) {
    final Persistent source = (Persistent) context.getGraphManager().getNode(nodeId);
    if (source != null && source.getPersistenceState() != PersistenceState.HOLLOW) {
        final int state = source.getPersistenceState();
        PropertyDescriptor p = propertyForId(nodeId, arcId.toString());
        p.visit(new PropertyVisitor() {

            public boolean visitAttribute(AttributeProperty property) {
                return false;
            }

            public boolean visitToMany(ToManyProperty property) {
                if (state == PersistenceState.COMMITTED) {
                    property.invalidate(source);
                }
                return false;
            }

            public boolean visitToOne(ToOneProperty property) {
                if (state == PersistenceState.COMMITTED) {
                    property.invalidate(source);
                }
                // of dirty objects. See DataRowUtils for details.
                return false;
            }
        });
    }
}
Also used : PropertyDescriptor(org.apache.cayenne.reflect.PropertyDescriptor) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) Persistent(org.apache.cayenne.Persistent) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty)

Example 24 with PropertyVisitor

use of org.apache.cayenne.reflect.PropertyVisitor in project cayenne by apache.

the class DataRowUtils method forceMergeWithSnapshot.

static void forceMergeWithSnapshot(final DataContext context, ClassDescriptor descriptor, final Persistent object, final DataRow snapshot) {
    final ObjectDiff diff = context.getObjectStore().getChangesByObjectId().get(object.getObjectId());
    descriptor.visitProperties(new PropertyVisitor() {

        public boolean visitAttribute(AttributeProperty property) {
            String dbAttrPath = property.getAttribute().getDbAttributePath();
            // supports merging of partial snapshots...
            // check for null is cheaper than double lookup
            // for a key... so check for partial snapshot
            // only if the value is null
            Object newValue = snapshot.get(dbAttrPath);
            if (newValue != null || snapshot.containsKey(dbAttrPath)) {
                Object curValue = property.readPropertyDirectly(object);
                Object oldValue = diff != null ? diff.getSnapshotValue(property.getName()) : null;
                // otherwise leave it alone
                if (Util.nullSafeEquals(curValue, oldValue) && !Util.nullSafeEquals(newValue, curValue)) {
                    property.writePropertyDirectly(object, oldValue, newValue);
                }
            }
            return true;
        }

        public boolean visitToMany(ToManyProperty property) {
            // noop - nothing to merge
            return true;
        }

        public boolean visitToOne(ToOneProperty property) {
            ObjRelationship relationship = property.getRelationship();
            if (relationship.isToPK()) {
                // otherwise leave it alone
                if (!isToOneTargetModified(property, object, diff)) {
                    DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
                    // snapshots
                    if (hasFK(dbRelationship, snapshot)) {
                        ObjectId id = snapshot.createTargetObjectId(relationship.getTargetEntityName(), dbRelationship);
                        if (diff == null || !diff.containsArcSnapshot(relationship.getName()) || !Util.nullSafeEquals(id, diff.getArcSnapshotValue(relationship.getName()))) {
                            if (id == null) {
                                property.writeProperty(object, null, null);
                            } else {
                                // .. must turn to fault instead
                                if (!relationship.isSourceDefiningTargetPrecenseAndType(context.getEntityResolver())) {
                                    property.invalidate(object);
                                } else {
                                    property.writeProperty(object, null, context.findOrCreateObject(id));
                                }
                            }
                        }
                    }
                }
            }
            return true;
        }
    });
}
Also used : ObjRelationship(org.apache.cayenne.map.ObjRelationship) ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) ObjectId(org.apache.cayenne.ObjectId) DbRelationship(org.apache.cayenne.map.DbRelationship) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty)

Example 25 with PropertyVisitor

use of org.apache.cayenne.reflect.PropertyVisitor in project cayenne by apache.

the class ObjectDiff method isNoop.

/**
 * Checks whether at least a single property is modified.
 */
@Override
public boolean isNoop() {
    // if we have no baseline to compare with, assume that there are changes
    if (snapshot == null) {
        return false;
    }
    if (flatIds != null && !flatIds.isEmpty()) {
        return false;
    }
    if (phantomFks != null && !phantomFks.isEmpty()) {
        return false;
    }
    int state = object.getPersistenceState();
    if (state == PersistenceState.NEW || state == PersistenceState.DELETED) {
        return false;
    }
    // check phantom mods
    final boolean[] modFound = new boolean[1];
    getClassDescriptor().visitProperties(new PropertyVisitor() {

        @Override
        public boolean visitAttribute(AttributeProperty property) {
            Object oldValue = snapshot.get(property.getName());
            Object newValue = property.readProperty(object);
            if (!Util.nullSafeEquals(oldValue, newValue)) {
                modFound[0] = true;
            }
            return !modFound[0];
        }

        @Override
        public boolean visitToMany(ToManyProperty property) {
            // flattened changes
            return true;
        }

        @Override
        public boolean visitToOne(ToOneProperty property) {
            if (arcSnapshot == null) {
                return true;
            }
            Object newValue = property.readPropertyDirectly(object);
            if (newValue instanceof Fault) {
                return true;
            }
            Object oldValue = arcSnapshot.get(property.getName());
            if (!Util.nullSafeEquals(oldValue, newValue != null ? ((Persistent) newValue).getObjectId() : null)) {
                modFound[0] = true;
            }
            return !modFound[0];
        }
    });
    return !modFound[0];
}
Also used : ToManyProperty(org.apache.cayenne.reflect.ToManyProperty) Fault(org.apache.cayenne.Fault) Persistent(org.apache.cayenne.Persistent) AttributeProperty(org.apache.cayenne.reflect.AttributeProperty) PropertyVisitor(org.apache.cayenne.reflect.PropertyVisitor) ToOneProperty(org.apache.cayenne.reflect.ToOneProperty)

Aggregations

AttributeProperty (org.apache.cayenne.reflect.AttributeProperty)28 PropertyVisitor (org.apache.cayenne.reflect.PropertyVisitor)28 ToManyProperty (org.apache.cayenne.reflect.ToManyProperty)28 ToOneProperty (org.apache.cayenne.reflect.ToOneProperty)28 ClassDescriptor (org.apache.cayenne.reflect.ClassDescriptor)21 ArcProperty (org.apache.cayenne.reflect.ArcProperty)10 Persistent (org.apache.cayenne.Persistent)8 DbRelationship (org.apache.cayenne.map.DbRelationship)8 ObjAttribute (org.apache.cayenne.map.ObjAttribute)8 ObjRelationship (org.apache.cayenne.map.ObjRelationship)8 PropertyDescriptor (org.apache.cayenne.reflect.PropertyDescriptor)8 DbJoin (org.apache.cayenne.map.DbJoin)7 ObjEntity (org.apache.cayenne.map.ObjEntity)7 CayenneRuntimeException (org.apache.cayenne.CayenneRuntimeException)6 ObjectId (org.apache.cayenne.ObjectId)6 DbAttribute (org.apache.cayenne.map.DbAttribute)6 HashSet (java.util.HashSet)4 Map (java.util.Map)4 ArrayList (java.util.ArrayList)3 Collection (java.util.Collection)3