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

org.xmlactions.db.save.SaveToDB Maven / Gradle / Ivy

package org.xmlactions.db.save;


import java.sql.Connection;




import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import org.xmlactions.action.config.IExecContext;
import org.xmlactions.common.collections.PropertyKeyValue;
import org.xmlactions.common.tracer.Tracer;
import org.xmlactions.db.ConstantsDB;
import org.xmlactions.db.DBConnector;
import org.xmlactions.db.DBSQL;
import org.xmlactions.db.DBUtils;
import org.xmlactions.db.actions.CommonStorageField;
import org.xmlactions.db.actions.Database;
import org.xmlactions.db.actions.FK;
import org.xmlactions.db.actions.PK;
import org.xmlactions.db.actions.Table;
import org.xmlactions.db.config.StorageConfig;
import org.xmlactions.db.exception.DBSQLException;
import org.xmlactions.db.sql.BuildSelect;
import org.xmlactions.db.sql.select.ISqlSelectBuildQuery;
import org.xmlactions.db.sql.select.ISqlTable;
import org.xmlactions.db.sql.select.SqlField;
import org.xmlactions.db.sql.select.SqlSelectInputs;
import org.xmlactions.db.sql.select.SqlTable;
import org.xmlactions.db.sql.select.VersionNumberConcurrency;

public class SaveToDB {

	private static final Logger log = LoggerFactory.getLogger(SaveToDB.class);

	/**
	 * 
	 * @param execContext
	 * @param storageConfig
	 * @param database
	 * @param table
	 * @param map
	 * @return the pk value if this was an insert else the number of rows updated if this was an update.
	 * @throws Exception
	 */
    public String saveData(IExecContext execContext, StorageConfig storageConfig, Database database, Table table,
            Map map) throws Exception {

        SqlSelectInputs sqlSelectInputs = buildSaveSql(storageConfig, database, table, map, execContext);
        ISqlSelectBuildQuery build = storageConfig.getSqlBuilder();
        ISqlTable[] sqlTables = build.buildSaveSqls(execContext, sqlSelectInputs);

        SaveToDB saveToDB = new SaveToDB();
        Tracer tracer = (Tracer) execContext.get(ConstantsDB.KEY_TRACER_DB_CLASS);
        String pkValue = saveToDB.save(execContext, storageConfig, sqlSelectInputs, sqlTables, tracer);
        return pkValue;
    }



    /**
     * 
     * @param execContext
     * @param storageConfig
     * @param sqlSelectInputs
     * @param sqlTables
     * @return the pkValue of the new record
     */
    public String save(IExecContext execContext, StorageConfig storageConfig, SqlSelectInputs sqlSelectInputs, ISqlTable[] sqlTables, Tracer tracer) {
    	
    	ListpkTables = new ArrayList();
    	
    	StringBuilder traceSB = null;
    	if (tracer != null) {
    		traceSB = new StringBuilder();
    	}
		DBConnector dbConnector = storageConfig.getDbConnector();
		Connection connection = null;
        String createdPkValue = null;
		try {
			connection = dbConnector.getConnection(execContext);
			connection.setAutoCommit(false);
			int pk = 0;
			for (int tableIndex = sqlTables.length-1; tableIndex>=0; tableIndex--) {
				ISqlTable sqlTable = sqlTables[tableIndex];
				if (sqlTable.getInsertSql() != null) {
					//log.debug("insert:" + sqlTable.getInsertSql());
					setFk(sqlTable, pkTables);
					pk = insert(execContext, storageConfig, sqlSelectInputs, sqlTable, tracer, traceSB, connection);
					createdPkValue = "" + pk;
					log.debug("insert pk value:" + pk);
					pkTables.add(new TableAndPk(sqlTable.getTable(), createdPkValue));
				} else if (sqlTable.getUpdateSql() != null) {
					//log.debug("update:" + sqlTable.getUpdateSql());
					setFk(sqlTable, pkTables);
					update(execContext, sqlTable, tracer, traceSB, connection);
				}
			}
			if (tracer != null) {
				if (createdPkValue != null) {
					traceSB.append("\ncreatedPkValue [" + createdPkValue + "]");
				}
				tracer.saveTrace(this.getClass().getName(), ConstantsDB.TRACE_INSERT, traceSB.toString());
			}
			connection.commit();
		} catch (Throwable e) {
			try {
				if (connection != null) {
					connection.rollback();
				}
			} catch (Exception ex) {
				// 2nd error. ignore this and only report the first error.
				log.error(ex.getMessage(), ex);
			}
			throw new IllegalArgumentException(e.getMessage(), e);
		} finally {
			
			DBUtils.closeQuietly(connection);
		}
        return createdPkValue;
	}

    // private String insert(IExecContext execContext, ISqlTable sqlTable, SqlSelectInputs sqlSelectInputs) {
    public int insert(IExecContext execContext, StorageConfig storageConfig, SqlSelectInputs sqlSelectInputs, ISqlTable sqlTable, Tracer tracer, StringBuilder traceSB, Connection connection) throws DBSQLException {
        int pk = 0;
		String sql = execContext.replace(sqlTable.getInsertSql());
		String pkSql = null;
		if (sqlTable.getTable().getPk() != null) {
            pkSql = sqlTable.getTable()
                    .getPk()
                    .getPkCreateSql(sqlSelectInputs.getDatabase(), storageConfig.getDbSpecificName());
		}
		
		if (StringUtils.isNotEmpty(pkSql)) {
			if (log.isDebugEnabled()) {
				log.debug("\npkSql:" + pkSql);
			}
		    String pk_value = DBSQL.queryOne(connection, pkSql, null);
		    if (tracer != null) {
		    	traceSB.append("\n");
		    	traceSB.append("pk_value [" + pk_value + "]");
		    }
		    pk = Integer.parseInt(pk_value);
            execContext.put(ConstantsDB.SQL_INSERT_PK_VALUE, pk_value);
        }
        for (SqlField sqlField : sqlTable.getParams()) {
        	if (sqlField.getValue() != null && sqlField.getValue() instanceof String) {
        		String value = execContext.replace((String) sqlField.getValue());
				if (log.isDebugEnabled()) {
					log.debug("setValue (" + sqlField.getFieldName() + ") = [" + value + "]");
				}
			    if (tracer != null) {
					traceSB.append("\nsetValue (" + sqlField.getFieldName() + ") = [" + value + "]");
			    }
        		sqlField.setValue(value);
        	}
        }
		if (log.isDebugEnabled()) {
			log.debug("\ninsert:" + sql);
		}
        if (StringUtils.isNotEmpty(sql)) {
        	pk = DBSQL.insertAndReturnKey(connection, sql, sqlTable.getParams(), sqlTable);
        	// pk = DBSQL.insert(connection, sql, sqlTable.getParams());
        } else {
        	pk = DBSQL.insertAndReturnKey(connection, sql, sqlTable.getParams(), sqlTable);
        }
        
		if (sqlTable.getTable().getPk() != null) {
			PK pK = sqlTable.getTable().getPk();
			String key = sqlTable.getTable().getName() + Table.TABLE_FIELD_SEPERATOR + pK.getName();
			execContext.put(key, pk);
		}
		if (log.isDebugEnabled()) {
			log.debug("pk:" + pk);
		}
    	return pk;
    }

    /**
     * Wil update the data to the database and return the number of rows updated.
     * @param execContext
     * @param sqlTable
     * @param tracer
     * @param traceSB
     * @param connection
     * @return the number of rows updated.
     * @throws DBSQLException
     */
    private int update(IExecContext execContext, ISqlTable sqlTable, Tracer tracer, StringBuilder traceSB, Connection connection) throws DBSQLException {

		// update any foreign key values
		for (SqlField sqlField : sqlTable.getParams()) {
			if (sqlField.getValue() != null && sqlField.getValue() instanceof String) {
				sqlField.setValue(execContext.replace((String)sqlField.getValue()));
				if (tracer != null) {
					traceSB.append("\n  Field(after replace):" + sqlField.getFieldName() + " [" + sqlField.getValue() + "]");
				}
			}
		}
    	
    	String sql = sqlTable.getUpdateSql();
		sql = execContext.replace(sql);
		if (log.isDebugEnabled()) {
			log.debug(sql);
		}
		if (tracer != null) {
			traceSB.append(sql);
			for (SqlField sqlField : sqlTable.getParams()) {
				traceSB.append("\n  Field:" + sqlField.getFieldName() + " [" + sqlField.getValue() + "]");
			}
			tracer.saveTrace(this.getClass().getName(), ConstantsDB.TRACE_UPDATE, traceSB.toString());
		}
		int result = DBSQL.update(connection, sql, sqlTable.getParams());

		Object obj = execContext.get(ConstantsDB.ENFORCE_CONCURRENCY);
		if (obj != null && (Boolean)obj == false) {
			// skip concurrency
		} else {
			PropertyKeyValue versionNumber = VersionNumberConcurrency.getVersionNumber(execContext, sqlTable);
			if (versionNumber != null && result < 1) {
				throw new IllegalArgumentException("Save failed, caused by concurrency update.\n" + sqlToString(sql, sqlTable, versionNumber, result));
			}
		}
		return result;
    }

    private String sqlToString(String sql, ISqlTable sqlTable, PropertyKeyValue versionNumber, int result) {
    	StringBuilder sb = new StringBuilder();
    	sb.append("Concurrency issue version number key:" + versionNumber.getKey() + " version number value:" + versionNumber.getValue() + " rows updated:" + result);
    	sb.append("\nsql:" + sql);
    	if (sqlTable.getParams().size() > 0) {
    		sb.append("\nsql params:");
    	}
    	for (SqlField sqlField : sqlTable.getParams()) {
			sb.append("\n  Field:" + sqlField.getFieldName() + " [" + sqlField.getValue() + "]");
    	}
    	return sb.toString();
    }
    private void  setFk(ISqlTable sqlTable, ListpkTables) {
    	
    	for (TableAndPk pkTable : pkTables) {
    		SqlField matchingSqlField = pkTable.getMatchingFk(sqlTable);
    		if (matchingSqlField != null && StringUtils.isEmpty("" + matchingSqlField.getValue())) {
    			matchingSqlField.setValue(pkTable.getPkValue());
    		}
    	}
    }

    private class TableAndPk {
    	String pkValue;
    	Table table;
    	
    	private TableAndPk(Table table, String pk) {
    		this.pkValue = pk;
    		this.table = table;
    	}
    	
    	private String getPkValue() {
    		return this.pkValue;
    	}
    	
    	private Table getTable() {
    		return this.table;
    	}
    	
    	private SqlField getMatchingFk(ISqlTable sqlTable) {
    		//
    		// FIXME - get FK from Table not SqlTable
    		// Instead of expecting the FK to be already in the table we should check if there is one in the Table.
    		// This will drop the need for the developer to include the pk field in the add or edit configuration.
    		//
			for (SqlField sqlField : sqlTable.getFields()) {
	    		if (sqlField.getCommonStorageField() != null && sqlField.getCommonStorageField() instanceof FK) {
	    			// check all FKs
	    			FK fk = (FK) sqlField.getCommonStorageField();
	    			if (fk.getForeignTableAliasOrName().equals(getTable().getName()) ||
	    				fk.getForeignTableAliasOrName().equals(getTable().getAlias())) {
	    				// fk references this Table
	    				PK pk = getTable().getPk();
	    				if (pk != null) {
	    					if (fk.getForeign_key().equals(pk.getName()) ||
	    						fk.getForeign_key().equals(pk.getAlias())) {
	    						return sqlField;
	    					}
	    				}
	    			}
	    		}
	    	}
			return null;
    	}
    }

    /**
     * 
     * @param storageConfig
     * @param database
     * @param table
     * @param map
     * @param execContext
     * @return
     */
    private SqlSelectInputs buildSaveSql(StorageConfig storageConfig, Database database, Table table,
            Map map, IExecContext execContext) {

        List sqlFields = new ArrayList();
        for (String key : map.keySet()) {
            // sqlFields.add(new SqlField(map.get(key)));
            SqlField sqlField = new SqlField(key);
            sqlField.setValue(map.get(key));
            sqlFields.add(sqlField);
        }

        SqlSelectInputs sqlSelectInputs = BuildSelect.buildSelect(storageConfig.getStorageContainer().getStorage(),
                database.getName(),
                table.getName(),
                sqlFields,
                storageConfig.getDbSpecificName());
        return sqlSelectInputs;

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy