summaryrefslogtreecommitdiff
path: root/sql-persistence/src/main/java/io/trygvis/persistence/sql/SqlEntityManager.java
diff options
context:
space:
mode:
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.java419
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;
+ }
+ }
+}