org.fuchss.objectcasket.tablemodule.impl.TableModuleImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of object-casket Show documentation
Show all versions of object-casket Show documentation
Object Casket is a simple O/R mapper that can be used together with the Java Persistence API (JPA). The aim is to provide a simple solution for small projects to store multi-related
entities in a simple manner.
package org.fuchss.objectcasket.tablemodule.impl;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.fuchss.objectcasket.common.CasketError.CE0;
import org.fuchss.objectcasket.common.CasketError.CE1;
import org.fuchss.objectcasket.common.CasketError.CE2;
import org.fuchss.objectcasket.common.CasketError.CE4;
import org.fuchss.objectcasket.common.CasketException;
import org.fuchss.objectcasket.common.Util;
import org.fuchss.objectcasket.sqlconnector.port.SqlColumnSignature;
import org.fuchss.objectcasket.sqlconnector.port.SqlDatabase;
import org.fuchss.objectcasket.sqlconnector.port.SqlObjectFactory;
import org.fuchss.objectcasket.sqlconnector.port.StorageClass;
import org.fuchss.objectcasket.sqlconnector.port.TableAssignment;
import org.fuchss.objectcasket.tablemodule.port.Table;
import org.fuchss.objectcasket.tablemodule.port.TableModule;
class TableModuleImpl implements TableModule {
private final SqlObjectFactory objFac;
private final SqlDatabase database;
private ModuleConfigurationImpl config;
private final Map allViews = new HashMap<>();
private final Map allTables = new HashMap<>();
private TransactionImpl transaction;
private boolean close;
protected TableModuleImpl(ModuleConfigurationImpl config, SqlDatabase db, SqlObjectFactory objFac) {
this.database = db;
this.objFac = objFac;
this.config = config;
}
@Override
public synchronized Table mkView(String tableName, String pkName, Map> signature, boolean autoIncrement) throws CasketException {
Util.objectsNotNull(tableName, pkName, signature);
if (this.allViews.containsKey(tableName))
throw CE1.TABLE_OR_VIEW_EXISTS.defaultBuild(tableName);
TableImpl table = this.caa(CMD.ASSIGN, tableName, pkName, signature, autoIncrement);
this.allViews.put(tableName, table);
return table;
}
@Override
public synchronized Table createTable(String tableName, String pkName, Map> signature, boolean autoIncrement) throws CasketException {
Util.objectsNotNull(tableName, pkName, signature);
if (this.allTables.containsKey(tableName) || this.allViews.containsKey(tableName))
throw CE1.TABLE_OR_VIEW_EXISTS.defaultBuild(tableName);
TableImpl table = this.caa(CMD.CREATE, tableName, pkName, signature, autoIncrement);
this.allTables.put(tableName, table);
return table;
}
@Override
public synchronized Table adjustTable(String tableName, String pkName, Map> signature, boolean autoIncrement) throws CasketException {
Util.objectsNotNull(tableName, pkName, signature);
if (this.allTables.containsKey(tableName) || this.allViews.containsKey(tableName))
throw CE2.TABLE_IN_USE.defaultBuild(tableName, "altered");
TableImpl table = this.caa(CMD.ADJUST, tableName, pkName, signature, autoIncrement);
this.allTables.put(tableName, table);
return table;
}
@Override
public synchronized void dropTable(String tableName) throws CasketException {
Util.objectsNotNull(tableName);
this.database.dropTable(tableName);
}
@Override
public synchronized boolean tableExists(String tableName) throws CasketException {
Util.objectsNotNull(tableName);
return this.database.tableExists(tableName);
}
private TableImpl caa(CMD cmd, String tableName, String pkName, Map> signature, boolean autoIncrement) throws CasketException {
Map colSig = this.mkColSig(signature, pkName, autoIncrement);
TableAssignment dbTab = null;
dbTab = switch (cmd) {
case CREATE -> this.database.createTable(tableName, colSig);
case ASSIGN -> this.database.createView(tableName, colSig);
case ADJUST -> this.database.adjustTable(tableName, colSig);
};
Map> pkSignature = new HashMap<>();
pkSignature.put(pkName, signature.get(pkName));
Map pkDef = this.mkColSig(pkSignature, pkName, autoIncrement);
TableAssignment pkTab = this.database.createView(tableName, pkDef);
TableImpl tableImpl = new TableImpl(this, dbTab, pkTab, this.database, this.objFac);
tableImpl.initSignature(signature, pkName, autoIncrement);
return tableImpl;
}
private Map mkColSig(Map> signature, String pkName, boolean autoIncrement) throws CasketException {
Map colMap = new HashMap<>();
for (Entry> entry : signature.entrySet()) {
Class extends Serializable> javaType = entry.getValue();
String columnName = entry.getKey();
StorageClass sClass = this.getStorageClass(javaType);
if (sClass == null)
throw CE1.NO_SUITABLE_STORAGE_CLASS.defaultBuild(javaType);
SqlColumnSignature colSig = this.objFac.mkColumnSignature(sClass, javaType, null);
if (columnName.equals(pkName)) {
colSig.setFlag(SqlColumnSignature.Flag.PRIMARY_KEY);
if (autoIncrement)
colSig.setFlag(SqlColumnSignature.Flag.AUTOINCREMENT);
}
colMap.put(columnName, colSig);
}
return colMap;
}
private StorageClass getStorageClass(Class extends Serializable> javaType) {
StorageClass storageClass = StorageClass.TYPE_MAP.get(javaType);
if ((storageClass == null) && Serializable.class.isAssignableFrom(javaType))
storageClass = StorageClass.BLOB;
return storageClass;
}
protected SqlDatabase getDatabase() {
return this.database;
}
protected ModuleConfigurationImpl config() {
return this.config;
}
protected void close() throws CasketException {
if (this.close)
throw CE2.ALREADY_CLOSED.defaultBuild("table module", this);
this.close = true;
for (TableImpl tab : this.allViews.values())
tab.close();
for (TableImpl tab : this.allTables.values())
tab.close();
this.config = null;
}
@Override
public boolean isClosed() {
return this.close;
}
@Override
public synchronized Object beginTransaction() {
Object obj = this.database.beginTransaction(true);
this.transaction = new TransactionImpl(obj);
return obj;
}
@Override
public synchronized void endTransaction(Object voucher) throws CasketException {
this.checkVoucher(voucher);
try {
this.database.endTransaction(voucher);
this.transaction.done();
this.transaction = null;
} catch (Exception exc) {
this.transaction.rollbackCreated(voucher);
throw CasketException.build(exc);
}
}
@Override
public synchronized void rollback(Object voucher) throws CasketException {
this.checkVoucher(voucher);
this.transaction.rollbackCreated(voucher);
this.transaction = null;
this.database.rollback(voucher);
}
protected void rollback(CasketException exc, Object voucher) throws CasketException {
Objects.requireNonNull(exc);
this.rollback(voucher);
throw exc;
}
protected void add2created(TableImpl tableImpl, RowImpl newRow) {
this.transaction.add2created(tableImpl, newRow);
}
protected void add2deleted(TableImpl tableImpl, RowImpl theRow) {
this.transaction.add2deleted(tableImpl, theRow);
}
protected void add2changed(TableImpl tableImpl, RowImpl newRow) {
this.transaction.add2changed(tableImpl, newRow);
}
protected void checkVoucher(Object voucher) throws CasketException {
if ((this.transaction == null) || (this.transaction.voucher != voucher)) {
if (this.transaction == null)
throw CE0.MISSING_TRANSACTION.defaultBuild();
else
throw CE4.UNKNOWN_MANAGED_OBJECT.defaultBuild("Voucher", voucher, this.transaction.getClass(), this.transaction);
}
}
private enum CMD {
CREATE, ASSIGN, ADJUST
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy