All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fuchss.objectcasket.tablemodule.impl.TableModuleImpl Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 0.20.17
Show newest version
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 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 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