/*******************************************************************************
 * Copyright (c) 2005, 2009 SAP. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     SAP - initial API and implementation
 ******************************************************************************/

package org.eclipse.persistence.testing.tests.wdf.jpa1.simple;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import org.eclipse.persistence.testing.framework.wdf.Bugzilla;
import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment;
import org.eclipse.persistence.testing.framework.wdf.Skip;
import org.eclipse.persistence.testing.models.wdf.jpa1.types.BasicTypesPropertyAccess;
import org.eclipse.persistence.testing.models.wdf.jpa1.types.UserDefinedEnum;
import org.eclipse.persistence.testing.models.wdf.jpa1.types.UserDefinedSerializable;
import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base;
import org.junit.Test;

public class TestBasicPropertyTypes extends JPA1Base {

    @Test
    public void testInsert() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            BasicTypesPropertyAccess obj = new BasicTypesPropertyAccess(0);
            obj.fill();
            env.beginTransaction(em);
            em.persist(obj);
            env.commitTransactionAndClear(em);
            verify(true, "no Exception");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(0));
        } finally {
            closeEntityManager(em);
        }
    }

    private void validatePrimitive(final int id, Validator validator, String fieldName) {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            // insert the object
            env.beginTransaction(em);
            BasicTypesPropertyAccess obj = new BasicTypesPropertyAccess(id);
            validator.set(obj);
            em.persist(obj);
            env.commitTransactionAndClear(em);
            verify(true, "no Exception");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " not persisted");
            // update unchanged object
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            env.commitTransactionAndClear(em);
            verify(!obj.postUpdateWasCalled(), "postUpdate was called -> before image fails");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " is changed");
            // update changed object
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            validator.change(obj);
            env.commitTransactionAndClear(em);
            verify(obj.postUpdateWasCalled(), "postUpdate was not called -> before image fails");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isChanged(obj), fieldName + " is unchanged");
        } finally {
            closeEntityManager(em);
        }
    }

    private void validateReference(final int id, ReferenceValidator validator, String fieldName) {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            BasicTypesPropertyAccess obj = new BasicTypesPropertyAccess(id);
            // insert object with null-field
            env.beginTransaction(em);
            em.persist(obj);
            env.commitTransactionAndClear(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isNull(obj), fieldName + " is not null");
            // delete the object again
            env.beginTransaction(em);
            em.remove(em.find(BasicTypesPropertyAccess.class, new Integer(id)));
            env.commitTransactionAndClear(em);
            // insert object with non-null field
            env.beginTransaction(em);
            validator.set(obj);
            em.persist(obj);
            env.commitTransactionAndClear(em);
            verify(true, "no Exception");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " not persisted");
            // update unchanged
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            env.commitTransactionAndClear(em);
            verify(!obj.postUpdateWasCalled(), "postUpdate was called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " is changed");
            // update changed object
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            validator.change(obj);
            env.commitTransactionAndClear(em);
            verify(obj.postUpdateWasCalled(), "postUpdate was not called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isChanged(obj), fieldName + " is unchanged");
            // update to null
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            validator.setNull(obj);
            env.commitTransactionAndClear(em);
            verify(obj.postUpdateWasCalled(), "postUpdate was not called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isNull(obj), fieldName + " is not null");
        } finally {
            closeEntityManager(em);
        }
    }

    private void validateMutable(final int id, MutableValidator validator, String fieldName) {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            BasicTypesPropertyAccess obj = new BasicTypesPropertyAccess(id);
            // insert object with null-field
            env.beginTransaction(em);
            em.persist(obj);
            env.commitTransactionAndClear(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isNull(obj), fieldName + " is not null");
            // delete the object again
            env.beginTransaction(em);
            em.remove(em.find(BasicTypesPropertyAccess.class, new Integer(id)));
            env.commitTransactionAndClear(em);
            // insert object with non-null field
            env.beginTransaction(em);
            validator.set(obj);
            em.persist(obj);
            env.commitTransactionAndClear(em);
            verify(true, "no Exception");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " not persisted");
            // update unchanged
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            env.commitTransactionAndClear(em);
            verify(!obj.postUpdateWasCalled(), "postUpdate was not called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " is changed");
            // update changed
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            validator.setNull(obj);
            env.commitTransactionAndClear(em);
            verify(obj.postUpdateWasCalled(), "postUpdate was not called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isNull(obj), fieldName + " is not null");
            // update original
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            validator.set(obj);
            env.commitTransactionAndClear(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(!validator.isChanged(obj), fieldName + " not persisted");
            // mutate
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            validator.mutate(obj);
            env.commitTransactionAndClear(em);
            verify(obj.postUpdateWasCalled(), "postUpdate was not called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isChanged(obj), fieldName + " not mutated");
            // update to null
            env.beginTransaction(em);
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            obj.clearPostUpdate();
            validator.setNull(obj);
            env.commitTransactionAndClear(em);
            verify(obj.postUpdateWasCalled(), "postUpdate was not called");
            obj = em.find(BasicTypesPropertyAccess.class, new Integer(id));
            verify(validator.isNull(obj), fieldName + " is not null");
        } finally {
            closeEntityManager(em);
        }
    }

    // primitive types
    @Test
    public void testPrimitiveBoolean() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveBoolean(true);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveBoolean(false);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveBoolean() != true;
            }
        };
        validatePrimitive(1, validator, "primitiveBoolean");
    }

    @Test
    public void testPrimitiveByte() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimititveByte((byte) 17);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimititveByte((byte) 23);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimititveByte() != 17;
            }
        };
        validatePrimitive(2, validator, "primitiveByte");
    }

    @Test
    public void testPrimitiveChar() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveChar('A');
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveChar('B');
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveChar() != 'A';
            }
        };
        validatePrimitive(3, validator, "primitiveChar");
    }

    @Test
    public void testPrimitiveShort() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveShort((short) 19);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveShort((short) 45);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveShort() != 19;
            }
        };
        validatePrimitive(4, validator, "primitiveShort");
    }

    @Test
    public void testPrimitiveInt() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveInt(88);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveInt(77);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveInt() != 88;
            }
        };
        validatePrimitive(5, validator, "primitiveInt");
    }

    @Test
    public void testPrimitiveLong() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveLong(88);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveLong(77);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveLong() != 88;
            }
        };
        validatePrimitive(6, validator, "primitiveLong");
    }

    @Test
    public void testPrimitiveFloat() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveFloat((float) 88.5);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveFloat((float) 77.5);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveFloat() != 88.5;
            }
        };
        validatePrimitive(7, validator, "primitiveFloat");
    }

    @Test
    public void testPrimitiveDouble() {
        Validator validator = new Validator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveDouble(99.5);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveDouble(77.5);
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveDouble() != 99.5;
            }
        };
        validatePrimitive(8, validator, "primitiveDouble");
    }

    // wrappers of primitive types
    @Test
    public void testWrapperBoolean() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperBoolean(Boolean.TRUE);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperBoolean(Boolean.FALSE);
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperBoolean(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.isWrapperBoolean() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.isWrapperBoolean().equals(Boolean.TRUE);
            }
        };
        validateReference(11, validator, "wrapperBoolean");
    }

    @Test
    public void testWrapperByte() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperByte(new Byte((byte) 17));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperByte(new Byte((byte) 18));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperByte(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperByte() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperByte().equals(new Byte((byte) 17));
            }
        };
        validateReference(12, validator, "wrapperByte");
    }

    @Test
    public void testWrapperCharacter() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacter(new Character('A'));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacter(new Character('B'));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacter(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperCharacter() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperCharacter().equals(new Character('A'));
            }
        };
        validateReference(13, validator, "wrapperCharacter");
    }

    @Test
    public void testWrapperShort() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperShort(new Short((short) 1));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperShort(new Short((short) 2));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperShort(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperShort() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperShort().equals(new Short((short) 1));
            }
        };
        validateReference(14, validator, "wrapperShort");
    }

    @Test
    public void testWrapperInteger() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperInteger(new Integer(1));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperInteger(new Integer(2));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperInteger(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperInteger() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperInteger().equals(new Integer(1));
            }
        };
        validateReference(15, validator, "wrapperInteger");
    }

    @Test
    public void testWrapperLong() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperLong(new Long(1));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperLong(new Long(2));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperLong(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperLong() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperLong().equals(new Long(1));
            }
        };
        validateReference(16, validator, "wrapperLong");
    }

    @Test
    public void testWrapperDouble() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperDouble(new Double(1));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperDouble(new Double(2));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperDouble(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperDouble() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperDouble().equals(new Double(1));
            }
        };
        validateReference(18, validator, "wrapperDouble");
    }

    @Test
    public void testWrapperFloat() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperFloat(new Float(1));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperFloat(new Float(2));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperFloat(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperFloat() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getWrapperFloat().equals(new Float(1));
            }
        };
        validateReference(17, validator, "wrapperFloat");
    }

    // immutable reference types
    @Test
    public void testString2Varchar() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setString2Varchar("VC 1");
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setString2Varchar("VC 2");
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setString2Varchar(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getString2Varchar() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getString2Varchar().equals("VC 1");
            }
        };
        validateReference(21, validator, "string2Varchar");
    }

    @Test
    public void testString2Clob() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setString2Clob("VC 1");
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setString2Clob("VC 2");
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setString2Clob(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getString2Clob() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getString2Clob().equals("VC 1");
            }
        };
        validateReference(22, validator, "string2Clob");
    }

    @Test
    public void testBigDecimal() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setBigDecimal(new BigDecimal("1.1"));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setBigDecimal(new BigDecimal("2.2"));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setBigDecimal(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getBigDecimal() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getBigDecimal().compareTo(new BigDecimal("1.1")) != 0;
            }
        };
        validateReference(23, validator, "bigDecimal");
    }

    @Test
    public void testBigInteger() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setBigInteger(new BigInteger("11"));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setBigInteger(new BigInteger("22"));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setBigInteger(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getBigInteger() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getBigInteger().equals(new BigInteger("11"));
            }
        };
        validateReference(24, validator, "bigInteger");
    }

    // mutable types
    @Test
    public void testUtilDate() {
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setUtilDate(new Date(1000));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setUtilDate(new Date(2000));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setUtilDate(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getUtilDate() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getUtilDate().equals(new Date(1000));
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getUtilDate().setTime(2000);
            }
        };
        validateMutable(31, validator, "utilDate");
    }

    @Test
    public void testUtilCalendar() {
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setUtilCalendar(new GregorianCalendar(2005, 9, 8, 10, 49));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setUtilCalendar(new GregorianCalendar(2005, 9, 9, 10, 49));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setUtilCalendar(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getUtilCalendar() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getUtilCalendar().equals(new GregorianCalendar(2005, 9, 8, 10, 49));
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getUtilCalendar().set(2005, 9, 9);
            }
        };
        validateMutable(32, validator, "utilCalendar");
    }

    @Test
    public void testSqlDate() {
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setSqlDate(java.sql.Date.valueOf("2005-09-08"));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setSqlDate(java.sql.Date.valueOf("2005-09-09"));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setSqlDate(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getSqlDate() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getSqlDate().equals(java.sql.Date.valueOf("2005-09-08"));
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getSqlDate().setTime(java.sql.Date.valueOf("2005-09-09").getTime());
            }
        };
        validateMutable(33, validator, "sqlDate");
    }

    @Test
    public void testSqlTime() {
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setSqlTime(java.sql.Time.valueOf("10:49:00"));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setSqlTime(java.sql.Time.valueOf("11:49:00"));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setSqlTime(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getSqlTime() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getSqlTime().equals(java.sql.Time.valueOf("10:49:00"));
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getSqlTime().setTime(java.sql.Time.valueOf("11:49:00").getTime());
            }
        };
        validateMutable(34, validator, "sqlTime");
    }

    @Test
    public void testSqlTimestamp() {
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setSqlTimestamp(new java.sql.Timestamp(1000));
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setSqlTimestamp(new java.sql.Timestamp(2000));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setSqlTimestamp(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getSqlTimestamp() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !obj.getSqlTimestamp().equals(new java.sql.Timestamp(1000));
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getSqlTimestamp().setTime(2000);
            }
        };
        validateMutable(35, validator, "sqlTimestamp");
    }

    // arrays
    @Test
    public void testPrimitiveByteArray2Binary() {
        final byte[] UNCHANGED = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Binary(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Binary(new byte[] { 8, 1, 2, 3, 4, 5, 6, 7 });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Binary(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveByteArray2Binary() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getPrimitiveByteArray2Binary());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getPrimitiveByteArray2Binary()[0] = 8;
            }
        };
        validateMutable(41, validator, "primitiveByteArray2Binary");
    }

    @Test
    @Skip(databaseNames = "org.eclipse.persistence.platform.database.MaxDBPlatform")
    public void testPrimitiveByteArray2Longvarbinary() {
        final byte[] UNCHANGED = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Longvarbinary(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Longvarbinary(new byte[] { 8, 1, 2, 3, 4, 5, 6, 7 });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Longvarbinary(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveByteArray2Longvarbinary() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getPrimitiveByteArray2Longvarbinary());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getPrimitiveByteArray2Longvarbinary()[0] = 8;
            }
        };
        validateMutable(42, validator, "primitiveByteArray2Longvarbinary");
    }

    @Test
    public void testPrimitiveByteArray2Blob() {
        final byte[] UNCHANGED = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Blob(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Blob(new byte[] { 8, 1, 2, 3, 4, 5, 6, 7 });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveByteArray2Blob(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveByteArray2Blob() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getPrimitiveByteArray2Blob());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getPrimitiveByteArray2Blob()[0] = 8;
            }
        };
        validateMutable(43, validator, "primitiveByteArray2Blob");
    }

    @Test
    public void testPrimitiveCharArray2Varchar() {
        final char[] UNCHANGED = new char[] { 'U', 'N', 'C', 'H', 'A', 'N', 'G', 'E', 'D' };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveCharArray2Varchar(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveCharArray2Varchar(new char[] { 'C', 'H', 'A', 'N', 'G', 'E', 'D' });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveCharArray2Varchar(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveCharArray2Varchar() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getPrimitiveCharArray2Varchar());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getPrimitiveCharArray2Varchar()[0] = 'X';
            }
        };
        validateMutable(44, validator, "primitiveCharArray2Varchar");
    }

    @Test
    public void testPrimitiveCharArray2Clob() {
        final char[] UNCHANGED = new char[] { 'U', 'N', 'C', 'H', 'A', 'N', 'G', 'E', 'D' };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveCharArray2Clob(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveCharArray2Clob(new char[] { 'C', 'H', 'A', 'N', 'G', 'E', 'D' });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setPrimitiveCharArray2Clob(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getPrimitiveCharArray2Clob() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getPrimitiveCharArray2Clob());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getPrimitiveCharArray2Clob()[0] = 'X';
            }
        };
        validateMutable(45, validator, "primitiveCharArray2Clob");
    }

    @Test
    public void testWrapperByteArray2Binary() {
        final Byte[] UNCHANGED = new Byte[] { Byte.valueOf((byte) 0), Byte.valueOf((byte) 1), Byte.valueOf((byte) 2),
                Byte.valueOf((byte) 3), Byte.valueOf((byte) 4), Byte.valueOf((byte) 5), Byte.valueOf((byte) 6),
                Byte.valueOf((byte) 7), };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Binary(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Binary(new Byte[] { Byte.valueOf((byte) 8), Byte.valueOf((byte) 1),
                        Byte.valueOf((byte) 2), Byte.valueOf((byte) 3), Byte.valueOf((byte) 4), Byte.valueOf((byte) 5),
                        Byte.valueOf((byte) 6), Byte.valueOf((byte) 7), });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Binary(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperByteArray2Binary() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getWrapperByteArray2Binary());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getWrapperByteArray2Binary()[0] = Byte.valueOf((byte) 8);
            }
        };
        validateMutable(46, validator, "wrapperByteArray2Binary");
    }

    @Test
    public void testWrapperByteArray2Longvarbinary() {
        final Byte[] UNCHANGED = new Byte[] { Byte.valueOf((byte) 0), Byte.valueOf((byte) 1), Byte.valueOf((byte) 2),
                Byte.valueOf((byte) 3), Byte.valueOf((byte) 4), Byte.valueOf((byte) 5), Byte.valueOf((byte) 6),
                Byte.valueOf((byte) 7), };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Longvarbinary(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Longvarbinary(new Byte[] { Byte.valueOf((byte) 8), Byte.valueOf((byte) 1),
                        Byte.valueOf((byte) 2), Byte.valueOf((byte) 3), Byte.valueOf((byte) 4), Byte.valueOf((byte) 5),
                        Byte.valueOf((byte) 6), Byte.valueOf((byte) 7), });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Longvarbinary(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperByteArray2Longvarbinary() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getWrapperByteArray2Longvarbinary());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getWrapperByteArray2Longvarbinary()[0] = Byte.valueOf((byte) 8);
            }
        };
        validateMutable(47, validator, "wrapperByteArray2Longvarbinary");
    }

    @Test
    public void testWrapperByteArray2Blob() {
        final Byte[] UNCHANGED = new Byte[] { Byte.valueOf((byte) 0), Byte.valueOf((byte) 1), Byte.valueOf((byte) 2),
                Byte.valueOf((byte) 3), Byte.valueOf((byte) 4), Byte.valueOf((byte) 5), Byte.valueOf((byte) 6),
                Byte.valueOf((byte) 7), };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Blob(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Blob(new Byte[] { Byte.valueOf((byte) 8), Byte.valueOf((byte) 1),
                        Byte.valueOf((byte) 2), Byte.valueOf((byte) 3), Byte.valueOf((byte) 4), Byte.valueOf((byte) 5),
                        Byte.valueOf((byte) 6), Byte.valueOf((byte) 7) });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperByteArray2Blob(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperByteArray2Blob() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getWrapperByteArray2Blob());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getWrapperByteArray2Blob()[0] = Byte.valueOf((byte) 8);
            }
        };
        validateMutable(48, validator, "wrapperByteArray2Blob");
    }

    @SuppressWarnings("boxing")
    @Test
    public void testWrapperCharArray2Varchar() {
        final Character[] UNCHANGED = new Character[] { 'U', 'N', 'C', 'H', 'A', 'N', 'G', 'E', 'D' };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacterArray2Varchar(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacterArray2Varchar(new Character[] { 'C', 'H', 'A', 'N', 'G', 'E', 'D' });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacterArray2Varchar(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperCharacterArray2Varchar() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getWrapperCharacterArray2Varchar());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getWrapperCharacterArray2Varchar()[0] = 'X';
            }
        };
        validateMutable(49, validator, "wrapperCharArray2Varchar");
    }

    @SuppressWarnings("boxing")
    @Test
    public void testWrapperCharArray2Clob() {
        final Character[] UNCHANGED = new Character[] { 'U', 'N', 'C', 'H', 'A', 'N', 'G', 'E', 'D' };
        MutableValidator validator = new MutableValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacterArray2Clob(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacterArray2Clob(new Character[] { 'C', 'H', 'A', 'N', 'G', 'E', 'D' });
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setWrapperCharacterArray2Clob(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getWrapperCharacterArray2Clob() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !Arrays.equals(UNCHANGED, obj.getWrapperCharacterArray2Clob());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                obj.getWrapperCharacterArray2Clob()[0] = 'X';
            }
        };
        validateMutable(50, validator, "wrapperCharArray2Clob");
    }

    @Test
    public void testSerializable() {
        MutableValidator validator = new MutableValidator() {
            UserDefinedSerializable UNCHANGED = new UserDefinedSerializable("Unchanged");

            public void set(BasicTypesPropertyAccess obj) {
                obj.setSerializable(UNCHANGED);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setSerializable(new UserDefinedSerializable("Changed"));
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setSerializable(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getSerializable() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return !UNCHANGED.equals(obj.getSerializable());
            }

            public void mutate(BasicTypesPropertyAccess obj) {
                ((UserDefinedSerializable) obj.getSerializable()).setTxt("Changed");
            }
        };
        validateMutable(51, validator, "serializable");
    }

    @Test
    public void testEnumString() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setEnumString(UserDefinedEnum.HUGO);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setEnumString(UserDefinedEnum.EMIL);
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setEnumString(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getEnumString() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getEnumString() != UserDefinedEnum.HUGO;
            }
        };
        validateReference(52, validator, "enumString");
    }

    @Test
    public void testEnumOrdinal() {
        ReferenceValidator validator = new ReferenceValidator() {
            public void set(BasicTypesPropertyAccess obj) {
                obj.setEnumOrdinal(UserDefinedEnum.HUGO);
            }

            public void change(BasicTypesPropertyAccess obj) {
                obj.setEnumOrdinal(UserDefinedEnum.EMIL);
            }

            public void setNull(BasicTypesPropertyAccess obj) {
                obj.setEnumOrdinal(null);
            }

            public boolean isNull(BasicTypesPropertyAccess obj) {
                return obj.getEnumOrdinal() == null;
            }

            public boolean isChanged(BasicTypesPropertyAccess obj) {
                return obj.getEnumOrdinal() != UserDefinedEnum.HUGO;
            }
        };
        validateReference(53, validator, "enumOrdinal");
    }

    @Test
    @Bugzilla(bugid=309681)
    public void testNullsPAshort() throws SQLException {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        BasicTypesPropertyAccess obj = new BasicTypesPropertyAccess(8888);
        try {
            obj.fill();
            env.beginTransaction(em);
            em.persist(obj);
            env.commitTransactionAndClear(em);

            Connection con = env.getDataSource().getConnection();
            try {
                String stmt = "update TMP_BASIC_TYPES_PA set P_SHORT = ? where ID = 8888";
                PreparedStatement pstmt = con.prepareStatement(stmt);
                try {
                    pstmt.setNull(1, Types.SMALLINT);
                    pstmt.executeUpdate();
                } finally {
                    pstmt.close();
                }
                if (!con.getAutoCommit()) {
                    con.commit();
                }
            } finally {
                con.close();
            }

            obj = em.find(BasicTypesPropertyAccess.class, new Integer(8888));
            flop("missing exception");
        } catch (PersistenceException iae) {
            // $JL-EXC$ expected behavior
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    @Bugzilla(bugid = 309681)
    public void testNullsPAint() throws SQLException {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        BasicTypesPropertyAccess obj = new BasicTypesPropertyAccess(8889);
        try {
            obj.fill();
            env.beginTransaction(em);
            em.persist(obj);
            env.commitTransactionAndClear(em);

            Connection con = env.getDataSource().getConnection();
            try {
                String stmt = "update TMP_BASIC_TYPES_PA set P_INT = ? where ID = 8889";
                PreparedStatement pstmt = con.prepareStatement(stmt);
                try {
                    pstmt.setNull(1, Types.INTEGER);
                    pstmt.executeUpdate();
                } finally {
                    pstmt.close();
                }
                if (!con.getAutoCommit()) {
                    con.commit();
                }
            } finally {
                con.close();
            }

            obj = em.find(BasicTypesPropertyAccess.class, new Integer(8889));
            flop("missing exception");
        } catch (PersistenceException iae) {
            // $JL-EXC$ expected behavior
        } finally {
            closeEntityManager(em);
        }
    }

    private interface Validator {
        void set(BasicTypesPropertyAccess obj);

        void change(BasicTypesPropertyAccess obj);

        boolean isChanged(BasicTypesPropertyAccess obj);
    }

    private interface ReferenceValidator extends Validator {
        boolean isNull(BasicTypesPropertyAccess obj);

        void setNull(BasicTypesPropertyAccess obj);
    }

    private interface MutableValidator extends ReferenceValidator {
        void mutate(BasicTypesPropertyAccess obj);
    }
}
