diff options
Diffstat (limited to 'sql-persistence/src/main/java/io/trygvis/persistence/sql/SqlEntityManager.java')
-rw-r--r-- | sql-persistence/src/main/java/io/trygvis/persistence/sql/SqlEntityManager.java | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/sql-persistence/src/main/java/io/trygvis/persistence/sql/SqlEntityManager.java b/sql-persistence/src/main/java/io/trygvis/persistence/sql/SqlEntityManager.java new file mode 100644 index 0000000..adcd2e2 --- /dev/null +++ b/sql-persistence/src/main/java/io/trygvis/persistence/sql/SqlEntityManager.java @@ -0,0 +1,419 @@ +package io.trygvis.persistence.sql; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.FlushModeType; +import javax.persistence.LockModeType; +import javax.persistence.PersistenceException; +import javax.persistence.Query; +import javax.persistence.RollbackException; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.metamodel.Metamodel; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static javax.persistence.FlushModeType.AUTO; +import static javax.persistence.LockModeType.NONE; + +public abstract class SqlEntityManager implements EntityManager { + + private Map<String, Object> properties = new HashMap<>(); + + public abstract <Id, T> SqlDao<Id, T> getDao(Class<T> klass); + + // ----------------------------------------------------------------------- + // + // ----------------------------------------------------------------------- + + private final SqlEntityManagerFactory factory; + + private final Connection c; + + private boolean autoCommit; + + private final Tx tx = new Tx(); + + protected Connection currentConnection() { + return c; + } + + // ----------------------------------------------------------------------- + // EntityManager Implementation + // ----------------------------------------------------------------------- + + protected SqlEntityManager(SqlEntityManagerFactory factory, Connection c) { + this.factory = factory; + this.c = c; + + try { + autoCommit = c.getAutoCommit(); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public void persist(Object entity) { + if (entity == null) { + throw new NullPointerException("entity"); + } + + try { + @SuppressWarnings("unchecked") + Class<Object> klass = (Class<Object>) entity.getClass(); + this.<Object, Object>getDao(klass).insert(entity); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public <T> T merge(T entity) { + if (entity == null) { + throw new NullPointerException("entity"); + } + + try { + @SuppressWarnings("unchecked") + Class<T> klass = (Class<T>) entity.getClass(); + SqlDao<Object, T> dao = getDao(klass); + T t = dao.selectById(entity); + if (t == null) { + dao.insert(entity); + } else { + dao.update(entity); + } + + return t; + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public void remove(Object entity) { + if (entity == null) { + throw new NullPointerException("entity"); + } + + try { + @SuppressWarnings("unchecked") + Class<Object> klass = (Class<Object>) entity.getClass(); + this.<Object, Object>getDao(klass).delete(entity); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public <T> T find(Class<T> entityClass, Object primaryKey) { + try { + SqlDao<Object, T> dao = getDao(entityClass); + return dao.selectById(primaryKey); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) { + return find(entityClass, primaryKey); + } + + @Override + public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) { + if (lockMode != NONE) { + throw new IllegalArgumentException("Only lockMode = NONE is supported."); + } + return find(entityClass, primaryKey); + } + + @Override + public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) { + return find(entityClass, primaryKey, lockMode); + } + + @Override + public <T> T getReference(Class<T> entityClass, Object primaryKey) { + throw new UnsupportedOperationException(); + } + + @Override + public void flush() { + } + + @Override + public void setFlushMode(FlushModeType flushMode) { + if (flushMode != AUTO) { + throw new RuntimeException("Flush mode not supported: " + flushMode); + } + } + + @Override + public FlushModeType getFlushMode() { + return AUTO; + } + + @Override + public void lock(Object entity, LockModeType lockMode) { + throw new UnsupportedOperationException(); + } + + @Override + public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) { + throw new UnsupportedOperationException(); + } + + @Override + public void refresh(Object entity) { + throw new UnsupportedOperationException(); + } + + @Override + public void refresh(Object entity, Map<String, Object> properties) { + throw new UnsupportedOperationException(); + } + + @Override + public void refresh(Object entity, LockModeType lockMode) { + throw new UnsupportedOperationException(); + } + + @Override + public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + } + + @Override + public void detach(Object entity) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean contains(Object entity) { + throw new UnsupportedOperationException(); + } + + @Override + public LockModeType getLockMode(Object entity) { + throw new UnsupportedOperationException(); + } + + @Override + public void setProperty(String propertyName, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Map<String, Object> getProperties() { + return properties; + } + + @Override + public Query createQuery(String qlString) { + throw new UnsupportedOperationException(); + } + + @Override + public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) { + throw new UnsupportedOperationException(); + } + + @Override + public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) { + throw new UnsupportedOperationException(); + } + + @Override + public Query createNamedQuery(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) { + throw new UnsupportedOperationException(); + } + + @Override + public Query createNativeQuery(String sql) { + throw new UnsupportedOperationException(); + } + + @Override + public Query createNativeQuery(String sqlString, Class resultClass) { + // What happens if the transaction is aborted and this query is executes? Can a Query outlive it's connection? + // Or even EntityManager? Should probably store a reference to the current connection and check that the + // current one is the same when executing. + @SuppressWarnings({"UnnecessaryLocalVariable", "unchecked"}) + Class<Object> klass = resultClass; + + SqlDao<?, Object> dao = this.<Object, Object>getDao(klass); + return new SqlQuery<>(dao, new SqlExecutorDelegate(), sqlString, true); + } + + private class SqlExecutorDelegate implements SqlExecutor { + + // For now an EntityManager wraps a Connection + private Connection getCurrentOrNewConnection() { + return c; + } + + @Override + public int executeUpdate(UpdateCommand command) { + if (!isOpen()) { + throw new PersistenceException("This entity manager is closed."); + } + + Connection c = getCurrentOrNewConnection(); + + try { + return command.run(c); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public <T> List<T> executeQuery(QueryCommand<T> command) { + if (!isOpen()) { + throw new PersistenceException("This entity manager is closed."); + } + + Connection c = getCurrentOrNewConnection(); + + try { + return command.run(c); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + } + + @Override + public Query createNativeQuery(String sqlString, String resultSetMapping) { + throw new UnsupportedOperationException(); + } + + @Override + public void joinTransaction() { + throw new UnsupportedOperationException(); + } + + @Override + public <T> T unwrap(Class<T> cls) { + if(cls == SqlUnit.class) { + return cls.cast(this.factory.sqlUnit); + } + throw new PersistenceException(); + } + + @Override + public Object getDelegate() { + throw new UnsupportedOperationException(); + } + + @Override + public void close() { + } + + @Override + public boolean isOpen() { + throw new UnsupportedOperationException(); + } + + @Override + public EntityTransaction getTransaction() { + return tx; + } + + @Override + public SqlEntityManagerFactory getEntityManagerFactory() { + throw new UnsupportedOperationException(); + } + + @Override + public CriteriaBuilder getCriteriaBuilder() { + throw new UnsupportedOperationException(); + } + + @Override + public Metamodel getMetamodel() { + throw new UnsupportedOperationException(); + } + + private class Tx implements EntityTransaction { + private boolean active; + private boolean rollbackOnly; + + @Override + public void begin() { + try { + if (autoCommit) { + c.setAutoCommit(false); + autoCommit = false; + } + active = true; + rollbackOnly = false; + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public void commit() { + if (rollbackOnly) { + throw new RollbackException("Transaction marked for rollback only."); + } + + if (autoCommit) { + return; + } + + try { + c.commit(); + } catch (SQLException e) { + throw new PersistenceException(e); + } + + active = true; + } + + @Override + public void rollback() { + active = false; + if (autoCommit) { + return; + } + + try { + c.rollback(); + } catch (SQLException e) { + throw new PersistenceException(e); + } + } + + @Override + public void setRollbackOnly() { + this.rollbackOnly = active; + } + + @Override + public boolean getRollbackOnly() { + return rollbackOnly; + } + + @Override + public boolean isActive() { + return active; + } + } +} |