org.apache.cayenne.access.ObjectStoreGraphDiff 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.cayenne.DataObject;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.PersistenceState;
import org.apache.cayenne.Persistent;
import org.apache.cayenne.graph.CompoundDiff;
import org.apache.cayenne.graph.GraphChangeHandler;
import org.apache.cayenne.graph.GraphDiff;
import org.apache.cayenne.validation.ValidationException;
import org.apache.cayenne.validation.ValidationResult;
/**
* A GraphDiff facade for the ObjectStore changes. Provides a way for the lower layers of
* the access stack to speed up processing of presorted ObjectStore diffs.
*
* @author Andrus Adamchik
* @since 1.2
*/
class ObjectStoreGraphDiff implements GraphDiff {
private ObjectStore objectStore;
private GraphDiff resolvedDiff;
ObjectStoreGraphDiff(ObjectStore objectStore) {
this.objectStore = objectStore;
preprocess(objectStore);
}
Map getChangesByObjectId() {
return objectStore.getChangesByObjectId();
}
/**
* Requires external synchronization on ObjectStore.
*/
boolean validateAndCheckNoop() {
if (getChangesByObjectId().isEmpty()) {
return true;
}
ValidationResult result = new ValidationResult();
boolean noop = true;
// build a new collection for validation as validation methods may result in
// ObjectStore modifications
Collection objectsToValidate = null;
Iterator it = getChangesByObjectId().entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
if (!((ObjectDiff) entry.getValue()).isNoop()) {
if (noop) {
noop = false;
objectsToValidate = new ArrayList();
}
// accessing objectMap directly to avoid unneeded synchronization.
objectsToValidate.add(objectStore.getNodeNoSync(entry.getKey()));
}
}
if (objectsToValidate != null) {
Iterator validationIt = objectsToValidate.iterator();
while (validationIt.hasNext()) {
DataObject object = (DataObject) validationIt.next();
switch (object.getPersistenceState()) {
case PersistenceState.NEW:
object.validateForInsert(result);
break;
case PersistenceState.MODIFIED:
object.validateForUpdate(result);
break;
case PersistenceState.DELETED:
object.validateForDelete(result);
break;
}
}
if (result.hasFailures()) {
throw new ValidationException(result);
}
}
return noop;
}
public boolean isNoop() {
if (getChangesByObjectId().isEmpty()) {
return true;
}
Iterator it = getChangesByObjectId().values().iterator();
while (it.hasNext()) {
if (!((ObjectDiff) it.next()).isNoop()) {
return false;
}
}
return true;
}
public void apply(GraphChangeHandler handler) {
resolveDiff();
resolvedDiff.apply(handler);
}
public void undo(GraphChangeHandler handler) {
resolveDiff();
resolvedDiff.undo(handler);
}
/**
* Converts diffs organized by ObjectId in a collection of diffs sorted by diffId
* (same as creation order).
*/
private void resolveDiff() {
if (resolvedDiff == null) {
CompoundDiff diff = new CompoundDiff();
Map changes = getChangesByObjectId();
if (!changes.isEmpty()) {
List allChanges = new ArrayList(changes.size() * 2);
Iterator it = changes.values().iterator();
while (it.hasNext()) {
((ObjectDiff) it.next()).appendDiffs(allChanges);
}
Collections.sort(allChanges);
diff.addAll(allChanges);
}
this.resolvedDiff = diff;
}
}
private void preprocess(ObjectStore objectStore) {
Map changes = getChangesByObjectId();
if (!changes.isEmpty()) {
Iterator it = changes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
ObjectId id = (ObjectId) entry.getKey();
Persistent object = (Persistent) objectStore.getNode(id);
// address manual id override.
ObjectId objectId = object.getObjectId();
if (!id.equals(objectId)) {
if (objectId != null) {
Map replacement = id.getReplacementIdMap();
replacement.clear();
replacement.putAll(objectId.getIdSnapshot());
}
object.setObjectId(id);
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy