package jpa;

import java.util.List;
import java.util.concurrent.Callable;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.LockModeType;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class Test9 {

  /**
   * Test des entités versionnées et de la méthode lock.
   * @param args
   * @throws InterruptedException 
   */
  public static void main(String[] args) throws InterruptedException {
    final EntityManagerFactory emf = 
      Persistence.createEntityManagerFactory("Employes");
    EntityManager em = emf.createEntityManager();
    EntityTransaction t = em.getTransaction();
    t.begin();
    // Récupère un département
    Query q = em.createQuery("select d from Departement d");
    List<Departement> liste = q.getResultList();
    Departement d = liste.get(0);
    System.out.println("**Au début : " + d);
    // Sans ce lock, il faut que cette transaction modifie d pour
    // qu'une exception soit levée.
    // Le mode WRITE incrémenterait le numéro de version
    em.lock(d, LockModeType.READ);
    // Vérification du numéro de version
    System.out.println("**Après le lock : " + d);
    // Affichage du numéro de version du département
    System.out.println(d.getVersion());
    // Lancer ici un autre thread qui utilise un autre entityManager
    // pour modifier le nom du département.
    Runnable tache = new Runnable() {
      /**
       * Tâche qui modifie le nom du département bloqué et qui renvoie
       * la valeur du numéro de version lu au début (à la fin ?).
       */
      @Override
      public void run() {
        try {
          Thread.sleep(2000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        EntityManager em = emf.createEntityManager();
        EntityTransaction t = em.getTransaction();
        t.begin();
        Query q = em.createQuery("select d from Departement d");
        List<Departement> liste = q.getResultList();
        Departement d = liste.get(0);
        d.setNom("Truc33");
        t.commit();
        System.out.println("**Dans l'autre thread : " + d);
        em.close();
      }
    };
    Thread thread = new Thread(tache);
    thread.start();
    // Attend pour permettre une modification concurrente
    System.out.println("Dors....");
    Thread.sleep(10000);
    // Modification du département
    // Il faut cette ligne pour provoquer une exception s'il n'y a pas eu de lock
//    d.setNom("Direction générale3");
    System.out.println("**Après la modification par le thread principal : " + d);

    // Provoquera une OptimisticLockException à cause de la modification 
    // effectuée par le thread lancé en parallèle.
    t.commit();
    System.out.println("Après le commit du thread principal : " + d);

  }

}
