/**
   * test for issue 635: NullPointerException occuring for Object typed version fields. Employee has
   * a write lock (version) field of type Integer The NullPointerException is thrown when comparing
   * versions in ObjectChangeSet#compareWriteLockValues
   */
  public void testCreateEmployeeWithFlush() {
    EntityManager em = createEntityManager("fieldaccess");
    Project project1, project2;
    Employee employee;

    try {
      beginTransaction(em);
      employee = ModelExamples.employeeExample1();
      em.persist(employee);

      // first flush: Employee is written to the database
      Query query = em.createNamedQuery("findFieldAccessProjectByName");
      query.setParameter("name", "Farmer effecency evaluations");
      project1 = (Project) query.getSingleResult();
      employee.getProjects().add(project1);

      // second flush: Employee is modified, but
      // no update to EMPLOYEE table; only join table entry is written
      query = em.createNamedQuery("findFieldAccessProjectByName");
      query.setParameter("name", "Feline Demographics Assesment");
      project2 = (Project) query.getSingleResult();
      employee.getProjects().add(project2);

      // third flush: Employee is modified, but
      // no update to EMPLOYEE table; only join table entry is written
      // A NullPointerException in ObjectChangeSet#compareWriteLockValues
      commitTransaction(em);
    } catch (RuntimeException e) {
      if (isTransactionActive(em)) {
        rollbackTransaction(em);
      }
      closeEntityManager(em);
      throw e;
    }
  }
  protected void clear() {
    UnitOfWork uow = acquireUnitOfWork();

    // use alternate way for Symfoware as it doesn't support UpdateAll/DeleteAll on multi-table
    // objects (see rfe 298193)
    if (!(JUnitTestCase.getServerSession("fieldaccess")).getPlatform().isSymfoware()) {
      UpdateAllQuery updateEmployees = new UpdateAllQuery(Employee.class);
      updateEmployees.addUpdate("manager", null);
      updateEmployees.addUpdate("address", null);
      uow.executeQuery(updateEmployees);

      uow.executeQuery(new DeleteAllQuery(Employee.class));
    } else {
      Iterator<Employee> emps = uow.readAllObjects(Employee.class).iterator();
      while (emps.hasNext()) {
        Employee emp = emps.next();
        emp.setManager(null);
        emp.setAddress(null);
        uow.deleteObject(emp);
      }
      ;
    }

    UpdateAllQuery updateProjects = new UpdateAllQuery(Project.class);
    updateProjects.addUpdate("teamLeader", null);
    uow.executeQuery(updateProjects);

    uow.executeQuery(new DeleteAllQuery(PhoneNumber.class));
    uow.executeQuery(new DeleteAllQuery(Address.class));
    uow.executeQuery(new DeleteAllQuery(Project.class));

    uow.commit();
    dbSessionClearCache();
  }
  /**
   * test: updating the version field with the in-memory value. This should be allowed; there's no
   * change for TopLink to detect this.
   */
  public void testVersionUpdateWithCorrectValue() {
    EntityManager em = createEntityManager("fieldaccess");
    Employee employee;

    try {
      beginTransaction(em);
      employee = ModelExamples.employeeExample1();
      em.persist(employee);
      commitTransaction(em);

      beginTransaction(em);
      employee.setVersion(1);
      commitTransaction(em);
    } catch (RuntimeException re) {
      if (isTransactionActive(em)) {
        rollbackTransaction(em);
      }
      closeEntityManager(em);
      throw re;
    }
  }
  /**
   * test: updating the version field with value != in-memory value. This should throw an
   * OptimisticLockException
   */
  public void testVersionUpdateWithIncorrectValue() {
    EntityManager em = createEntityManager("fieldaccess");
    Employee employee;

    try {
      beginTransaction(em);
      employee = ModelExamples.employeeExample1();
      em.persist(employee);
      commitTransaction(em);

      beginTransaction(em);
      Employee employee1 = em.find(Employee.class, employee.getId());
      employee1.setVersion(2);
      commitTransaction(em);
      fail("updating object version with wrong value didn't throw exception");
    } catch (PersistenceException pe) {
      // expected behavior
    } catch (Exception exception) {
      Throwable persistenceException = exception;
      // Remove an wrapping exceptions such as rollback, runtime, etc.
      while (persistenceException != null
          && !(persistenceException instanceof OptimisticLockException)) {
        // In the server this is always a rollback exception, need to get nested exception.
        persistenceException = persistenceException.getCause();
      }
      if (persistenceException instanceof OptimisticLockException) {
        return;
      } else {
        fail(
            "updating object version with wrong value threw a wrong exception: "
                + exception.getMessage());
      }
    } finally {
      if (isTransactionActive(em)) {
        rollbackTransaction(em);
      }
      closeEntityManager(em);
    }
  }
  public void testTwoUnrelatedResultWithOneToOneJoinsWithExtraItem() {
    if (getServerSession("fieldaccess").getPlatform().isSymfoware()) {
      getServerSession("fieldaccess")
          .logMessage(
              "Test testTwoUnrelatedResultWithOneToOneJoinsWithExtraItem skipped for this platform, "
                  + "Symfoware doesn't support UpdateAll/DeleteAll on multi-table objects (see rfe 298193).");
      return;
    }
    ReadAllQuery raq = new ReadAllQuery(Employee.class);
    raq.setSelectionCriteria(
        raq.getExpressionBuilder()
            .get("lastName")
            .equal("Way")
            .or(raq.getExpressionBuilder().get("lastName").equal("Jones")));
    Employee emp = (Employee) ((Vector) getDbSession().executeQuery(raq)).firstElement();
    emp.getAddress();

    raq = new ReadAllQuery(Address.class);
    raq.setSelectionCriteria(raq.getExpressionBuilder().get("city").like("%ttawa%"));
    Address addr = (Address) ((Vector) getDbSession().executeQuery(raq)).firstElement();
    addr.getEmployees();
    for (Iterator iterator = addr.getEmployees().iterator(); iterator.hasNext(); ) {
      ((Employee) iterator.next()).getAddress();
    }

    getDbSession().getIdentityMapAccessor().initializeAllIdentityMaps();

    ReportQuery query = new ReportQuery();
    query.setShouldReturnWithoutReportQueryResult(true);
    query.setReferenceClass(Employee.class);

    ExpressionBuilder eb = new ExpressionBuilder(Address.class);
    query.setSelectionCriteria(
        query
            .getExpressionBuilder()
            .get("id")
            .equal(emp.getId())
            .and(eb.get("id").equal(addr.getId())));

    List list = new ArrayList();
    list.add(query.getExpressionBuilder().get("address"));
    query.addItem("employee", query.getExpressionBuilder(), list);
    query.addItem("employee_name", query.getExpressionBuilder().get("firstName"));

    list = new ArrayList();
    list.add(eb.anyOf("employees"));
    query.addItem("address", eb, list);

    Vector result = (Vector) getDbSession().executeQuery(query);

    UpdateAllQuery updall = new UpdateAllQuery(Employee.class);
    updall.addUpdate("address", null);
    updall.setSelectionCriteria(updall.getExpressionBuilder().get("id").equal(emp.getId()));
    UnitOfWork uow = getDbSession().acquireUnitOfWork();
    uow.executeQuery(updall);

    updall = new UpdateAllQuery(Employee.class);
    updall.addUpdate("address", null);
    updall.setSelectionCriteria(
        updall.getExpressionBuilder().get("address").get("id").equal(addr.getId()));
    uow.executeQuery(updall);

    uow.commit();

    Employee emp2 = (Employee) ((Object[]) result.firstElement())[0];
    Address addr2 = (Address) ((Object[]) result.firstElement())[2];
    try {
      assertTrue(
          "Address were not joined correctly, emp.getAddress() = null",
          (emp2.getAddress() != null));
      assertTrue(
          "Employees were not joined correctly, addr.employees.size = "
              + addr.getEmployees().size()
              + "addr2.employees.size = "
              + addr2.getEmployees().size(),
          (addr.getEmployees().size() == addr2.getEmployees().size()));
      if (!emp2.getFirstName().equals(((Object[]) result.firstElement())[1])) {
        fail("Failed to return employee name as an separate item");
      }

    } finally {
      testSetup();
    }
  }
  public void testMultipleUnrelatedResultWithOneToManyJoins() {
    if (getServerSession("fieldaccess").getPlatform().isSymfoware()) {
      getServerSession("fieldaccess")
          .logMessage(
              "Test testMultipleUnrelatedResultWithOneToManyJoins skipped for this platform, "
                  + "Symfoware doesn't support UpdateAll/DeleteAll on multi-table objects (see rfe 298193).");
      return;
    }
    ReadAllQuery raq = new ReadAllQuery(Employee.class);
    raq.setSelectionCriteria(raq.getExpressionBuilder().notEmpty("phoneNumbers"));
    Employee emp = (Employee) ((Vector) getDbSession().executeQuery(raq)).firstElement();
    emp.getPhoneNumbers();
    for (Iterator iterator = emp.getPhoneNumbers().iterator(); iterator.hasNext(); ) {
      ((PhoneNumber) iterator.next()).getOwner();
    }

    raq = new ReadAllQuery(Address.class);
    raq.setSelectionCriteria(raq.getExpressionBuilder().get("city").like("%ttawa%"));
    Address addr = (Address) ((Vector) getDbSession().executeQuery(raq)).firstElement();
    addr.getEmployees();
    for (Iterator iterator = addr.getEmployees().iterator(); iterator.hasNext(); ) {
      Employee addrEmp = (Employee) iterator.next();
      addrEmp.getAddress();
      addrEmp
          .getPhoneNumbers()
          .size(); // as the report query will join in all phones to all emps, make sure we can
                   // compare.
    }

    getDbSession().getIdentityMapAccessor().initializeAllIdentityMaps();

    ReportQuery query = new ReportQuery();
    query.setShouldReturnWithoutReportQueryResult(true);
    query.setReferenceClass(Address.class);

    ExpressionBuilder eb = new ExpressionBuilder(Employee.class);

    List list = new ArrayList();
    list.add(eb.anyOf("phoneNumbers"));
    query.addItem("employee", eb, list);

    list = new ArrayList();
    list.add(query.getExpressionBuilder().anyOf("employees"));
    query.addItem("address", query.getExpressionBuilder(), list);

    query.setSelectionCriteria(query.getExpressionBuilder().get("id").equal(addr.getId()));

    Vector result = (Vector) getDbSession().executeQuery(query);

    DeleteAllQuery deleteAll = new DeleteAllQuery(PhoneNumber.class);
    deleteAll.setSelectionCriteria(
        deleteAll.getExpressionBuilder().get("owner").get("id").equal(emp.getId()));
    UnitOfWork uow = getDbSession().acquireUnitOfWork();
    uow.executeQuery(deleteAll);

    UpdateAllQuery updall = new UpdateAllQuery(Employee.class);
    updall.addUpdate("address", null);
    updall.setSelectionCriteria(
        updall.getExpressionBuilder().get("address").get("id").equal(addr.getId()));
    uow.executeQuery(updall);

    uow.commit();

    try {
      Employee emp2 = null;
      Address addr2 = null;
      for (Iterator iterator = result.iterator(); iterator.hasNext(); ) {
        Object[] items = (Object[]) iterator.next();
        emp2 = (Employee) items[0];
        if (emp2.getId().equals(emp.getId())) {
          addr2 = (Address) items[1];
          break;
        }
      }
      assertTrue(
          "PhoneNumbers were not joined correctly, emp.getPhoneNumbers().size = "
              + emp.getPhoneNumbers().size()
              + " emp2.getPhoneNumbers().size = "
              + emp2.getPhoneNumbers().size(),
          (emp.getPhoneNumbers().size() == emp2.getPhoneNumbers().size()));
      assertTrue(
          "Employees were not joined correctly, addr.employees.size = "
              + addr.getEmployees().size()
              + "addr2.employees.size = "
              + addr2.getEmployees().size(),
          (addr.getEmployees().size() == addr2.getEmployees().size()));
    } finally {
      testSetup();
    }
  }