<commit_before>package de.hhu.stups.plues.data;

import de.hhu.stups.plues.data.entities.AbstractUnit;
import de.hhu.stups.plues.data.entities.Course;
import de.hhu.stups.plues.data.entities.Group;
import de.hhu.stups.plues.data.entities.Info;
import de.hhu.stups.plues.data.entities.Level;
import de.hhu.stups.plues.data.entities.Log;
import de.hhu.stups.plues.data.entities.Module;
import de.hhu.stups.plues.data.entities.ModuleAbstractUnitSemester;
import de.hhu.stups.plues.data.entities.ModuleAbstractUnitType;
import de.hhu.stups.plues.data.entities.Session;
import de.hhu.stups.plues.data.entities.Unit;
import de.hhu.stups.plues.data.sessions.SessionFacade;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 * Database based storage for timetable data.
 */
public class SqliteStore implements Store {
  private final Logger logger = Logger.getLogger(getClass().getSimpleName());
  private String dbPath;
  private SessionFactory sessionFactory;

  public SqliteStore(final String dbPath) throws IncompatibleSchemaError, StoreException {
    this.init(dbPath);
  }

  private void logException(final Exception exception) {
    logger.log(java.util.logging.Level.SEVERE, "an exception was thrown", exception);
  }

  @Override
  public synchronized void init() throws IncompatibleSchemaError, StoreException {
    assert this.dbPath != null;
    try {
      openDataBase(dbPath);
      checkSchemaVersion();
    } catch (final ClassNotFoundException exception) {
      this.close();
      logException(exception);
      throw new StoreException(exception);
    } catch (final IncompatibleSchemaError exception) {
      this.close();
      throw exception;
    }
  }

  @Override
  public synchronized void init(final String dbpath)
      throws IncompatibleSchemaError, StoreException {
    this.dbPath = dbpath;
    this.init();
  }

  private synchronized <T> T getById(final Integer key, final Class<T> type) {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final CriteriaBuilder cb = session.getCriteriaBuilder();

    final CriteriaQuery<T> query = cb.createQuery(type);

    final Root<T> root = query.from(type);
    query.where(cb.equal(root.get("id"), key));

    final T result = session.createQuery(query).setCacheable(true).getSingleResult();
    tx.commit();
    return result;
  }

  private synchronized <T> T getByKey(final String key, final Class<T> type) {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();

    final CriteriaBuilder cb = session.getCriteriaBuilder();

    final CriteriaQuery<T> query = cb.createQuery(type);

    final Root<T> root = query.from(type);
    query.where(cb.equal(root.get("key"), key));

    final T result = session.createQuery(query).setCacheable(true).getSingleResult();
    tx.commit();

    return result;
  }

  @Override
  public synchronized String getInfoByKey(final String key) {
    return getByKey(key, Info.class).getValue();
  }

  @Override
  public synchronized Course getCourseByKey(final String key) {
    return getByKey(key, Course.class);
  }

  @Override
  public synchronized List<Info> getInfo() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Info> result = session
        .createQuery("from Info", Info.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<AbstractUnit> getAbstractUnits() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<AbstractUnit> result = session
        .createQuery("from AbstractUnit", AbstractUnit.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<AbstractUnit> getAbstractUnitsWithoutUnits() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();

    final CriteriaBuilder cb = session.getCriteriaBuilder();
    final CriteriaQuery<AbstractUnit> query =
        cb.createQuery(AbstractUnit.class);

    final Root<AbstractUnit> root = query.from(AbstractUnit.class);
    query.where(cb.isEmpty(root.get("units")));

    final List<AbstractUnit> result = session.createQuery(query)
        .setCacheable(true).list();
    tx.commit();

    return result;
  }

  @Override
  public synchronized AbstractUnit getAbstractUnitById(final Integer key) {
    return getById(key, AbstractUnit.class);
  }

  @Override
  public synchronized Group getGroupById(final Integer gid) {
    return getById(gid, Group.class);
  }

  @Override
  public synchronized Module getModuleById(final Integer mid) {
    return getById(mid, Module.class);
  }

  @Override
  public synchronized Unit getUnitById(final Integer uid) {
    return getById(uid, Unit.class);
  }

  @Override
  public synchronized List<Course> getCourses() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final Query<Course> query = session.createQuery("from Course", Course.class);
    final List<Course> result = query.setCacheable(true).list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Group> getGroups() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Group> result = session
        .createQuery("from Group", Group.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Level> getLevels() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Level> result = session
        .createQuery("from Level", Level.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Module> getModules() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Module> result = session
        .createQuery("from Module", Module.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<ModuleAbstractUnitSemester> getModuleAbstractUnitSemester() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<ModuleAbstractUnitSemester> result = session
        .createQuery("from ModuleAbstractUnitSemester", ModuleAbstractUnitSemester.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<ModuleAbstractUnitType> getModuleAbstractUnitType() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<ModuleAbstractUnitType> result = session
        .createQuery("from ModuleAbstractUnitType", ModuleAbstractUnitType.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Session> getSessions() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final Query<Session> query = session.createQuery("from Session", Session.class);
    final List<Session> result = query.setCacheable(true).list();
    tx.commit();
    return result;
  }

  /**
   * Find a session using a given Id. Return this found session.
   * @param id Id of the session
   * @return Found session
   */
  @Override
  public synchronized Session getSessionById(final int id) {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final Session result = session.get(Session.class, id);
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Unit> getUnits() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Unit> result = session
        .createQuery("from Unit", Unit.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Log> getLogEntries() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Log> result = session.createQuery("from Log", Log.class).setCacheable(true).list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized void moveSession(final SessionFacade sessionFacade,
      final SessionFacade.Slot slot) {
    final String srcDay = sessionFacade.getSlot().getDayString();
    final String srcTime = sessionFacade.getSlot().getTime().toString();
    final String targetDay = slot.getDayString();
    final String targetTime = slot.getTime().toString();

    sessionFacade.setSlot(slot);

    final Log log = new Log();
    // TODO day and time should each be a field in the log table
    log.setSrc(srcDay + srcTime);
    log.setTarget(targetDay + targetTime);
    log.setSession(sessionFacade.getSession());

    final org.hibernate.Session s = sessionFactory.getCurrentSession();

    final Transaction tx = s.beginTransaction();
    try {
      final Query query
          = s.createQuery("UPDATE Session SET time = :time, day = :day WHERE id = :session_id");
      query.setParameter("time", Integer.valueOf(targetTime));
      query.setParameter("day", targetDay);
      query.setParameter("session_id", sessionFacade.getSession().getId());
      query.executeUpdate();
      s.persist(log);
      // TODO: ensure hibernate caches to be up to date
      tx.commit();
    } catch (final HibernateException exception) {
      if (tx != null) {<commit_msg>Make sure we start the transaction in case it is not active<commit_after>package de.hhu.stups.plues.data;

import de.hhu.stups.plues.data.entities.AbstractUnit;
import de.hhu.stups.plues.data.entities.Course;
import de.hhu.stups.plues.data.entities.Group;
import de.hhu.stups.plues.data.entities.Info;
import de.hhu.stups.plues.data.entities.Level;
import de.hhu.stups.plues.data.entities.Log;
import de.hhu.stups.plues.data.entities.Module;
import de.hhu.stups.plues.data.entities.ModuleAbstractUnitSemester;
import de.hhu.stups.plues.data.entities.ModuleAbstractUnitType;
import de.hhu.stups.plues.data.entities.Session;
import de.hhu.stups.plues.data.entities.Unit;
import de.hhu.stups.plues.data.sessions.SessionFacade;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 * Database based storage for timetable data.
 */
public class SqliteStore implements Store {
  private final Logger logger = Logger.getLogger(getClass().getSimpleName());
  private String dbPath;
  private SessionFactory sessionFactory;

  public SqliteStore(final String dbPath) throws IncompatibleSchemaError, StoreException {
    this.init(dbPath);
  }

  private void logException(final Exception exception) {
    logger.log(java.util.logging.Level.SEVERE, "an exception was thrown", exception);
  }

  @Override
  public synchronized void init() throws IncompatibleSchemaError, StoreException {
    assert this.dbPath != null;
    try {
      openDataBase(dbPath);
      checkSchemaVersion();
    } catch (final ClassNotFoundException exception) {
      this.close();
      logException(exception);
      throw new StoreException(exception);
    } catch (final IncompatibleSchemaError exception) {
      this.close();
      throw exception;
    }
  }

  @Override
  public synchronized void init(final String dbpath)
      throws IncompatibleSchemaError, StoreException {
    this.dbPath = dbpath;
    this.init();
  }

  private synchronized <T> T getById(final Integer key, final Class<T> type) {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final CriteriaBuilder cb = session.getCriteriaBuilder();

    final CriteriaQuery<T> query = cb.createQuery(type);

    final Root<T> root = query.from(type);
    query.where(cb.equal(root.get("id"), key));

    final T result = session.createQuery(query).setCacheable(true).getSingleResult();
    tx.commit();
    return result;
  }

  private synchronized <T> T getByKey(final String key, final Class<T> type) {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();

    final CriteriaBuilder cb = session.getCriteriaBuilder();

    final CriteriaQuery<T> query = cb.createQuery(type);

    final Root<T> root = query.from(type);
    query.where(cb.equal(root.get("key"), key));

    final T result = session.createQuery(query).setCacheable(true).getSingleResult();
    tx.commit();

    return result;
  }

  @Override
  public synchronized String getInfoByKey(final String key) {
    return getByKey(key, Info.class).getValue();
  }

  @Override
  public synchronized Course getCourseByKey(final String key) {
    return getByKey(key, Course.class);
  }

  @Override
  public synchronized List<Info> getInfo() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Info> result = session
        .createQuery("from Info", Info.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<AbstractUnit> getAbstractUnits() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<AbstractUnit> result = session
        .createQuery("from AbstractUnit", AbstractUnit.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<AbstractUnit> getAbstractUnitsWithoutUnits() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();

    final CriteriaBuilder cb = session.getCriteriaBuilder();
    final CriteriaQuery<AbstractUnit> query =
        cb.createQuery(AbstractUnit.class);

    final Root<AbstractUnit> root = query.from(AbstractUnit.class);
    query.where(cb.isEmpty(root.get("units")));

    final List<AbstractUnit> result = session.createQuery(query)
        .setCacheable(true).list();
    tx.commit();

    return result;
  }

  @Override
  public synchronized AbstractUnit getAbstractUnitById(final Integer key) {
    return getById(key, AbstractUnit.class);
  }

  @Override
  public synchronized Group getGroupById(final Integer gid) {
    return getById(gid, Group.class);
  }

  @Override
  public synchronized Module getModuleById(final Integer mid) {
    return getById(mid, Module.class);
  }

  @Override
  public synchronized Unit getUnitById(final Integer uid) {
    return getById(uid, Unit.class);
  }

  @Override
  public synchronized List<Course> getCourses() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final Query<Course> query = session.createQuery("from Course", Course.class);
    final List<Course> result = query.setCacheable(true).list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Group> getGroups() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Group> result = session
        .createQuery("from Group", Group.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Level> getLevels() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Level> result = session
        .createQuery("from Level", Level.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Module> getModules() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Module> result = session
        .createQuery("from Module", Module.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<ModuleAbstractUnitSemester> getModuleAbstractUnitSemester() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<ModuleAbstractUnitSemester> result = session
        .createQuery("from ModuleAbstractUnitSemester", ModuleAbstractUnitSemester.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<ModuleAbstractUnitType> getModuleAbstractUnitType() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<ModuleAbstractUnitType> result = session
        .createQuery("from ModuleAbstractUnitType", ModuleAbstractUnitType.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Session> getSessions() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final Query<Session> query = session.createQuery("from Session", Session.class);
    final List<Session> result = query.setCacheable(true).list();
    tx.commit();
    return result;
  }

  /**
   * Find a session using a given Id. Return this found session.
   * @param id Id of the session
   * @return Found session
   */
  @Override
  public synchronized Session getSessionById(final int id) {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final Session result = session.get(Session.class, id);
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Unit> getUnits() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Unit> result = session
        .createQuery("from Unit", Unit.class)
        .setCacheable(true)
        .list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized List<Log> getLogEntries() {
    final org.hibernate.Session session = sessionFactory.getCurrentSession();
    final Transaction tx = session.beginTransaction();
    final List<Log> result = session.createQuery("from Log", Log.class).setCacheable(true).list();
    tx.commit();
    return result;
  }

  @Override
  public synchronized void moveSession(final SessionFacade sessionFacade,
      final SessionFacade.Slot slot) {
    final String srcDay = sessionFacade.getSlot().getDayString();
    final String srcTime = sessionFacade.getSlot().getTime().toString();
    final String targetDay = slot.getDayString();
    final String targetTime = slot.getTime().toString();

    sessionFacade.setSlot(slot);

    final Log log = new Log();
    // TODO day and time should each be a field in the log table
    log.setSrc(srcDay + srcTime);
    log.setTarget(targetDay + targetTime);
    log.setSession(sessionFacade.getSession());

    final org.hibernate.Session s = sessionFactory.getCurrentSession();

    final Transaction tx = s.beginTransaction();

    if (!tx.isActive()) {
      tx.begin();
    }
    try {
      final Query query
          = s.createQuery("UPDATE Session SET time = :time, day = :day WHERE id = :session_id");
      query.setParameter("time", Integer.valueOf(targetTime));
      query.setParameter("day", targetDay);
      query.setParameter("session_id", sessionFacade.getSession().getId());
      query.executeUpdate();
      s.persist(log);
      // TODO: ensure hibernate caches to be up to date
      tx.commit();
    } catch (final HibernateException exception) {
      if (tx != null) {
{'fraction_non_alphanumeric': 0.10773570074443982, 'fraction_numerical': 0.0, 'mean_word_length': 3.8711711711711714, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1559432', 'n_tokens_mistral': 6020, 'n_tokens_neox': 5906, 'n_words': 1462}