You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/05/07 22:08:19 UTC
svn commit: r404834 - in
/incubator/cayenne/main/trunk/cayenne/cayenne-java/src:
cayenne/java/org/objectstyle/cayenne/
cayenne/java/org/objectstyle/cayenne/access/
tests/java/org/objectstyle/cayenne/access/ tests/resources/dml/
Author: aadamchik
Date: Sun May 7 13:08:17 2006
New Revision: 404834
URL: http://svn.apache.org/viewcvs?rev=404834&view=rev
Log:
CAY-544 - adding correct fault handling
Added:
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataContextFaults.java
Modified:
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/Fault.java
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataDomain.java
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/ObjectDiff.java
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/objectstyle/cayenne/access/DataContextExtrasTst.java
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/resources/dml/access.DataContextExtrasTst.xml
Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/Fault.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/Fault.java?rev=404834&r1=404833&r2=404834&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/Fault.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/Fault.java Sun May 7 13:08:17 2006
@@ -56,10 +56,6 @@
package org.objectstyle.cayenne;
import java.io.Serializable;
-import java.util.List;
-
-import org.objectstyle.cayenne.access.ToManyList;
-import org.objectstyle.cayenne.query.RelationshipQuery;
/**
* Represents a placeholder for an unresolved relationship from a source object. Fault is
@@ -70,13 +66,12 @@
* @since 1.1
* @author Andrei Adamchik
*/
-
// TODO: serialization of faults should take into account the fact that
// they are used as singletons to avoid duplicate creation on deserialization
public abstract class Fault implements Serializable {
- protected static final Fault toOneFault = new ToOneFault();
- protected static final Fault toManyFault = new ToManyFault();
+ protected static Fault toOneFault;
+ protected static Fault toManyFault;
public static Fault getToOneFault() {
return toOneFault;
@@ -93,46 +88,4 @@
* Returns an object for a given source object and relationship.
*/
public abstract Object resolveFault(Persistent sourceObject, String relationshipName);
-
- final static class ToManyFault extends Fault {
-
- /**
- * Resolves this fault to a List of objects.
- */
- public Object resolveFault(Persistent sourceObject, String relationshipName) {
- return new ToManyList(sourceObject, relationshipName);
- }
- }
-
- final static class ToOneFault extends Fault {
-
- /**
- * Resolves this fault to a DataObject.
- */
- public Object resolveFault(Persistent sourceObject, String relationshipName) {
- ObjectContext context = sourceObject.getObjectContext();
-
- RelationshipQuery query = new RelationshipQuery(
- sourceObject.getObjectId(),
- relationshipName,
- false);
-
- List objects = context.performQuery(query);
-
- if (objects.isEmpty()) {
- return null;
- }
- else if (objects.size() == 1) {
- return objects.get(0);
- }
- else {
- throw new CayenneRuntimeException("Error resolving to-one fault. "
- + "More than one object found. "
- + "Source Id: "
- + sourceObject.getObjectId()
- + ", relationship: "
- + relationshipName);
- }
- }
- }
}
Added: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataContextFaults.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataContextFaults.java?rev=404834&view=auto
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataContextFaults.java (added)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataContextFaults.java Sun May 7 13:08:17 2006
@@ -0,0 +1,162 @@
+/* ====================================================================
+ *
+ * The ObjectStyle Group Software License, version 1.1
+ * ObjectStyle Group - http://objectstyle.org/
+ *
+ * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
+ * of the software. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any,
+ * must include the following acknowlegement:
+ * "This product includes software developed by independent contributors
+ * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
+ * or promote products derived from this software without prior written
+ * permission. For written permission, email
+ * "andrus at objectstyle dot org".
+ *
+ * 5. Products derived from this software may not be called "ObjectStyle"
+ * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
+ * names without prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals and hosted on ObjectStyle Group web site. For more
+ * information on the ObjectStyle Group, please see
+ * <http://objectstyle.org/>.
+ */
+package org.objectstyle.cayenne.access;
+
+import java.util.List;
+
+import org.objectstyle.cayenne.CayenneRuntimeException;
+import org.objectstyle.cayenne.Fault;
+import org.objectstyle.cayenne.ObjectContext;
+import org.objectstyle.cayenne.PersistenceState;
+import org.objectstyle.cayenne.Persistent;
+import org.objectstyle.cayenne.query.RelationshipQuery;
+
+/**
+ * A helper class that initializes server-side fault singletons.
+ *
+ * @since 1.2
+ * @author Andrus Adamchik
+ */
+class DataContextFaults {
+
+ /**
+ * Resets super singletons.
+ */
+ static void init() {
+ ToManyFault.init();
+ ToOneFault.init();
+ }
+
+ final static class ToManyFault extends Fault {
+
+ /**
+ * Resets super singletons.
+ */
+ static void init() {
+ if (Fault.toManyFault == null) {
+ Fault.toManyFault = new ToManyFault();
+ }
+ }
+
+ /**
+ * Resolves this fault to a List of objects.
+ */
+ public Object resolveFault(Persistent sourceObject, String relationshipName) {
+ return new ToManyList(sourceObject, relationshipName);
+ }
+ }
+
+ final static class ToOneFault extends Fault {
+
+ /**
+ * Resets super singletons.
+ */
+ static void init() {
+ if (Fault.toOneFault == null) {
+ Fault.toOneFault = new ToOneFault();
+ }
+ }
+
+ /**
+ * Resolves this fault to a DataObject.
+ */
+ public Object resolveFault(Persistent sourceObject, String relationshipName) {
+ Object target = doResolveFault(sourceObject, relationshipName);
+
+ // must update the diff for the object
+ int state = sourceObject.getPersistenceState();
+ ObjectContext context = sourceObject.getObjectContext();
+ if ((state == PersistenceState.MODIFIED || state == PersistenceState.DELETED)
+ && context instanceof DataContext) {
+
+ ObjectDiff diff = (ObjectDiff) ((DataContext) context)
+ .getObjectStore()
+ .getChangesByObjectId()
+ .get(sourceObject.getObjectId());
+
+ if (diff != null) {
+ diff.updateArcSnapshot(relationshipName, (Persistent) target);
+ }
+ }
+
+ return target;
+ }
+
+ Object doResolveFault(Persistent sourceObject, String relationshipName) {
+ RelationshipQuery query = new RelationshipQuery(
+ sourceObject.getObjectId(),
+ relationshipName,
+ false);
+
+ List objects = sourceObject.getObjectContext().performQuery(query);
+
+ if (objects.isEmpty()) {
+ return null;
+ }
+ else if (objects.size() == 1) {
+ return objects.get(0);
+ }
+ else {
+ throw new CayenneRuntimeException("Error resolving to-one fault. "
+ + "More than one object found. "
+ + "Source Id: "
+ + sourceObject.getObjectId()
+ + ", relationship: "
+ + relationshipName);
+ }
+ }
+ }
+}
Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataDomain.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataDomain.java?rev=404834&r1=404833&r2=404834&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataDomain.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/DataDomain.java Sun May 7 13:08:17 2006
@@ -147,6 +147,7 @@
* Creates a DataDomain and assigns it a name.
*/
public DataDomain(String name) {
+ DataContextFaults.init();
setName(name);
resetProperties();
}
Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/ObjectDiff.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/ObjectDiff.java?rev=404834&r1=404833&r2=404834&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/ObjectDiff.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/access/ObjectDiff.java Sun May 7 13:08:17 2006
@@ -7,6 +7,7 @@
import java.util.Map;
import org.objectstyle.cayenne.CayenneRuntimeException;
+import org.objectstyle.cayenne.Fault;
import org.objectstyle.cayenne.ObjectId;
import org.objectstyle.cayenne.PersistenceState;
import org.objectstyle.cayenne.Persistent;
@@ -50,6 +51,10 @@
|| state == PersistenceState.DELETED
|| state == PersistenceState.MODIFIED) {
+ ObjEntity entity = objectStore.getContext().getEntityResolver().getObjEntity(
+ object.getObjectId().getEntityName());
+ final boolean lock = entity.getLockType() == ObjEntity.LOCK_TYPE_OPTIMISTIC;
+
this.snapshot = new HashMap();
this.arcSnapshot = new HashMap();
@@ -65,7 +70,17 @@
}
public boolean visitSingleObjectArc(SingleObjectArcProperty property) {
- takeSingleObjectArcSnapshot(property, object);
+
+ // eagerly resolve optimistically locked relationships
+ Object target = lock ? property.readProperty(object) : property
+ .readPropertyDirectly(object);
+
+ if (target instanceof Persistent) {
+ target = ((Persistent) target).getObjectId();
+ }
+ // else - null || Fault
+
+ arcSnapshot.put(property.getName(), target);
return true;
}
});
@@ -77,7 +92,19 @@
}
ObjectId getArcSnapshotValue(String propertyName) {
- return arcSnapshot != null ? (ObjectId) arcSnapshot.get(propertyName) : null;
+ Object value = arcSnapshot != null
+ ? arcSnapshot.get(propertyName)
+ : null;
+
+ if (value instanceof Fault) {
+ Persistent source = (Persistent) objectStore.getNode(nodeId);
+ Persistent target = (Persistent) ((Fault) value).resolveFault(source, propertyName);
+
+ value = target != null ? target.getObjectId() : null;
+ arcSnapshot.put(propertyName, value);
+ }
+
+ return (ObjectId) value;
}
boolean containsArcSnapshot(String propertyName) {
@@ -113,7 +140,59 @@
otherDiffs.add(diff);
if (diff instanceof ArcOperation) {
- takeArcSnapshot((ArcOperation) diff);
+
+ ArcOperation arcDiff = (ArcOperation) diff;
+
+ if (snapshot == null) {
+ return;
+ }
+
+ Object targetId = arcDiff.getTargetNodeId();
+ String arcId = arcDiff.getArcId().toString();
+
+ Persistent object = (Persistent) objectStore.getNode(nodeId);
+ Property property = getClassDescriptor().getProperty(arcId);
+
+ // note that some collection properties implement 'SingleObjectArcProperty',
+ // so we cant't do 'instanceof SingleObjectArcProperty'
+ // TODO: andrus, 3.22.2006 - should we consider this a bug?
+
+ if (property instanceof CollectionProperty) {
+
+ // record flattened op changes
+ ObjEntity entity = objectStore.context.getEntityResolver().getObjEntity(
+ object.getObjectId().getEntityName());
+
+ ObjRelationship relationship = (ObjRelationship) entity
+ .getRelationship(property.getName());
+ if (relationship.isFlattened()) {
+
+ if (flatIds == null) {
+ flatIds = new HashMap();
+ }
+
+ ArcOperation oldOp = (ArcOperation) flatIds.put(arcDiff, arcDiff);
+
+ // "delete" cancels "create" and vice versa...
+ if (oldOp != null && oldOp.isDelete() != arcDiff.isDelete()) {
+ flatIds.remove(arcDiff);
+ }
+ }
+ }
+ else if (property instanceof SingleObjectArcProperty) {
+
+ if (currentArcSnapshot == null) {
+ currentArcSnapshot = new HashMap();
+ }
+
+ currentArcSnapshot.put(arcId, targetId);
+ }
+ else {
+ String message = (property == null)
+ ? "No property for arcId " + arcId
+ : "Unrecognized property for arcId " + arcId + ": " + property;
+ throw new CayenneRuntimeException(message);
+ }
}
}
@@ -164,11 +243,15 @@
return true;
}
- Object oldValue = arcSnapshot.get(property.getName());
- Persistent newValue = (Persistent) property.readProperty(object);
+ Object newValue = property.readPropertyDirectly(object);
+ if (newValue instanceof Fault) {
+ return true;
+ }
- if (!Util.nullSafeEquals(oldValue, newValue != null ? newValue
- .getObjectId() : null)) {
+ Object oldValue = arcSnapshot.get(property.getName());
+ if (!Util.nullSafeEquals(oldValue, newValue != null
+ ? ((Persistent) newValue).getObjectId()
+ : null)) {
modFound[0] = true;
}
@@ -240,71 +323,15 @@
});
}
- private void takeArcSnapshot(ArcOperation operation) {
-
- if (snapshot == null) {
- return;
- }
-
- Object targetId = operation.getTargetNodeId();
- String arcId = operation.getArcId().toString();
-
- Persistent object = (Persistent) objectStore.getNode(nodeId);
- Property property = getClassDescriptor().getProperty(arcId);
-
- // note that some collection properties implement 'SingleObjectArcProperty',
- // so we cant't do 'instanceof SingleObjectArcProperty'
- // TODO: andrus, 3.22.2006 - should we consider this a bug?
-
- if (property instanceof CollectionProperty) {
-
- // record flattened op changes
- ObjEntity entity = objectStore.context.getEntityResolver().getObjEntity(
- object.getObjectId().getEntityName());
-
- ObjRelationship relationship = (ObjRelationship) entity
- .getRelationship(property.getName());
- if (relationship.isFlattened()) {
-
- if (flatIds == null) {
- flatIds = new HashMap();
- }
-
- ArcOperation oldOp = (ArcOperation) flatIds.put(operation, operation);
-
- // "delete" cancels "create" and vice versa...
- if (oldOp != null && oldOp.isDelete() != operation.isDelete()) {
- flatIds.remove(operation);
- }
- }
- }
- else if (property instanceof SingleObjectArcProperty) {
- takeSingleObjectArcSnapshot(property, object);
-
- if (currentArcSnapshot == null) {
- currentArcSnapshot = new HashMap();
- }
-
- currentArcSnapshot.put(arcId, targetId);
- }
- else {
- String message = (property == null)
- ? "No property for arcId " + arcId
- : "Unrecognized property for arcId " + arcId + ": " + property;
- throw new CayenneRuntimeException(message);
- }
- }
-
- void takeSingleObjectArcSnapshot(Property property, Persistent object) {
+ /**
+ * This is used to update faults.
+ */
+ void updateArcSnapshot(String propertyName, Persistent object) {
if (arcSnapshot == null) {
arcSnapshot = new HashMap();
}
- if (!arcSnapshot.containsKey(property.getName())) {
- Persistent oldTarget = (Persistent) property.readProperty(object);
- arcSnapshot.put(property.getName(), oldTarget != null ? oldTarget
- .getObjectId() : null);
- }
+ arcSnapshot.put(propertyName, object != null ? object.getObjectId() : null);
}
ClassDescriptor getClassDescriptor() {
Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/objectstyle/cayenne/access/DataContextExtrasTst.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/objectstyle/cayenne/access/DataContextExtrasTst.java?rev=404834&r1=404833&r2=404834&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/objectstyle/cayenne/access/DataContextExtrasTst.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/objectstyle/cayenne/access/DataContextExtrasTst.java Sun May 7 13:08:17 2006
@@ -322,9 +322,9 @@
assertFalse(a1.isValidateForSaveCalled());
}
- public void testPhantomModificationsValidate2() throws Exception {
+ public void testPhantomModificationsValidateToOne() throws Exception {
deleteTestData();
- createTestData("testPhantomModification2");
+ createTestData("testPhantomModificationsValidateToOne");
DataContext context = createDataContext();
List objects = context.performQuery(new SelectQuery(Painting.class));
@@ -334,7 +334,25 @@
p1.resetValidationFlags();
context.commitChanges();
- assertFalse(p1.isValidateForSaveCalled());
+ assertFalse("To-one relationship presence caused incorrect validation call.", p1
+ .isValidateForSaveCalled());
+ }
+
+ public void testValidateOnToManyChange() throws Exception {
+ deleteTestData();
+ createTestData("testValidateOnToManyChange");
+ DataContext context = createDataContext();
+
+ List objects = context.performQuery(new SelectQuery(Artist.class));
+ Artist a1 = (Artist) objects.get(0);
+
+ Painting p1 = (Painting) context.newObject(Painting.class);
+ p1.setPaintingTitle("XXX");
+ a1.addToPaintingArray(p1);
+ a1.resetValidationFlags();
+ context.commitChanges();
+
+ assertFalse(a1.isValidateForSaveCalled());
}
public void testPhantomAttributeModificationCommit() throws Exception {
Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/resources/dml/access.DataContextExtrasTst.xml
URL: http://svn.apache.org/viewcvs/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/resources/dml/access.DataContextExtrasTst.xml?rev=404834&r1=404833&r2=404834&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/resources/dml/access.DataContextExtrasTst.xml (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/resources/dml/access.DataContextExtrasTst.xml Sun May 7 13:08:17 2006
@@ -38,11 +38,18 @@
</list>
</constructor-arg>
</bean>
- <bean id="testPhantomModification2" class="java.util.ArrayList">
+ <bean id="testPhantomModificationsValidateToOne" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="A1"/>
<ref bean="P11"/>
+ </list>
+ </constructor-arg>
+ </bean>
+ <bean id="testValidateOnToManyChange" class="java.util.ArrayList">
+ <constructor-arg>
+ <list>
+ <ref bean="A1"/>
</list>
</constructor-arg>
</bean>