You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 20:40:21 UTC

svn commit: r171355 [18/31] - in /incubator/jdo/trunk/fostore20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/fostore/ test/ test/conf/ test/fsuid2/ test/fsuid2/org/ test/fsuid2/org/apache/ test/fsuid2/org/apache/jdo/ test/fsuid2/org/apache/jdo/pc/ test/java/ test/java/org/ test/java/org/apache/ test/java/org/apache/jdo/ test/java/org/apache/jdo/impl/ test/java/org/apache/jdo/impl/fostore/ test/java/org/apache/jdo/pc/ test/java/org/apache/jdo/pc/appid/ test/java/org/apache/jdo/pc/empdept/ test/java/org/apache/jdo/pc/serializable/ test/java/org/apache/jdo/pc/xempdept/ test/java/org/apache/jdo/test/ test/java/org/apache/jdo/test/query/ test/java/org/apache/jdo/test/util/ test/jdo/ test/jdo/org/ test/jdo/org/apache/ test/jdo/org/apache/jdo/ test/jdo/org/apache/jdo/pc/ test/jdo/org/apache/jdo/pc/appid/ test/jdo/org/apache/jdo/pc/empdept/ test/jdo/org/apache/jdo/pc/serializable/ test/jdo/org/apache/jdo/pc/xempdept/

Added: incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_JDOModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_JDOModel.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_JDOModel.java (added)
+++ incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_JDOModel.java Sun May 22 11:40:13 2005
@@ -0,0 +1,460 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+
+import javax.jdo.JDOFatalInternalException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.jdo.impl.model.java.runtime.RuntimeJavaModelFactory;
+import org.apache.jdo.impl.model.jdo.util.PrintSupport;
+import org.apache.jdo.model.java.JavaModel;
+import org.apache.jdo.model.jdo.JDOClass;
+import org.apache.jdo.model.jdo.JDOField;
+import org.apache.jdo.model.jdo.JDOIdentityType;
+import org.apache.jdo.model.jdo.JDOModel;
+import org.apache.jdo.model.jdo.NullValueTreatment;
+import org.apache.jdo.model.jdo.PersistenceModifier;
+import org.apache.jdo.pc.PCArrays;
+import org.apache.jdo.pc.appid.PCRect;
+import org.apache.jdo.pc.empdept.PCFullTimeEmployee;
+import org.apache.jdo.pc.serializable.PCSub3;
+import org.apache.jdo.pc.xempdept.Employee;
+import org.apache.jdo.test.util.AbstractTest;
+import org.apache.jdo.test.util.JDORITestRunner;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * This is a very simple test of the JDOModel.
+ * 
+ * @author Dave Bristor
+ */
+public class Test_JDOModel extends AbstractTest {
+    
+    /** RuntimeJavaModelFactory. */
+    private RuntimeJavaModelFactory javaModelFactory;
+    private JDOModel jdoModel;
+    
+    /** */
+    public static void main(String args[]) {
+        JDORITestRunner.run(Test_JDOModel.class);
+    }
+
+    /** */
+    protected void setUp() {
+        javaModelFactory = (RuntimeJavaModelFactory) AccessController.doPrivileged(
+            new PrivilegedAction () {
+                public Object run () {
+                    return RuntimeJavaModelFactory.getInstance();
+                }});
+        JavaModel javaModel =
+            javaModelFactory.getJavaModel(this.getClass().getClassLoader());
+        jdoModel = javaModel.getJDOModel();
+    }
+    
+    /** */
+    protected void tearDown() { }
+
+    /** */
+    public void testXML() throws Exception {
+        DocumentBuilderFactory domParserFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder domParser = domParserFactory.newDocumentBuilder();
+        domParser.setEntityResolver(new JDOEntityResolver());
+
+        // package.jdo in org.apache.jdo.pc
+        handleJDOFile(getResourceAsStream(PCArrays.class, "package.jdo"), domParser);
+        // package.jdo in org.apache.jdo.pc.empdept
+        handleJDOFile(getResourceAsStream(PCFullTimeEmployee.class, "package.jdo"), domParser);
+        // package.jdo in org.apache.jdo.pc.serializable
+        handleJDOFile(getResourceAsStream(PCSub3.class, "package.jdo"), domParser);
+        // package.jdo in org.apache.jdo.pc.appid
+        handleJDOFile(getResourceAsStream(PCRect.class, "package.jdo"), domParser);
+        // Employee.jdo in org.apache.jdo.pc.xempdept
+        handleJDOFile(getResourceAsStream(Employee.class, "Employee.jdo"), domParser);
+    }
+
+    /** 
+     * Tests the JDOModel properties of selected pc classes to make sure
+     * that the default calulation of the JDOModel is correct.
+     */
+    public void testDefaults() {
+        verifyPCFullTimeEmployee();
+        verifyPCSub3();
+    }
+
+    /** */
+    protected void handleJDOFile(InputStream is, DocumentBuilder domParser)
+        throws Exception {
+        Document dom = domParser.parse(is);
+        String packageName = getPackageName(dom);
+        handleClassElements(dom.getElementsByTagName("class"), packageName);
+    }
+
+    /** */
+    protected String getPackageName(Document dom) {
+        NodeList packageElements = dom.getElementsByTagName("package");
+        int length = packageElements.getLength();
+        if (length != 1)
+            fail("Multiple package nodes");
+        Node packageElement = packageElements.item(0);
+        String packageName =
+            packageElement.getAttributes().getNamedItem("name").getNodeValue();
+        if (debug) logger.debug("packageName: " + packageName);
+        return packageName;
+    }
+
+    /** */
+    protected void handleClassElements(NodeList classElements,
+                                       String packageName) {
+        for (int i = 0; i < classElements.getLength(); i++) {
+            handleClassElement((Element)classElements.item(i), packageName);
+        }
+    }
+    
+    /** */
+    protected void handleClassElement(Element classElement, String packageName) {
+        String fullClassName = packageName + '.' + classElement.getAttribute("name");
+        if (debug) logger.debug("class: " + fullClassName);
+        JDOClass jdoClass = jdoModel.getJDOClass(fullClassName);
+        assertNotNull("No JDOClass instance for class " + fullClassName, jdoClass);
+
+        // handle identity type attribute
+        if (classElement.hasAttribute("identity-type")) {
+            String identityType = classElement.getAttribute("identity-type");
+            if (debug) logger.debug("  identity-type: " + identityType);
+            assertEquals("Wrong identity-type of class " + fullClassName, 
+                         identityType, 
+                         JDOIdentityType.toString(jdoClass.getIdentityType()));
+        }
+
+        // handle objectid-class attribute
+        if (classElement.hasAttribute("objectid-class")) {
+            String objectIdClass = classElement.getAttribute("objectid-class");
+            if (debug) logger.debug("  objectid-class: " + objectIdClass);
+            assertEquals("Wrong objectid-class of class " + fullClassName, 
+                         objectIdClass, 
+                         jdoClass.getDeclaredObjectIdClassName());
+        }
+
+        // handle requires-extent attribute
+        if (classElement.hasAttribute("requires-extent")) {
+            String requiresExtent = classElement.getAttribute("requires-extent");
+            if (debug) logger.debug("  requires-extent: " + requiresExtent);
+            assertEquals("Wrong requires-extent of class " + fullClassName, 
+                         Boolean.valueOf(requiresExtent).booleanValue(), 
+                         jdoClass.requiresExtent());
+        }
+
+        // handle persistence-capable-superclass attribute
+        if (classElement.hasAttribute("persistence-capable-superclass")) {
+            String pcSuperClass =
+                classElement.getAttribute("persistence-capable-superclass");
+            if (debug)
+                logger.debug("  persistence-capable-superclass: " + pcSuperClass);
+            // Note, this code assumes the persistence-capable-superclass
+            // attribute is either a fully qualified class name or a class
+            // in the same package as the pc class!
+            assertEquals("Wrong persistence-capable-superclass of class " +
+                         fullClassName, 
+                         getQualifiedClassName(pcSuperClass, packageName), 
+                         jdoClass.getPersistenceCapableSuperclassName());
+        }
+            
+        // handle field subelements
+        handleFieldElements(classElement.getElementsByTagName("field"), jdoClass);
+    }
+
+    /** */
+    protected void handleFieldElements(NodeList fields, JDOClass jdoClass) {
+        for (int i = 0; i < fields.getLength(); i++) {
+            handleFieldElement((Element)fields.item(i), jdoClass);
+        }
+    }
+    
+    /** */
+    protected void handleFieldElement(Element fieldElement, JDOClass jdoClass) {
+        String fieldName = fieldElement.getAttribute("name");
+        String className = jdoClass.getName();
+        if (debug) logger.debug("  field: " + fieldName);
+        JDOField jdoField = jdoClass.getField(fieldName);
+        assertNotNull("No JDOField instance for field " + fieldName +
+                      " of class " + className, jdoField);
+
+        // handle persistence-modifier attribute
+        if (fieldElement.hasAttribute("persistence-modifier")) {
+            String persistenceModifier =
+                fieldElement.getAttribute("persistence-modifier");
+            if (debug)
+                logger.debug("    persistence-modifier: " + persistenceModifier);
+            assertEquals("Wrong persistence-modifier of field " + fieldName +
+                         " of class " + className, 
+                         persistenceModifier, 
+                         PersistenceModifier.toString(jdoField.getPersistenceModifier()));
+        }
+        
+        // handle primary-key attribute
+        if (fieldElement.hasAttribute("primary-key")) {
+            String primaryKey = fieldElement.getAttribute("primary-key");
+            if (debug) logger.debug("    primary-key: " + primaryKey);
+            assertEquals("Wrong primary-key of field " + fieldName + " of class " + className, 
+                         Boolean.valueOf(primaryKey).booleanValue(), 
+                         jdoField.isPrimaryKey());
+        }
+
+        // handle null-value attribute 
+        if (fieldElement.hasAttribute("null-value")) {
+            String nullValue = fieldElement.getAttribute("null-value");
+            if (debug) logger.debug("    null-value: " + nullValue);
+            assertEquals("Wrong null-value of field " + fieldName +
+                         " of class " + className, 
+                         nullValue, 
+                         NullValueTreatment.toString(jdoField.getNullValueTreatment()));
+        }
+
+        // handle default-fetch-group attribute 
+        if (fieldElement.hasAttribute("default-fetch-group")) {
+            String dfg = fieldElement.getAttribute("default-fetch-group");
+            if (debug) logger.debug("    default-fetch-group: " + dfg);
+            assertEquals("Wrong default-fetch-group of field " + fieldName +
+                         " of class " + className, 
+                         Boolean.valueOf(dfg).booleanValue(), 
+                         jdoField.isDefaultFetchGroup());
+        }
+
+        // handle embedded attribute 
+        if (fieldElement.hasAttribute("embedded")) {
+            String embedded = fieldElement.getAttribute("embedded");
+            if (debug) logger.debug("    embedded: " + embedded);
+            assertEquals("Wrong embedded of field " + fieldName +
+                         " of class " + className, 
+                         Boolean.valueOf(embedded).booleanValue(), 
+                         jdoField.isEmbedded());
+        }
+        
+    }
+
+    /** 
+     * Verify metadata for org.apache.jdo.pc.empdept.PCFullTimeEmployee.
+     */ 
+    protected void verifyPCFullTimeEmployee() {
+        Class clazz = PCFullTimeEmployee.class;
+        String className = clazz.getName();
+        JDOClass jdoClass = javaModelFactory.getJavaType(clazz).getJDOClass();
+        assertNotNull("No JDOClass instance for class " + className, jdoClass);
+        assertEquals("Wrong identity type of class " + className, 
+                     JDOIdentityType.DATASTORE, 
+                     jdoClass.getIdentityType());
+        assertEquals("Wrong pc super class of class " + className, 
+                     "org.apache.jdo.pc.empdept.PCEmployee", 
+                     jdoClass.getPersistenceCapableSuperclassName());
+        assertEquals("Wrong number of declared managed fields of class " + className, 
+                     1, 
+                     jdoClass.getDeclaredManagedFieldCount());
+        assertEquals("Wrong number of inherited managed fields of class " + className, 
+                     10, 
+                     jdoClass.getInheritedManagedFieldCount());
+        assertEquals("Wrong list of managed fields of class " + className, 
+                     "[birthdate, firstname, lastname, department, empid, employees, hiredate, insurance, manager, projects, salary]",
+                     Arrays.asList(jdoClass.getManagedFields()).toString());
+        assertEquals("Wrong list of default fetch group fields of class " + className, 
+                     "[birthdate, firstname, lastname, empid, hiredate, salary]",
+                     Arrays.asList(jdoClass.getDefaultFetchGroupFields()).toString());
+        assertEquals("Wrong list of  managedFieldNumbers of class " + className, 
+                     "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
+                     PrintSupport.asList(jdoClass.getManagedFieldNumbers()).toString());
+        assertEquals("Wrong list of  persistentFieldNumbers of class " + className, 
+                     "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
+                     PrintSupport.asList(jdoClass.getPersistentFieldNumbers()).toString());
+        assertEquals("Wrong list of primaryKeyFieldNumbers of class " + className, 
+                     "[]",
+                     PrintSupport.asList(jdoClass.getPrimaryKeyFieldNumbers()).toString());
+        assertEquals("Wrong list of persistentNonPKFieldNs of class " + className, 
+                     "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
+                     PrintSupport.asList(jdoClass.getPersistentNonPrimaryKeyFieldNumbers()).toString());
+        assertEquals("Wrong list of persistentRelshipFieldNumbers of class " + className, 
+                     "[3, 5, 7, 8, 9]",
+                     PrintSupport.asList(jdoClass.getPersistentRelationshipFieldNumbers()).toString());
+        assertEquals("Wrong list of persistentSerializableFieldNumbers of class " + className, 
+                     "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
+                     PrintSupport.asList(jdoClass.getPersistentSerializableFieldNumbers()).toString());
+
+        JDOField[] jdoFields = jdoClass.getDeclaredFields();
+        assertEquals("Wrong number of declared fields of class" + className,
+                     1,
+                     jdoFields.length);
+        JDOField jdoField = jdoFields[0];
+        String fieldName = jdoField.getName();
+        assertEquals("Wrong name of field of class " + className,
+                     "salary",
+                     fieldName);
+        assertEquals("Wrong type of field " + fieldName + " of class " + className,
+                     "double",
+                     jdoField.getType().toString());
+        assertEquals("Wrong field number of field " + fieldName + " of class " + className,
+                     10,
+                     jdoField.getFieldNumber());
+    }
+    
+    
+    /** 
+     * Verify metadata for org.apache.jdo.pc.serializable.PCSub3. 
+     * It explicitly defines the dfg attribute.
+     */
+    protected void verifyPCSub3() {
+        Class clazz = PCSub3.class;
+        String className = clazz.getName();
+        JDOClass jdoClass = javaModelFactory.getJavaType(clazz).getJDOClass();
+        assertNotNull("No JDOClass instance for class " + className, jdoClass);
+        assertEquals("Wrong identity type of class " + className, 
+                     JDOIdentityType.DATASTORE, 
+                     jdoClass.getIdentityType());
+        assertEquals("Wrong pc super class of class " + className, 
+                     "org.apache.jdo.pc.serializable.PCSuper", 
+                     jdoClass.getPersistenceCapableSuperclassName());
+        assertEquals("Wrong number of declared managed fields of class " + className, 
+                     2, 
+                     jdoClass.getDeclaredManagedFieldCount());
+        assertEquals("Wrong number of inherited managed fields of class " + className, 
+                     2, 
+                     jdoClass.getInheritedManagedFieldCount());
+        assertEquals("Wrong list of managed fields of class " + className, 
+                     "[s01, t02, s03, t04]",
+                     Arrays.asList(jdoClass.getManagedFields()).toString());
+        assertEquals("Wrong list of  managedFieldNumbers of class " + className, 
+                     "[0, 1, 2, 3]",
+                     PrintSupport.asList(jdoClass.getManagedFieldNumbers()).toString());
+        assertEquals("Wrong list of  persistentFieldNumbers of class " + className, 
+                     "[0, 1, 2, 3]",
+                     PrintSupport.asList(jdoClass.getPersistentFieldNumbers()).toString());
+        assertEquals("Wrong list of primaryKeyFieldNumbers of class " + className, 
+                     "[]",
+                     PrintSupport.asList(jdoClass.getPrimaryKeyFieldNumbers()).toString());
+        assertEquals("Wrong list of persistentNonPKFieldNs of class " + className, 
+                     "[0, 1, 2, 3]",
+                     PrintSupport.asList(jdoClass.getPersistentNonPrimaryKeyFieldNumbers()).toString());
+        assertEquals("Wrong list of persistentRelshipFieldNumbers of class " + className, 
+                     "[]",
+                     PrintSupport.asList(jdoClass.getPersistentRelationshipFieldNumbers()).toString());
+        assertEquals("Wrong list of persistentSerializableFieldNumbers of class " + className, 
+                     "[0, 2]",
+                     PrintSupport.asList(jdoClass.getPersistentSerializableFieldNumbers()).toString());
+
+        JDOField[] jdoFields = jdoClass.getDeclaredFields();
+        assertEquals("Wrong number of declared fields of class" + className,
+                     2,
+                     jdoFields.length);
+
+        JDOField jdoField;
+        String fieldName;
+
+        jdoField = jdoFields[0];
+        fieldName = jdoField.getName();
+        assertEquals("Wrong name of field of class " + className,
+                     "s03",
+                     fieldName);
+        assertEquals("Wrong type of field " + fieldName + " of class " + className,
+                     "java.lang.String",
+                     jdoField.getType().toString());
+        assertEquals("Wrong field number of field " + fieldName + " of class " +
+                     className,
+                     2,
+                     jdoField.getFieldNumber());
+        
+        jdoField = jdoFields[1];
+        fieldName = jdoField.getName();
+        assertEquals("Wrong name of field of class " + className,
+                     "t04",
+                     fieldName);
+        assertEquals("Wrong type of field " + fieldName + " of class " + className,
+                     "java.lang.String",
+                     jdoField.getType().toString());
+        assertEquals("Wrong field number of field " + fieldName + " of class " + className,
+                     3,
+                     jdoField.getFieldNumber());
+    }
+
+    /** */
+    protected String getQualifiedClassName(String className, String packageName) {
+        if (className.indexOf('.') == -1) {
+            // not qualified
+            return packageName + '.' + className;
+        }
+        return className;
+    }
+
+    /** */
+    protected InputStream getResourceAsStream(final Class clazz,
+                                              final String resourceName) {
+        return (InputStream)AccessController.doPrivileged(
+            new PrivilegedAction () {
+                public Object run () {
+                    return clazz.getResourceAsStream(resourceName);
+                }});
+    }
+    
+    /**
+     * Implementation of EntityResolver interface to check the jdo.dtd location
+     **/
+    private static class JDOEntityResolver 
+        implements EntityResolver 
+    {
+        private static final String RECOGNIZED_PUBLIC_ID = 
+            "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN";
+        private static final String RECOGNIZED_SYSTEM_ID = 
+            "file:/javax/jdo/jdo.dtd";
+
+        public InputSource resolveEntity(String publicId, String systemId)
+            throws SAXException, IOException 
+        {
+            // check for recognized ids
+            if (((publicId != null) && RECOGNIZED_PUBLIC_ID.equals(publicId)) ||
+                ((publicId == null) && (systemId != null) && 
+                 RECOGNIZED_SYSTEM_ID.equals(systemId))) {
+                // Substitute the dtd with the one from javax.jdo.jdo.dtd,
+                // but only if the publicId is equal to RECOGNIZED_PUBLIC_ID
+                // or there is no publicID and the systemID is equal to
+                // RECOGNIZED_SYSTEM_ID. 
+                InputStream stream = (InputStream) AccessController.doPrivileged (
+                    new PrivilegedAction () {
+                        public Object run () {
+                            return getClass().getClassLoader().
+                                getResourceAsStream("javax/jdo/jdo.dtd"); //NOI18N
+                        }});
+                if (stream == null) {
+                    throw new JDOFatalInternalException(
+                        "Cannot load javax/jdo/jdo.dtd, because the file does not exist in the jdo.jar file, or the test case class is not granted permission to read this file.  The metadata .xml file contained PUBLIC=" + publicId + " SYSTEM=" + systemId + ".");
+                }
+                return new InputSource(new InputStreamReader(stream));
+            }
+            return null;
+        }
+    }
+}
+

Added: incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_KeyFieldNull.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_KeyFieldNull.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_KeyFieldNull.java (added)
+++ incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_KeyFieldNull.java Sun May 22 11:40:13 2005
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.test;
+
+
+import javax.jdo.JDOUserException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.Transaction;
+
+import org.apache.jdo.pc.appid.PCObjectKey;
+import org.apache.jdo.test.util.AbstractTest;
+import org.apache.jdo.test.util.JDORITestRunner;
+
+/**
+* Test makePersistent with an instance with null key fields throws an exception.
+*
+* @author Craig Russell
+*/
+public class Test_KeyFieldNull extends AbstractTest {
+    
+    /** */
+    public static void main(String args[]) {
+        JDORITestRunner.run(Test_KeyFieldNull.class);
+    }
+
+    /** Create an instance with a null key field and verify that the proper
+     * exception is thrown.
+     */
+    public void test1() {
+        PersistenceManager pm = pmf.getPersistenceManager();
+        Transaction tx = pm.currentTransaction();
+        try {
+            tx.begin();
+            PCObjectKey obj = new PCObjectKey();
+            try {
+                pm.makePersistent(obj);
+                fail("Test failed. Expected JDOUserException on makePersistent with key field null");
+            } catch (JDOUserException ex) {
+                if (debug) logger.debug("caught expected " + ex);
+            }
+        }
+        finally {
+            if (tx != null && tx.isActive())
+                tx.rollback();
+            if (pm != null && !pm.isClosed())
+                pm.close();
+        }
+    }
+    
+    /** Create an instance with a null key field and verify that the proper
+     * exception is thrown for makePersistentAll.
+     */
+    public void test2() {
+        PersistenceManager pm = pmf.getPersistenceManager();
+        Transaction tx = pm.currentTransaction();
+        try {
+            tx.begin();
+            PCObjectKey obj = new PCObjectKey();
+            try {
+                pm.makePersistentAll(new Object[] {obj});
+                fail("Test failed. Expected JDOUserException on makePersistent with key field null");
+            } catch (JDOUserException ex) {
+                if (debug) logger.debug("caught expected " + ex);
+            }
+        }
+        finally {
+            if (tx != null && tx.isActive())
+                tx.rollback();
+            if (pm != null && !pm.isClosed())
+                pm.close();
+        }
+    }
+    
+    /** GetObjectById with an object id with a key field null and verify that the
+     * proper exception is thrown.
+     */
+    public void test3() {
+        PersistenceManager pm = pmf.getPersistenceManager();
+        try {
+            PCObjectKey pcobj = new PCObjectKey();
+            PCObjectKey.Oid key = new PCObjectKey.Oid();
+            try {
+                Object obj = pm.getObjectById(key, false);
+                fail("Test failed. Expected JDOUserException on getObjectById with key field null");
+            } catch (JDOUserException ex) {
+                if (debug) logger.debug("caught expected " + ex);
+            }
+        }
+        finally {
+            if (pm != null && !pm.isClosed())
+                pm.close();
+        }
+    }    
+
+}

Added: incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LargeObj.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LargeObj.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LargeObj.java (added)
+++ incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LargeObj.java Sun May 22 11:40:13 2005
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.test;
+
+import org.apache.jdo.pc.LargeObjFactory;
+import org.apache.jdo.test.util.Factory;
+import org.apache.jdo.test.util.JDORITestRunner;
+
+/**
+* Tests that we can insert a large object.  Size is optionally given as
+* system property; default is 100,000 integers in an array.
+* To test that we can fetch the object(s), use Test_FetchExisting.
+*
+* @author Dave Bristor
+*/
+public class Test_LargeObj extends Test_Insert {
+
+    /** */
+    private static int size = Integer.getInteger("size", 100000).intValue();
+    
+    /** */
+    public static void main(String args[]) {
+        JDORITestRunner.run(Test_LargeObj.class);
+    }
+
+    /** */
+    public void test() throws Exception
+    {
+        if (debug) logger.debug("Test_LargeObj size: " + size);
+        insertObjects();
+        checkExtent(factory.getPCClass(), numInsert);
+        writeOIDs();
+    }
+
+    /** */
+    protected Factory getFactory(int verify) {
+        return new LargeObjFactory(size);
+    }
+    
+}

Added: incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LifeCycle.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LifeCycle.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LifeCycle.java (added)
+++ incubator/jdo/trunk/fostore20/test/java/org/apache/jdo/test/Test_LifeCycle.java Sun May 22 11:40:13 2005
@@ -0,0 +1,854 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+
+/*
+ * Test_LifeCycle.java
+ *
+ * Created on July 19, 2001, 3:42 PM
+ */
+
+package org.apache.jdo.test;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOException;
+import javax.jdo.JDOFatalUserException;
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOUserException;
+import javax.jdo.PersistenceManager;
+
+import org.apache.jdo.pc.empdept.PCPerson;
+import org.apache.jdo.test.util.AbstractTest;
+import org.apache.jdo.test.util.JDORITestRunner;
+
+/**
+ * Tests LifeCycle state transitions for datastore transactions with
+ * retainValues flag set to true.
+ *
+ * @author  clr
+ * @version
+ */
+public class Test_LifeCycle extends AbstractTest {
+
+    final static int BEGIN_TRANSACTION = 0;
+    final static int COMMIT_TRANSACTION = 1;
+    final static int ROLLBACK_TRANSACTION = 2;
+    final static int MAKE_PERSISTENT = 10;
+    final static int DELETE_PERSISTENT = 11;
+    final static int MAKE_TRANSIENT = 12;
+    final static int MAKE_TRANSACTIONAL = 13;
+    final static int MAKE_NONTRANSACTIONAL = 14;
+    final static int EVICT = 15;
+    final static int REFRESH = 16;
+    final static int READ_FIELD = 20;
+    final static int WRITE_FIELD = 21;
+    final static int GET_OBJECT_ID = 22;
+    final static int GET_OBJECT_BY_ID_WITH_VALIDATE = 23;
+    final static int GET_OBJECT_BY_ID_WOUT_VALIDATE = 24;
+    final static int MAKE_DIRTY = 25;
+    final static int CATCH_JDO_EXCEPTION = 30;
+    final static int CATCH_JDO_USER_EXCEPTION = 31;
+    final static int CATCH_JDO_DATASTORE_EXCEPTION = 32;
+    final static int CATCH_JDO_FATAL_USER_EXCEPTION = 33;
+    final static int CATCH_JDO_FATAL_INTERNAL_EXCEPTION = 34;
+    final static int ASSERT_TRANSIENT = 100;
+    final static int ASSERT_TRANSIENT_CLEAN = 101;
+    final static int ASSERT_TRANSIENT_DIRTY = 102;
+    final static int ASSERT_PERSISTENT_NEW = 103;
+    final static int ASSERT_PERSISTENT_CLEAN = 104;
+    final static int ASSERT_PERSISTENT_NONTRANSACTIONAL = 105;
+    final static int ASSERT_PERSISTENT_DIRTY = 106;
+    final static int ASSERT_PERSISTENT_NEW_DELETED = 107;
+    final static int ASSERT_PERSISTENT_DELETED = 108;
+    final static int ASSERT_HOLLOW = 109;
+    final static int CREATE_TRANSIENT = 200;
+
+    ArrayList cases = new ArrayList();
+
+    static PCPerson instance = null;
+    static Object oid = null;
+    static Date date = new Date();
+
+    static String testCaseName;
+    static PersistenceManager persistenceManager;
+    static Throwable thrown;
+
+    static boolean verbose = Boolean.getBoolean("verbose");
+
+    /** Creates new Test_LifeCycle */
+    public Test_LifeCycle() {
+        int i = 0;
+        cases.add (new Case (i++, "Transient: makeTransient, read, write", new int[] { // 0
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,GET_OBJECT_ID, ASSERT_TRANSIENT //
+            ,MAKE_TRANSIENT, ASSERT_TRANSIENT // A5.9-5
+            ,READ_FIELD, ASSERT_TRANSIENT // A5.9-13
+            ,WRITE_FIELD, ASSERT_TRANSIENT // A5.9-16
+            ,MAKE_DIRTY, ASSERT_TRANSIENT // A5.9-16
+            ,DELETE_PERSISTENT, CATCH_JDO_USER_EXCEPTION // A5.9-2
+            ,MAKE_NONTRANSACTIONAL, CATCH_JDO_USER_EXCEPTION // A5.9-4
+            ,EVICT, ASSERT_TRANSIENT // A5.9-12
+            ,REFRESH, ASSERT_TRANSIENT // A5.9-10
+            }));
+        cases.add (new Case (i++, "Transient: read, write, commit, rollback", new int[] { // 1
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,READ_FIELD, ASSERT_TRANSIENT // A5.9-15
+            ,WRITE_FIELD, ASSERT_TRANSIENT // A5.9-17
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT // A5.9-6
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT // A5.9-8
+            }));
+        cases.add (new Case (i++, "Transient: makeTransactional, read, commit, rollback", new int[] { // 2
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_CLEAN
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_CLEAN // A5.9-88
+            ,READ_FIELD, ASSERT_TRANSIENT_CLEAN // A5.9-100
+            ,MAKE_TRANSIENT, ASSERT_TRANSIENT_CLEAN // A5.9-90
+            ,DELETE_PERSISTENT, CATCH_JDO_USER_EXCEPTION // A5.9-87
+            ,EVICT, ASSERT_TRANSIENT_CLEAN // A5.9-97
+            ,REFRESH, ASSERT_TRANSIENT_CLEAN // A5.9-95
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT_CLEAN // A5.9-92
+            ,EVICT, ASSERT_TRANSIENT_CLEAN // A5.9-97
+            ,REFRESH, ASSERT_TRANSIENT_CLEAN // A5.9-95
+            ,READ_FIELD, ASSERT_TRANSIENT_CLEAN // A5.9-98
+            ,WRITE_FIELD, ASSERT_TRANSIENT_CLEAN // A5.9-101
+            ,MAKE_DIRTY, ASSERT_TRANSIENT_CLEAN // A5.9-101
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT_CLEAN
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT_CLEAN // A5.9-94
+            }));
+        cases.add (new Case (i++, "TransientClean: read, write, makeTransactional, makeTransient, commit, rollback", new int[] { // 3
+            ASSERT_TRANSIENT_CLEAN
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT_CLEAN
+            ,WRITE_FIELD, ASSERT_TRANSIENT_DIRTY // A5.9-102
+            ,READ_FIELD, ASSERT_TRANSIENT_DIRTY // A5.9-117
+            ,MAKE_DIRTY, ASSERT_TRANSIENT_DIRTY // A5.9-102
+            ,EVICT, ASSERT_TRANSIENT_DIRTY // A5.9-114
+            ,REFRESH, ASSERT_TRANSIENT_DIRTY // A5.9-112
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_DIRTY // A5.9-105
+            ,MAKE_NONTRANSACTIONAL, CATCH_JDO_USER_EXCEPTION // A5.9-106
+            ,MAKE_TRANSIENT, ASSERT_TRANSIENT_DIRTY // A5.9-107
+            ,DELETE_PERSISTENT, CATCH_JDO_USER_EXCEPTION // A5.9-104
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT_CLEAN // A5.9-109
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT_CLEAN
+            ,WRITE_FIELD, ASSERT_TRANSIENT_DIRTY // A5.9-119
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT_CLEAN // A5.9-111
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT_CLEAN
+            ,MAKE_DIRTY, ASSERT_TRANSIENT_DIRTY // A5.9-119
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT_CLEAN // A5.9-111
+            }));
+        cases.add (new Case (i++, "TransientClean: makeTransactional, makeNonTransactional, commit, rollback", new int[] { // 4
+            ASSERT_TRANSIENT_CLEAN
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT_CLEAN
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_CLEAN // A5.9-88
+            ,MAKE_NONTRANSACTIONAL, ASSERT_TRANSIENT // A5.9-89
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT // A5.9-6
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_CLEAN
+            ,MAKE_NONTRANSACTIONAL, ASSERT_TRANSIENT // A5.9-89
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT // A5.9-8
+            }));
+        cases.add (new Case (i++, "Transient: makeTransactional, makePersistent, rollback", new int[] { // 5
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_CLEAN
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW // A5.9-86
+            ,EVICT, ASSERT_PERSISTENT_NEW // A5.9-29
+            ,REFRESH, ASSERT_PERSISTENT_NEW // A5.9-27
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT // A5.9-8
+            }));
+        cases.add (new Case (i++, "Transient: makeTransactional, write, makePersistent, rollback", new int[] { // 6
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_TRANSACTIONAL, ASSERT_TRANSIENT_CLEAN
+            ,WRITE_FIELD, ASSERT_TRANSIENT_DIRTY // A5.9-102
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW // A5.9-103
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT // A5.9-8
+            }));
+
+        cases.add (new Case (i++, "Transient: makePersistent, rollback", new int[] { // 7
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION , ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW // A5.9-1
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW // A5.9-18
+            ,GET_OBJECT_ID, ASSERT_PERSISTENT_NEW // A5.9-18
+            ,MAKE_TRANSACTIONAL, ASSERT_PERSISTENT_NEW // A5.9-20
+            ,MAKE_NONTRANSACTIONAL, CATCH_JDO_USER_EXCEPTION // A5.9-21
+            ,MAKE_TRANSIENT, CATCH_JDO_USER_EXCEPTION // A5.9-22
+            ,READ_FIELD, ASSERT_PERSISTENT_NEW // A5.9-32
+            ,WRITE_FIELD, ASSERT_PERSISTENT_NEW // A5.9-34
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_NEW // A5.9-34
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT  // A5.9-25
+            }));
+        cases.add (new Case (i++, "Transient: makePersistent, delete, rollback", new int[] { // 8
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,DELETE_PERSISTENT, ASSERT_PERSISTENT_NEW_DELETED // A5.9-19
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW_DELETED // A5.9-120
+            ,DELETE_PERSISTENT, ASSERT_PERSISTENT_NEW_DELETED // A5.9-121
+            ,MAKE_TRANSACTIONAL, ASSERT_PERSISTENT_NEW_DELETED // A5.9-122
+            ,EVICT, ASSERT_PERSISTENT_NEW_DELETED // A5.9-131
+            ,REFRESH, ASSERT_PERSISTENT_NEW_DELETED // A5.9-129
+            ,MAKE_TRANSIENT, CATCH_JDO_USER_EXCEPTION // A5.9-124
+            ,MAKE_NONTRANSACTIONAL, CATCH_JDO_USER_EXCEPTION // A5.9-123
+            ,READ_FIELD, CATCH_JDO_USER_EXCEPTION // A5.9-134
+            ,WRITE_FIELD, CATCH_JDO_USER_EXCEPTION // A5.9-136
+            ,MAKE_DIRTY, CATCH_JDO_USER_EXCEPTION // A5.9-136
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT // A5.9-127
+            }));
+        cases.add (new Case (i++, "Transient: makePersistent, delete, commit", new int[] { // 9
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,DELETE_PERSISTENT, ASSERT_PERSISTENT_NEW_DELETED // A5.9-19
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT // A5.9-125
+            }));
+        cases.add (new Case (i++, "Transient: makePersistent, commit", new int[] { // 10
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            }));
+        cases.add (new Case (i++, "Nontransactional: makeNontransactional, read, write", new int[] { // 11
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,MAKE_NONTRANSACTIONAL, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-157
+            ,READ_FIELD, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-166
+            ,WRITE_FIELD, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-169
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-169
+            }));
+        cases.add (new Case (i++, "Nontransactional: makePersistent, makeTransactional", new int[] { // 12
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,MAKE_PERSISTENT, CATCH_JDO_USER_EXCEPTION // A12.5.7-1
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-154
+            ,MAKE_TRANSACTIONAL, ASSERT_PERSISTENT_CLEAN // A5.9-156
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            }));
+        cases.add (new Case (i++, "PersistentDirty: makePersistent, makeTransactional, commit", new int[] { // 13
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,WRITE_FIELD, ASSERT_PERSISTENT_DIRTY // A5.9-170
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_DIRTY // A5.9-170
+            ,EVICT, ASSERT_PERSISTENT_DIRTY // A5.9-63
+            ,WRITE_FIELD, ASSERT_PERSISTENT_DIRTY // A5.9-68
+            ,READ_FIELD, ASSERT_PERSISTENT_DIRTY // A5.9-66
+            ,MAKE_TRANSACTIONAL, ASSERT_PERSISTENT_DIRTY // A5.9-54
+            ,MAKE_NONTRANSACTIONAL, CATCH_JDO_USER_EXCEPTION // A5.9-55
+            ,MAKE_TRANSIENT, CATCH_JDO_USER_EXCEPTION // A5.9-56
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_DIRTY // A5.9-52
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-57
+            }));
+        cases.add (new Case (i++, "PersistentDirty: rollback", new int[] { // 14
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_DIRTY // A5.9-51
+            ,ROLLBACK_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-59
+            }));
+        cases.add (new Case (i++, "PersistentDirty: commit", new int[] { // 15
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_DIRTY // A5.9-51
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-57
+            }));
+        cases.add (new Case (i++, "PersistentDirty: refresh", new int[] { // 16
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN
+            ,WRITE_FIELD, ASSERT_PERSISTENT_DIRTY // A5.9-51
+            ,REFRESH, ASSERT_PERSISTENT_CLEAN // A5.9-61
+            ,ROLLBACK_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-59
+            }));
+        cases.add (new Case (i++, "PersistentClean: makePersistent, makeTransactional", new int[] { // 17
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN // A5.9-168
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN // A5.9-49
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_CLEAN // A5.9-35
+            ,MAKE_TRANSACTIONAL, ASSERT_PERSISTENT_CLEAN // A5.9-37
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-40
+            }));
+        cases.add (new Case (i++, "PersistentClean: makeNontransactional", new int[] { // 18
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN
+            ,MAKE_NONTRANSACTIONAL, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-38
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            }));
+        cases.add (new Case (i++, "PersistentDeleted: rollback", new int[] { // 19
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN
+            ,DELETE_PERSISTENT, ASSERT_PERSISTENT_DELETED // A5.9-36
+            ,EVICT, ASSERT_PERSISTENT_DELETED // A5.9-148
+            ,REFRESH, ASSERT_PERSISTENT_DELETED // A5.9-146
+            ,READ_FIELD, CATCH_JDO_USER_EXCEPTION // A5.9-134
+            ,ROLLBACK_TRANSACTION ,ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-145
+            }));
+        cases.add (new Case (i++, "PersistentDeleted: makePersistent, makeTransactional, commit", new int[] { // 20
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,GET_OBJECT_ID, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,DELETE_PERSISTENT, ASSERT_PERSISTENT_DELETED // A5.9-155
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_DELETED // A5.9-137
+            ,DELETE_PERSISTENT, ASSERT_PERSISTENT_DELETED // A5.9-138
+            ,MAKE_TRANSACTIONAL, ASSERT_PERSISTENT_DELETED // A5.9-139
+            ,MAKE_NONTRANSACTIONAL, CATCH_JDO_USER_EXCEPTION // A5.9-140
+            ,MAKE_TRANSIENT, CATCH_JDO_USER_EXCEPTION // A5.9-141
+            ,READ_FIELD, CATCH_JDO_USER_EXCEPTION // A5.9-151
+            ,WRITE_FIELD, CATCH_JDO_USER_EXCEPTION // A5.9-153
+            ,MAKE_DIRTY, CATCH_JDO_USER_EXCEPTION // A5.9-153
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT // A5.9-142
+            }));
+        cases.add (new Case (i++, "Transient: getObjectById(false), getObjectById(true), makePersistent, commit", new int[] { // 21
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,GET_OBJECT_BY_ID_WOUT_VALIDATE, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,READ_FIELD, CATCH_JDO_DATASTORE_EXCEPTION
+            ,GET_OBJECT_BY_ID_WITH_VALIDATE, CATCH_JDO_DATASTORE_EXCEPTION
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,GET_OBJECT_ID, ASSERT_PERSISTENT_NEW
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            }));
+        cases.add (new Case (i++, "Nontransactional: getObjectById(false), getObjectById(true)", new int[] { // 22
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,GET_OBJECT_BY_ID_WOUT_VALIDATE, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,GET_OBJECT_BY_ID_WITH_VALIDATE, ASSERT_PERSISTENT_CLEAN
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            }));
+        cases.add (new Case (i++, "Nontransactional: makeTransient, commit, rollback", new int[] { // 23
+            ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,MAKE_TRANSIENT, ASSERT_TRANSIENT // A5.9-158
+            ,COMMIT_TRANSACTION, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,MAKE_TRANSIENT, ASSERT_TRANSIENT // A5.9-158
+            ,ROLLBACK_TRANSACTION, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            ,MAKE_TRANSIENT, ASSERT_TRANSIENT // A5.9-158
+            }));
+        cases.add (new Case (i++, "Nontransactional: evict", new int[] { // 24
+            CREATE_TRANSIENT, ASSERT_TRANSIENT
+            ,BEGIN_TRANSACTION, ASSERT_TRANSIENT
+            ,MAKE_PERSISTENT, ASSERT_PERSISTENT_NEW
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            ,REFRESH, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-163
+            ,EVICT, ASSERT_HOLLOW // A5.9-165
+            ,EVICT, ASSERT_HOLLOW // A5.9-80
+            ,REFRESH, ASSERT_HOLLOW // A5.9-78
+            ,READ_FIELD, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,EVICT, ASSERT_HOLLOW // A5.9-80
+            ,REFRESH, ASSERT_HOLLOW // A5.9-78
+            ,COMMIT_TRANSACTION, ASSERT_HOLLOW // A5.9-23
+            }));
+        cases.add (new Case (i++, "PersistentClean: evict", new int[] { // 25
+            ASSERT_HOLLOW
+            ,BEGIN_TRANSACTION, ASSERT_HOLLOW
+            ,READ_FIELD, ASSERT_PERSISTENT_CLEAN
+            ,REFRESH, ASSERT_PERSISTENT_CLEAN // A5.9-44
+            ,EVICT, ASSERT_HOLLOW // A5.9-46
+            ,COMMIT_TRANSACTION, ASSERT_HOLLOW // A5.9-23
+            }));
+        cases.add (new Case (i++, "Hollow: makeDirty", new int[] { // 26
+            ASSERT_HOLLOW
+            ,BEGIN_TRANSACTION, ASSERT_HOLLOW
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_DIRTY // A5.9-85
+            ,COMMIT_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-23
+            ,BEGIN_TRANSACTION, ASSERT_PERSISTENT_NONTRANSACTIONAL
+            ,EVICT, ASSERT_HOLLOW // A5.9-80
+            ,COMMIT_TRANSACTION, ASSERT_HOLLOW // A5.9-23
+            ,MAKE_DIRTY, ASSERT_PERSISTENT_NONTRANSACTIONAL // A5.9-84
+            }));
+    }
+    
+    /** */
+    public static void main(String args[]) {
+        JDORITestRunner.run(Test_LifeCycle.class);
+    }
+
+    /** */
+    public void test() {
+        persistenceManager = pmf.getPersistenceManager();
+        for (Iterator i = cases.iterator(); i.hasNext();) {
+            Case testcase = (Case) i.next();
+            testcase.execute();
+        }
+    }
+
+    /**
+     * Initializes JDO startup properties with default values.
+     * Sub classes can overwrite this method in order to change those default
+     * values.
+     */
+    protected void initProperties()
+    {   super.initProperties();
+    //properties.setProperty( "javax.jdo.option.ConnectionUserName", "" );
+    //properties.setProperty( "javax.jdo.option.ConnectionPassword", "" );
+    //properties.setProperty( "javax.jdo.option.ConnectionURL", "fostore:test" );
+        properties.setProperty( "javax.jdo.option.NontransactionalWrite", "true" );
+        properties.setProperty( "javax.jdo.option.Optimistic", "false" );
+    }
+
+    /** */
+    static void resetThrown() {
+        thrown = null;
+    }
+
+    /** */
+    class Case {
+        int number;
+        String name;
+        int[] procedures;
+        Case (int number, String name, int[] procedures) {
+            this.number = number;
+            this.name = name;
+            this.procedures = procedures;
+        }
+        int execute () {
+            printFlush ("Test case " + number + ": " + name);
+            testCaseName = name;
+            for (int i = 0; i < procedures.length; ++i) {
+                try {
+                    switch (procedures[i]) {
+                        case BEGIN_TRANSACTION:
+                            resetThrown();
+                            Procedure.beginTransaction();
+                            break;
+                        case COMMIT_TRANSACTION:
+                            resetThrown();
+                            Procedure.commitTransaction();
+                            break;
+                        case ROLLBACK_TRANSACTION:
+                            resetThrown();
+                            Procedure.rollbackTransaction();
+                            break;
+                       case CREATE_TRANSIENT:
+                            resetThrown();
+                            Procedure.createTransient();
+                            break;
+                        case MAKE_PERSISTENT:
+                            resetThrown();
+                            Procedure.makePersistent();
+                            break;
+                        case DELETE_PERSISTENT:
+                            resetThrown();
+                            Procedure.deletePersistent();
+                            break;
+                        case MAKE_TRANSACTIONAL:
+                            resetThrown();
+                            Procedure.makeTransactional();
+                            break;
+                        case MAKE_TRANSIENT:
+                            resetThrown();
+                            Procedure.makeTransient();
+                            break;
+                        case MAKE_NONTRANSACTIONAL:
+                            resetThrown();
+                            Procedure.makeNontransactional();
+                            break;
+                        case EVICT:
+                            resetThrown();
+                            Procedure.evict();
+                            break;
+                        case REFRESH:
+                            resetThrown();
+                            Procedure.refresh();
+                            break;
+                        case ASSERT_PERSISTENT_NEW:
+                            Procedure.assertPersistentNew();
+                            break;
+                        case ASSERT_PERSISTENT_NEW_DELETED:
+                            Procedure.assertPersistentNewDeleted();
+                            break;
+                        case ASSERT_TRANSIENT:
+                            Procedure.assertTransient();
+                            break;
+                        case ASSERT_TRANSIENT_CLEAN:
+                            Procedure.assertTransientClean();
+                            break;
+                        case ASSERT_TRANSIENT_DIRTY:
+                            Procedure.assertTransientDirty();
+                            break;
+                        case ASSERT_PERSISTENT_CLEAN:
+                            Procedure.assertPersistentClean();
+                            break;
+                        case ASSERT_PERSISTENT_DIRTY:
+                            Procedure.assertPersistentDirty();
+                            break;
+                        case ASSERT_PERSISTENT_NONTRANSACTIONAL:
+                            Procedure.assertPersistentNontransactional();
+                            break;
+                        case ASSERT_HOLLOW:
+                            Procedure.assertHollow();
+                            break;
+                        case ASSERT_PERSISTENT_DELETED:
+                            Procedure.assertPersistentDeleted();
+                            break;
+                        case READ_FIELD:
+                            resetThrown();
+                            Procedure.readField();
+                            break;
+                        case WRITE_FIELD:
+                            resetThrown();
+                            Procedure.writeField();
+                            break;
+                        case GET_OBJECT_ID:
+                            resetThrown();
+                            Procedure.getObjectId();
+                            break;
+                        case GET_OBJECT_BY_ID_WITH_VALIDATE:
+                            resetThrown();
+                            Procedure.getObjectById(true);
+                            break;
+                        case GET_OBJECT_BY_ID_WOUT_VALIDATE:
+                            resetThrown();
+                            Procedure.getObjectById(false);
+                            break;
+                        case MAKE_DIRTY:
+                            resetThrown();
+                            Procedure.makeDirty();
+                            break;
+                        case CATCH_JDO_EXCEPTION:
+                            Procedure.catchJDOException();
+                            resetThrown();
+                            break;
+                        case CATCH_JDO_USER_EXCEPTION:
+                            Procedure.catchJDOUserException();
+                            resetThrown();
+                            break;
+                        case CATCH_JDO_FATAL_USER_EXCEPTION:
+                            Procedure.catchJDOFatalUserException();
+                            resetThrown();
+                            break;
+                        case CATCH_JDO_DATASTORE_EXCEPTION:
+                            Procedure.catchJDODataStoreException();
+                            resetThrown();
+                            break;
+                        default:
+                            throw new JDOException ("Unknown Procedure " + procedures[i]);
+                    }
+                } catch (JDOException t) {
+                    thrown = t;
+                } catch (RuntimeException e) {
+                    e.printStackTrace();
+                    throw new JDOException ("Test failed", e);
+                }
+            }
+            return 0;
+        }
+    }
+
+    /** */
+    static class Procedure {
+        static void createTransient() {
+            printFlush ("createTransient");
+            instance = new PCPerson("First", "Last", date);
+        }
+        static void makePersistent() {
+            printFlush ("makePersistent");
+            persistenceManager.makePersistent(instance);
+        }
+        static void deletePersistent() {
+            printFlush ("deletePersistent");
+            persistenceManager.deletePersistent(instance);
+        }
+        static void makeTransient() {
+            printFlush ("makeTransient");
+            persistenceManager.makeTransient(instance);
+        }
+        static void makeTransactional() {
+            printFlush ("makeTransactional");
+            persistenceManager.makeTransactional(instance);
+        }
+        static void makeNontransactional() {
+            printFlush ("makeNontransactional");
+            persistenceManager.makeNontransactional(instance);
+        }
+        static void refresh() {
+            printFlush ("refresh");
+            persistenceManager.refresh(instance);
+        }
+        static void evict() {
+            printFlush ("evict");
+            persistenceManager.evict(instance);
+        }
+        static void getObjectId() {
+            printFlush ("getObjectId");
+            oid = persistenceManager.getObjectId(instance);
+        }
+        static void getObjectById(boolean validate) {
+            printFlush ("getObjectById_" + validate);
+            Object o = persistenceManager.getObjectById(oid, validate);
+            instance = (PCPerson)o;
+        }
+        static void assertPersistentNew() {
+            printFlush ("assertPersistentNew");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isPersistentNew(instance))
+                throw new RuntimeException ("Assertion PersistentNew failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertPersistentNewDeleted() {
+            printFlush ("assertPersistentNewDeleted");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isPersistentNewDeleted(instance))
+                throw new RuntimeException ("Assertion NewDeleted failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertTransient() {
+            printFlush ("assertTransient");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isTransient(instance))
+                throw new RuntimeException ("Assertion Transient failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertTransientClean() {
+            printFlush ("assertTransientClean");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isTransientClean(instance))
+                throw new RuntimeException ("Assertion TransientClean failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertTransientDirty() {
+            printFlush ("assertTransientDirty");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isTransientDirty(instance))
+                throw new RuntimeException ("Assertion TransientDirty failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertPersistentClean() {
+            printFlush ("assertPersistentClean");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isPersistentClean(instance))
+                throw new RuntimeException ("Assertion PersistentClean failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertPersistentDirty() {
+            printFlush ("assertPersistentDirty");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isPersistentDirty(instance))
+                throw new RuntimeException ("Assertion PersistentDirty failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertPersistentDeleted() {
+            printFlush ("assertPersistentDeleted");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isPersistentDeleted(instance))
+                throw new RuntimeException ("Assertion PersistentDeleted failed" +
+                Assert.printLifeCycleState());
+        }
+        static void assertPersistentNontransactional() {
+            printFlush ("assertPersistentNontransactional");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isPersistentNontransactional(instance))
+                throw new RuntimeException ("Assertion PersistentNontransactional failed: " +
+                Assert.printLifeCycleState());
+        }
+        static void assertHollow() {
+            printFlush ("assertHollow");
+            if (thrown != null)
+                throw new RuntimeException ("Caught exception: " + thrown);
+            if (!Assert.isHollow(instance))
+                throw new RuntimeException ("Assertion Hollow failed: " +
+                Assert.printLifeCycleState());
+        }
+        static void beginTransaction() {
+            printFlush ("beginTransaction");
+            persistenceManager.currentTransaction().begin();
+        }
+        static void commitTransaction() {
+            printFlush ("commitTransaction");
+            persistenceManager.currentTransaction().commit();
+        }
+        static void rollbackTransaction() {
+            printFlush ("rollbackTransaction");
+            persistenceManager.currentTransaction().rollback();
+        }
+        static void readField() {
+            printFlush ("readField");
+            instance.getBirthdate();
+        }
+        static void writeField() {
+            printFlush ("writeField");
+            instance.setBirthdate(new Date());
+        }
+        static void makeDirty() {
+            printFlush ("makeDirty");
+            JDOHelper.makeDirty(instance, "lastname");
+        }
+        static void catchJDOException() {
+            printFlush ("catchJDOException");
+            if (thrown == null || !JDOException.class.isAssignableFrom(thrown.getClass()))
+                throw new RuntimeException ("Expected JDOException, got " + thrown);
+        }
+        static void catchJDOUserException() {
+            printFlush ("catchJDOUserException");
+            if (thrown == null || !JDOUserException.class.isAssignableFrom(thrown.getClass()))
+                throw new RuntimeException ("Expected JDOUserException, got " + thrown);
+        }
+        static void catchJDOFatalUserException() {
+            printFlush ("catchJDOFatalUserException");
+            if (thrown == null || !JDOFatalUserException.class.isAssignableFrom(thrown.getClass()))
+                throw new RuntimeException ("Expected JDOFatalUserException, got " + thrown);
+        }
+        static void catchJDODataStoreException() {
+            printFlush ("catchJDODataStoreException");
+            if (thrown == null || !JDODataStoreException.class.isAssignableFrom(thrown.getClass()))
+                throw new RuntimeException ("Expected JDODataStoreException, got " + thrown);
+        }
+    }
+
+    /** */
+    static void flush() {
+        try {
+            System.out.flush();
+        } catch (Exception e) {}
+    }
+
+    /** */
+    static void printFlush (String s) {
+        if (verbose) {
+            System.out.println (s);
+            flush();
+        }
+    }
+
+    /** */
+    static class Assert {
+        static String printLifeCycleState() {
+            return
+                testCaseName + ": isPersistent: " + JDOHelper.isPersistent(instance) +
+                ", isNew: " + JDOHelper.isNew(instance) +
+                ", isDirty: " + JDOHelper.isDirty(instance) +
+                ", isDeleted: " + JDOHelper.isDeleted(instance) +
+                ", isTransactional: " + JDOHelper.isTransactional(instance);
+        }
+        static boolean isTransient(Object instance) {
+            return (
+              (!JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (!JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (!JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isTransientClean(Object instance) {
+            return (
+              (!JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (!JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isTransientDirty(Object instance) {
+            return (
+              (!JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isPersistentNew(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (JDOHelper.isNew(instance))
+            & (JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isPersistentNewDeleted(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (JDOHelper.isNew(instance))
+            & (JDOHelper.isDirty(instance))
+            & (JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isPersistentDeleted(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (JDOHelper.isDirty(instance))
+            & (JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isPersistentClean(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (!JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isPersistentDirty(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (JDOHelper.isTransactional(instance))
+            );
+        }
+        static boolean isPersistentNontransactional(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (!JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (!JDOHelper.isTransactional(instance))
+            );
+        }
+	// The same as PersistentNontransactional from a user's perspective:
+        static boolean isHollow(Object instance) {
+            return (
+              (JDOHelper.isPersistent(instance))
+            & (!JDOHelper.isNew(instance))
+            & (!JDOHelper.isDirty(instance))
+            & (!JDOHelper.isDeleted(instance))
+            & (!JDOHelper.isTransactional(instance))
+            );
+        }
+    }
+
+}