Package quickdb.db

Source Code of quickdb.db.AdminBase

package quickdb.db;

import java.security.InvalidParameterException;
import quickdb.db.dbms.DbmsInterpreter;
import quickdb.db.dbms.mysql.ColumnDefined;
import quickdb.db.dbms.mysql.DataType;
import quickdb.modelSupport.M2mTable;
import quickdb.modelSupport.PrimitiveCollec;
import quickdb.query.Query;
import quickdb.query.StringQuery;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.ArrayList;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Stack;
import quickdb.db.connection.IConnectionDB;
import quickdb.exception.OptimisticLockException;
import quickdb.reflection.EntityManager;

/**
*
* @author Diego Sarmentero
*/
public class AdminBase {

    protected IConnectionDB conex;
    protected ResultSet rs;
    protected EntityManager manager;
    protected String tableForcedName;
    protected boolean forceTable;
    private Stack<ResultSet> arrayRs;
    private DATABASE db;
    private boolean collectionHasName;
    private boolean collection;
    private boolean startObtainAll;
    private boolean commit;
    private boolean autoCommit;

    public enum DATABASE {

        MYSQL, POSTGRES, SQLSERVER, SQLite, FIREBIRD, MariaDB
    };

    protected AdminBase(DATABASE db, String... args) {

        this.db = db;
        this.commit = true;
        this.autoCommit = false;
        this.startObtainAll = false;
        this.collection = false;
        this.collectionHasName = false;
        this.forceTable = false;
        this.tableForcedName = "";
        this.manager = new EntityManager();
        this.arrayRs = new Stack<ResultSet>();
        this.conex = DbmsInterpreter.connect(db, args);
    }

    /**
     * For MySQL args: MYSQL, host, port, catalog, username, password
     * @param Database enumeration
     * @param Array of String depending on the database selected
     */
    public static AdminBase initialize(DATABASE db, String... args) {
        AdminBase admin;
        switch(db){
            case SQLite:
                admin = new AdminSQLite(db, args);break;
            default:
                admin = new AdminBase(db, args);break;
        }
       
        return admin;
    }

    /**
     * Initialize the AdminBase private attribute from AdminBinding
     * when QuickDB is used in the Data Model through inheritance
     * @param db
     * @param args
     */
    public static void initializeAdminBinding(DATABASE db, String... args) {
        AdminBase admin = new AdminBase(db, args);
        AdminBinding.initializeAdminBase(admin);
    }

    public void initializeAdminBinding(){
        AdminBinding.initializeAdminBase(this);
    }

    public static void initializeViews(DATABASE db, String... args) {
        AdminBase admin = new AdminBase(db, args);
        View.initializeAllViews(admin);
    }

    public void initializeViews(){
        View.initializeAllViews(this);
    }

    /**
     * Store the object in the Database (create the Table if not exist)
     * @param Object
     * @return True if the object could be saved, False in the other case
     */
    public boolean save(Object object) {

        int value = -1;
        try{
            boolean commitValue = this.commit;
            if(this.commit || this.autoCommit){
                conex.initTransaction();
                this.commit = false;
            }

            ArrayList array = this.manager.entity2Array(this, object,
                    EntityManager.OPERATION.SAVE);

            value = this.saveProcess(array, object);

            this.commit = commitValue;
            if(this.commit || this.autoCommit){
                conex.confirmTransaction();
                if(this.conex.getConnection().getAutoCommit()){
                    this.conex.getConnection().setAutoCommit(false);
                }
            }
        }catch(SQLException e){
            this.commit = true;
        }
        return (value > 0);
    }

    protected int saveProcess(ArrayList array, Object object) {
        int index = -1;
        String table = "";
        int i = 2;
        try {
            if (this.forceTable) {
                table = tableForcedName;
                array.set(0, table);
            } else {
                table = String.valueOf(array.get(0));
            }

            conex.openBlock(table);

            int size = array.size() - 1;
            for (; i < size; i++) {
                Object[] obj = (Object[]) array.get(i);

                String column = (String) obj[0];
                Object value = obj[1];

                conex.insertField(column, value);
            }

            index = conex.closeBlock();
            if (this.collection) {
                this.saveMany2Many(((String) array.get(0)), true, index);
            }
            this.manager.updateCache(object.getClass(), this);
        } catch (SQLException ex) {
            int value = -1;
            try{
                this.conex.getConnection().setAutoCommit(true);
                if (!this.checkTableExist(table)) {
                    if (this.createTable(object, array.toArray())) {
                        value = this.saveProcess(array, object);
                    }
                } else {
                    if (this.addColumn(table, object, array, i)) {
                        value = this.saveProcess(array, object);
                    }
                }
            }catch(Exception e){}
            return value;
        } catch (Exception e) {
            conex.connectMySQL();
            try {
                conex.cancelTransaction();
            } catch (Exception ex) {
                return -1;
            }
        }

        return index;
    }

    /**
     * Store the object in the Database (create the Table if not exist) and
     * return the value of the PrimaryKey.
     * @param Object
     * @return The value of the PrimaryKey, or -1 if the object couldn't be
     * saved.
     */
    public int saveGetIndex(Object object) {
        int index = -1;
        try {
            boolean commitValue = this.commit;
            if(this.commit || this.autoCommit){
                conex.initTransaction();
                this.commit = false;
            }

            ArrayList array = this.manager.entity2Array(this, object,
                    EntityManager.OPERATION.SAVE);

            index = this.saveProcess(array, object);
            this.commit = commitValue;
            if(this.commit || this.autoCommit){
                conex.confirmTransaction();
                if(this.conex.getConnection().getAutoCommit()){
                    this.conex.getConnection().setAutoCommit(false);
                }
            }
        } catch (SQLException e) {
            this.commit = true;
        }

        return index;
    }

    protected boolean saveMany2Many(String table, boolean saveNotModify, int index) {
        ArrayList many = new ArrayList();
        try {
            String where = "";

            int sizeCollection = this.manager.sizeCollectionStack();
            for (int i = 0; i < sizeCollection; i++) {
                ArrayList collec = this.manager.getCollection();
                int size = collec.size();
                if(size > 0 && collec.get(0) instanceof PrimitiveCollec){
                    for (int q = 0; q < size; q++) {
                        ((PrimitiveCollec) collec.get(q)).setBase(index);
                        many.add(collec.get(q));
                    }
                }else{
                    for (int q = 0; q < size; q++) {
                        many.add(new M2mTable(index,
                                ((Integer) collec.get(q))));
                    }
                }

                this.collection = false;
                this.forceTable = true;
                if (this.collectionHasName) {
                    this.tableForcedName = this.manager.getNameCollection();
                } else {
                    String nameCollection = this.manager.getNameCollection();
                    //Consult if the table name or its inverse exists and asign match
                    this.tableForcedName = table + nameCollection;
                    where = "base = " + index;
                    String tempTableName = nameCollection + table;
                    if (!this.checkTableExist(this.tableForcedName) &&
                            this.checkTableExist(tempTableName)) {
                        this.tableForcedName = tempTableName;
                        where = "related = " + index;
                        for (M2mTable m2m : ((ArrayList<M2mTable>) many)) {
                            int temp = m2m.getBase();
                            m2m.setBase(m2m.getRelated());
                            m2m.setRelated(temp);
                        }
                    }
                }

                if (!saveNotModify) {
                    String sql = "DELETE FROM " + this.tableForcedName + " WHERE " + where;
                    this.executeQuery(sql);
                }
                this.saveAll(many);
                many.clear();
            }
        } catch (Exception e) {
            return false;
        } finally {
            this.collection = false;
            this.forceTable = false;
            this.collectionHasName = false;
        }

        return true;
    }

    /**
     * For this method only is the object to be modify.
     * It is necessary to execute obtain previously to recover
     * the proper object.
     * @param Object
     * @return True if the modification was successfull, False in the other case
     */
    public boolean modify(Object object) {
        if(!this.manager.checkOptimisticLock(this, object)){
            throw new OptimisticLockException();
        }
        boolean value = false;
        try{
            boolean commitValue = this.commit;
            if(this.commit || this.autoCommit){
                conex.initTransaction();
                this.commit = false;
            }

            ArrayList<String> manys = this.manager.getRef().isMany2Many(object.getClass());
            if (!manys.isEmpty()) {
                if (this.manager.deleteMany2Many(this, object, manys)) {
                    this.manager.cleanStack();
                    value = this.save(object);
                }
            } else {
                value = this.modifyProcess(object);
            }
           
            this.commit = commitValue;
            if(this.commit || this.autoCommit) conex.confirmTransaction();
        }catch(SQLException e){
            this.commit = true;
        }

        return value;
    }

    protected boolean modifyProcess(Object object) {
        ArrayList array = this.manager.entity2Array(this, object,
                EntityManager.OPERATION.MODIFY);

        try {
            this.rs = conex.updateField(((String) array.get(0)),
                    String.valueOf(array.get(array.size() - 1)));
            rs.next();

            do {
                int size = array.size() - 1;
                for (int i = 1; i < size; i++) {
                    Object[] obj = (Object[]) array.get(i);

                    String column = (String) obj[0];
                    Object value = obj[1];

                    rs.updateObject(column, value);
                    rs.updateRow();
                }
            } while (rs.next());

            int index = Integer.parseInt(String.valueOf(array.get(array.size() - 1)).
                    substring(String.valueOf(array.get(array.size() - 1)).indexOf("=")+1));

            if (this.collection) {
                this.saveMany2Many(((String) array.get(0)), false, index);
            }
            this.manager.updateCache(object.getClass(), this);
        } catch (Exception e) {
            try {
                conex.cancelTransaction();
            } catch (Exception ex) {
                return false;
            }
            return false;
        }

        return true;
    }

    private int modifyGetIndex(Object object) {
        int index = this.manager.getRef().checkIndexValue(object);
        /*If the index is greater than 0 it means that the Object already
        exist in the Database and has to be modify, if index is lower than
        0 it means that this is a new Object that has to be added to the
        database*/
        if (index > 0) {
            this.modify(object);
        } else {
            index = this.saveGetIndex(object);
        }

        return index;
    }

    /**
     * Delete the object received as parameter from the Database
     * @param Object
     * @return True if the operation complete successfully, False in the other case.
     */
    public boolean delete(Object object) {

        try {
            boolean commitValue = this.commit;
            if(this.commit || this.autoCommit){
                conex.initTransaction();
                this.commit = false;
            }

            ArrayList array = this.manager.entity2Array(this, object,
                EntityManager.OPERATION.DELETE);

            conex.deleteRows(((String) array.get(0)),
                    ((String) array.get(array.size() - 1)));

            this.manager.deleteParent(this, object);

            //Obtain the attributes from this object that are collections
            //and delete their relations in the Relational Table.
            ArrayList<String[]> strings = this.manager.getCollectionsTableForDelete(object, this);
            int index = (Integer) ((Object[]) array.get(1))[1];
            for (String[] s : strings) {
                if (this.checkTableExist(s[0])) {
                    this.executeQuery("DELETE FROM " + s[0] + " WHERE base=" + index);
                } else if (this.checkTableExist(s[1])) {
                    this.executeQuery("DELETE FROM " + s[1] + " WHERE related=" + index);
                }
            }

            this.commit = commitValue;
            if(this.commit || this.autoCommit) conex.confirmTransaction();
        } catch (Exception e) {
            this.commit = true;
            try {
                conex.cancelTransaction();
            } catch (Exception ex) {
                return false;
            }
            return false;
        }

        return true;

    }

    /**
     * Execute the SQL query received as parameter
     * @param object
     * @return
     */
    public boolean executeQuery(String statement) {
        try {
            conex.executeQuery(statement);

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private boolean obtainNext(Object object) {
        try {
            if (rs.next() && (this.manager.result2Object(this,
                    object, rs) != null)) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            this.rs = this.arrayRs.peek();
        }

        return false;
    }

    /**
     * Receive an Object and a query and return a Collection of object
     * from the same type as was received, that represent the result of
     * that query.
     * @param Object
     * @param Query [String]
     * @return ArrayList [Collection of Object]
     */
    public ArrayList obtainAll(Class clazz, String sql) {
        boolean cacheable = this.manager.isCacheable(clazz);
        if(cacheable){
            ArrayList array = this.manager.obtainCache(sql, this, clazz);
            if(array != null){
                return array;
            }
        }
        this.startObtainAll = true;
        ArrayList results = new ArrayList();
        try {
            boolean value = false;
            Object object = this.manager.getRef().emptyInstance(clazz);
            if(sql.startsWith("SELECT ")){
                value = this.obtainSelect(object, sql);
            }else{
                value = this.obtainWhere(object, sql);
            }
            if (value) {
                this.rs = this.arrayRs.peek();
                results.add(object);
                Object obj = this.manager.getRef().emptyInstance(object);
                while (this.obtainNext(obj)) {
                    results.add(obj);
                    obj = this.manager.getRef().emptyInstance(object);
                }
            }
            if(cacheable){
                this.manager.makeCacheable(sql, results, clazz, this);
            }
        } catch (Exception e) {
            return null;
        } finally {
            this.startObtainAll = false;
            this.arrayRs.pop();
            if (!this.arrayRs.isEmpty()) {
                this.rs = this.arrayRs.peek();
            }
        }

        return results;
    }

    /**
     * Load the attributes in the object gradually.
     * If this method received 2 parameters[Object, StringQuery] is
     * the first time that the object is going to be loaded, the next
     * time is only needed to receive the Object.
     * @param Object, [String only for the first time]
     * @return Object
     */
    public boolean lazyLoad(Object... object) {
        this.manager.setDropDown(false);
        boolean value = false;
        if (object.length == 2) {
            String sql = String.valueOf(object[1]);
            value = this.obtain(object[0], sql);
        } else {
            value = this.manager.completeLazyLoad(this, object[0]);
        }

        this.manager.setDropDown(true);

        return value;
    }

    /**
     * This method can receive an object to determine the type of
     * object that is going to be manage and a String with the query.
     * (Faster than 'obtain', this method doesnt has to parse the expression)
     * @param Object, String
     * @return True if the object could be obtained, False in the other case.
     */
    public boolean obtainWhere(Object object, String sql) {
        ArrayList array = this.manager.entity2Array(this, object,
                EntityManager.OPERATION.OBTAIN);

        try {
            if (this.collectionHasName) {
                this.rs = conex.selectWhere(this.manager.getNameCollection(), sql);
            } else {
                this.rs = conex.selectWhere(((String) array.get(0)), sql);
            }
            this.arrayRs.push(this.rs);

            if (rs.next() && (this.manager.result2Object(this, object, rs) != null)) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            if (!this.startObtainAll) {
                this.arrayRs.pop();
                if (!this.arrayRs.isEmpty()) {
                    this.rs = this.arrayRs.peek();
                }
            } else {
                this.startObtainAll = false;
            }
        }

        return false;
    }

    /**
     * This Method return an Object[] containing String[] in each item,
     * that represent the result of the specified query as a Matrix of Strings
     * @param SQL Query [String]
     * @param Number of Columns involved [int]
     * @return Object[] or null
     */
    public Object[] obtainTable(Object... prop) {
        try {
            this.rs = conex.select((String)prop[0]);
            rs.next();
            int cols = 0;
            String[] names = new String[0];
            boolean hash = false;
            if(prop.length > 1 && prop[1].getClass().getSimpleName().equalsIgnoreCase("Integer")){
                cols = (Integer) prop[1];
            }else if(prop.length > 1 && prop[1].getClass().getSimpleName().equalsIgnoreCase("Boolean")){
                if((Boolean)prop[1]){
                    String sql = ((String) prop[0]).toLowerCase();
                    names = sql.substring(
                            sql.indexOf("select ")+7, sql.indexOf(" from")).split(",");
                    cols = names.length;
                    hash = true;
                }else{
                    String sql = ((String) prop[0]).toLowerCase();
                    cols = sql.substring(
                            sql.indexOf("select ")+7, sql.indexOf(" from")).split(",").length;
                }
            }else{
                throw new InvalidParameterException();
            }

            if(hash){
                ArrayList<Hashtable<String, Object>> array = new ArrayList<Hashtable<String, Object>>();
                do {
                    Hashtable<String, Object> table = new Hashtable<String, Object>(cols);
                    for (int i = 1; i < cols + 1; i++) {
                        table.put(names[i-1].trim(), rs.getObject(i));
                    }
                    array.add(table);
                } while (rs.next());
                return array.toArray();
            }else{
                ArrayList<String[]> array = new ArrayList<String[]>();
                do {
                    String[] objs = new String[cols];
                    for (int i = 1; i < cols + 1; i++) {
                        objs[i - 1] = rs.getObject(i).toString();
                    }
                    array.add(objs);
                } while (rs.next());
                return array.toArray();
            }

        } catch (Exception e) {
            return null;
        }
    }

    @Deprecated
    public Object[] obtainJoin(String sql, int cols){
        return this.obtainTable(sql, cols);
    }

    public Query obtain(Object obj){
        return Query.create(this, obj);
    }

    /**
     * Return the object restore with the information from the
     * database, based on the Object Oriented Query that was received.
     * @param Object
     * @param Query statement
     * @return True if the Object could be restored, False in the other case.
     */
    public boolean obtain(Object obj, String sql) {
        String query = StringQuery.parse(obj.getClass(), sql);

        return this.obtainSelect(obj, query);
    }

    /**
     * Return the Object from the Database that represent
     * the [completely] specified query
     * @param Object
     * @param SQL Query [String]
     * @return True if the object could be restored, False in the other case.
     */
    public boolean obtainSelect(Object object, String sql) {
        try {
            this.rs = conex.select(sql);
            this.arrayRs.push(this.rs);

            if (rs.next() && (this.manager.result2Object(this,
                    object, rs) != null)) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            if (!this.startObtainAll) {
                this.arrayRs.pop();
                if (!this.arrayRs.isEmpty()) {
                    this.rs = this.arrayRs.peek();
                }
            } else {
                this.startObtainAll = false;
            }
        }

        return false;
    }

    /**
     * Save all the items in the Collection in the Database
     * @param An Object that implement java.util.Collection
     * @return An ArrayList with the number of elements inserted or
     * an ArrayList with each item index if the array received
     * represent a Collection Reference.
     */
    public ArrayList<Integer> saveAll(Collection array) {
        ArrayList<Integer> results = new ArrayList<Integer>();
        try{
            boolean commitValue = this.commit;
            if(this.commit || this.autoCommit){
                conex.initTransaction();
                this.commit = false;
            }
           
            Object objects[] = array.toArray();
            if (!this.collection) {
                for (int i = 0; i < objects.length; i++) {
                    if (!this.save(objects[i])) {
                        results.add(i); //throw exception
                        break;
                    }
                }
            } else {
                this.collection = false;
                for (Object obj : objects) {
                    results.add(this.saveGetIndex(obj));
                }
                this.collection = true;
            }

            this.commit = commitValue;
            if(this.commit || this.autoCommit){
                conex.confirmTransaction();
                if(this.conex.getConnection().getAutoCommit()){
                    this.conex.getConnection().setAutoCommit(false);
                }
            }
        }catch(SQLException e){
            this.commit = true;
        }

        return results;
    }

    /**
     * Modify in the Database the objects in the array received as
     * parameter.
     * @param An Object that implements java.util.Collection with the items
     * @return An ArrayList with the index of each item if collection if from
     * a Reference Collection or an ArrayList with the number of item that
     * couldnt be updated if this is not a Collection Reference
     */
    public ArrayList<Integer> modifyAll(Collection array) {
        ArrayList<Integer> results = new ArrayList<Integer>();
        try{
            boolean commitValue = this.commit;
            if(this.commit || this.autoCommit){
                conex.initTransaction();
                this.commit = false;
            }

            Object objects[] = array.toArray();
            if (!this.collection) {
                for (int i = 0; i < objects.length; i++) {
                    if (!this.modify(objects[i])) {
                        results.add(i);
                        break;
                    }
                }
            } else {
                this.collection = false;
                for (Object obj : objects) {
                    int index = this.modifyGetIndex(obj);
                    results.add(index);
                }
                this.collection = true;
            }

            this.commit = commitValue;
            if(this.commit || this.autoCommit) conex.confirmTransaction();
        }catch(SQLException e){
            this.commit = true;
        }

        return results;
    }

    protected boolean createTable(Object entity, Object[] objects) {
        return DbmsInterpreter.createTable(db, this, entity, objects, manager);
    }

    protected boolean addColumn(String table, Object object,
            ArrayList array, int pos) throws Exception{
        String statement = "";
        if ((object.getClass().getDeclaredFields()[pos-1].getDeclaredAnnotations().length != 0)) {
            Object columns[] = this.manager.mappingDefinition(this, object);

            statement = String.format("ALTER TABLE %s ADD %s", table,
                    ((ColumnDefined) columns[pos]).toString());
        } else {
            DataType dataType = new DataType();
            statement = String.format("ALTER TABLE %s ADD %s %s", table,
                    String.valueOf(((Object[]) array.get(pos))[0]),
                    dataType.getDataType(((Object[]) array.get(pos))[1].getClass(),
                    ((Object[]) array.get(pos))[1].toString().length()));
        }

        return this.executeQuery(statement);
    }

    public void openAtomicBlock(){
        this.commit = false;
        try{
            this.conex.initTransaction();
        }catch(Exception e){
            this.commit = true;
        }
    }

    public void closeAtomicBlock(){
        this.commit = true;
        try{
            this.conex.confirmTransaction();
        }catch(Exception e){
           
        }
    }

    public void cancelAtomicBlock(){
        this.commit = true;
        try{
            this.conex.cancelTransaction();
        }catch(Exception e){

        }
    }

    public void setAutoCommit(boolean value){
        this.autoCommit = value;
    }

    /**
     * Return True if the specified Table exist in the Database
     * @param Table Name
     * @return Boolean
     */
    public boolean checkTableExist(String table) {
        return this.conex.existTable(table);
    }

    public void setCollection(boolean collection) {
        this.collection = collection;
    }

    public boolean getCollection() {
        return this.collection;
    }

    public void setCollectionHasName(boolean collectionHasName) {
        this.collectionHasName = collectionHasName;
    }

    public IConnectionDB getConex() {
        return this.conex;
    }

    public DATABASE getDB(){
        return this.db;
    }

    public void close(){
        this.conex.closeConnection();
    }

    public void setForceTable(boolean forceTable) {
        this.forceTable = forceTable;
    }

    public void setTableForcedName(String tableForcedName) {
        this.tableForcedName = tableForcedName;
    }

    public void activateLogging(Object... values){
        this.close();
        if((Boolean) values[0]){
            if(values.length < 2) throw new InvalidParameterException();
            this.conex = DbmsInterpreter.connectLogging(db, ((String) values[1]), DbmsInterpreter.properties);
        }else{
            this.conex = DbmsInterpreter.connect(db, DbmsInterpreter.properties);
        }
    }
   
}
TOP

Related Classes of quickdb.db.AdminBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.