myrmidia.Database.Connector.java Source code

Java tutorial

Introduction

Here is the source code for myrmidia.Database.Connector.java

Source

/*
 *  Copyright (C) 2011 Glenn Rune Strandbrten 
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package myrmidia.Database;

import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import jcolibri.cbrcore.CBRCase;
import jcolibri.cbrcore.CaseComponent;
import org.hibernate.SessionFactory;
import jcolibri.connector.DataBaseConnector.*;
import jcolibri.exception.InitializingException;
import jcolibri.util.FileIO;
import myrmidia.CBR.CBREngine;
import myrmidia.CBR.Resources.ArmyChangeStatus;
import myrmidia.Enums.Outcomes;
import myrmidia.Util.CreateObjectFromDB;
import myrmidia.Warhammer.Army;
import myrmidia.Warhammer.ArmyUnit;
import myrmidia.Warhammer.Case;
import myrmidia.Warhammer.Equipment;
import myrmidia.Warhammer.UtilityUnit;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.w3c.dom.Document;

/**
 * Overrides most of the methods in the super class with the exact same
 * method, to be able to aquire one additional feature without impair original
 * functionality.
 * @author Glenn Rune Strandbrten
 * @version 1.0
 */
public class Connector extends jcolibri.connector.DataBaseConnector {

    private SessionFactory sessionFactory;
    private String descriptionClassName;
    private String solutionClassName;
    private String justOfSolutionClassName;
    private String resultClassName;
    private static final String ARMIES_QUERY = "insert into ARMIES(ID,PLAYER_RACE,ARMY_POINTS) values (?,?,?)";
    private static final String ARMY_UNITS_QUERY = "insert into ARMY_UNIT(ID,ARMY_ID,UNIT_NAME,NUM_UNITS) values(?,?,?,?)";
    private static final String ARMY_UNIT_UT_QUERY = "insert into ARMY_UNIT_UTILITY(ARMY_UNIT_ID,UTILITY_ID)values(?,?)";
    private static final String ARMY_UNIT_EQ_QUERY = "insert into ARMY_UNIT_EQUIPMENT(ARMY_UNIT_ID,EQUIPMENT_ID)values(?,?)";
    private static final String CASE_QUERY = "insert into CASES(ID,ARMY_ID,OPPONENT_RACE,OUTCOME) values(?,?,?,?)";
    private static final String CASE_UPDATE_OUTCOME_QUERY = "UPDATE CASES SET OUTCOME=(?) WHERE ID=(?)";
    private static final String DELETE_CASE_QUERY = "DELETE FROM CASES WHERE ID=(?)";
    private static final String DELETE_ARMY_QUERY = "DELETE FROM ARMIES WHERE ID=(?)";
    private static final String DELETE_ARMY_UNIT_QUERY = "DELETE FROM ARMY_UNIT WHERE ARMY_ID=(?)";
    private static final String DELETE_ARMY_UNIT_EQ_QUERY = "DELETE FROM ARMY_UNIT_EQUIPMENT WHERE ARMY_UNIT_ID=(?)";
    private static final String DELETE_ARMY_UNIT_UT_QUERY = "DELETE FROM ARMY_UNIT_UTILITY WHERE ARMY_UNIT_ID=(?)";

    /**
     * Default constructor - initializes the super class
     */
    public Connector() {
        super();
    }

    /**
     * Method to aquire a session from the connection
     * @return A Session object
     */
    public Session getSession() {
        return sessionFactory.openSession();
    }

    /**
     * This mehtod is used to override a hard-coded parameter in the
     * hibernate.cfg.xml file to give a the application a limited altered
     * configuration. Used to permit hibernate to create non-existing tables.
     * @param file URL the url path to the hibernate.cfg.xml file
     * @throws InitializingException
     */
    public void initOverwriteFromXMLFile(URL file) throws InitializingException {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(file.openStream());

            String hcf = document.getElementsByTagName("HibernateConfigFile").item(0).getTextContent();

            String descriptionMapFile = document.getElementsByTagName("DescriptionMappingFile").item(0)
                    .getTextContent();
            descriptionClassName = document.getElementsByTagName("DescriptionClassName").item(0).getTextContent();

            Configuration hbconfig = new Configuration();
            hbconfig.configure(FileIO.findFile(hcf));
            hbconfig.addURL(FileIO.findFile(descriptionMapFile));

            try {
                String solutionMapFile = document.getElementsByTagName("SolutionMappingFile").item(0)
                        .getTextContent();
                solutionClassName = document.getElementsByTagName("SolutionClassName").item(0).getTextContent();
                hbconfig.addResource(solutionMapFile);
            } catch (Exception e) {
                LogFactory.getLog(this.getClass()).info("Case does not have solution");
            }

            try {
                String justOfSolutionMapFile = document.getElementsByTagName("JustificationOfSolutionMappingFile")
                        .item(0).getTextContent();
                justOfSolutionClassName = document.getElementsByTagName("JustificationOfSolutionClassName").item(0)
                        .getTextContent();
                hbconfig.addResource(justOfSolutionMapFile);
            } catch (Exception e) {
                LogFactory.getLog(this.getClass()).info("Case does not have justification of the solution");
            }

            try {
                String resultMapFile = document.getElementsByTagName("ResultMappingFile").item(0).getTextContent();
                resultClassName = document.getElementsByTagName("ResultClassName").item(0).getTextContent();
                hbconfig.addResource(resultMapFile);
            } catch (Exception e) {
                LogFactory.getLog(this.getClass()).info("Case does not have result");
            }
            hbconfig.setProperty("hibernate.hbm2ddl.auto", "update");
            String currentProperty = hbconfig.getProperty("hibernate.connection.url");
            currentProperty += ";create=true";
            hbconfig.setProperty("hibernate.connection.url", currentProperty);
            sessionFactory = hbconfig.buildSessionFactory();
        } catch (Throwable ex) {
            throw new InitializingException(ex);
        }
    }

    /* (non-Javadoc)
     * @see jcolibri.cbrcore.Connector#initFromXMLfile(java.io.File)
     */
    @Override
    public void initFromXMLfile(URL file) throws InitializingException {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(file.openStream());

            String hcf = document.getElementsByTagName("HibernateConfigFile").item(0).getTextContent();

            String descriptionMapFile = document.getElementsByTagName("DescriptionMappingFile").item(0)
                    .getTextContent();
            descriptionClassName = document.getElementsByTagName("DescriptionClassName").item(0).getTextContent();

            Configuration hbconfig = new Configuration();
            hbconfig.configure(FileIO.findFile(hcf));
            hbconfig.addURL(FileIO.findFile(descriptionMapFile));

            try {
                String solutionMapFile = document.getElementsByTagName("SolutionMappingFile").item(0)
                        .getTextContent();
                solutionClassName = document.getElementsByTagName("SolutionClassName").item(0).getTextContent();
                hbconfig.addResource(solutionMapFile);
            } catch (Exception e) {
                LogFactory.getLog(this.getClass()).info("Case does not have solution");
            }

            try {
                String justOfSolutionMapFile = document.getElementsByTagName("JustificationOfSolutionMappingFile")
                        .item(0).getTextContent();
                justOfSolutionClassName = document.getElementsByTagName("JustificationOfSolutionClassName").item(0)
                        .getTextContent();
                hbconfig.addResource(justOfSolutionMapFile);
            } catch (Exception e) {
                LogFactory.getLog(this.getClass()).info("Case does not have justification of the solution");
            }

            try {
                String resultMapFile = document.getElementsByTagName("ResultMappingFile").item(0).getTextContent();
                resultClassName = document.getElementsByTagName("ResultClassName").item(0).getTextContent();
                hbconfig.addResource(resultMapFile);
            } catch (Exception e) {
                LogFactory.getLog(this.getClass()).info("Case does not have result");
            }
            sessionFactory = hbconfig.buildSessionFactory();
        } catch (Throwable ex) {
            throw new InitializingException(ex);
        }
    }

    /* (non-Javadoc)
     * @see jcolibri.cbrcore.Connector#retrieveAllCases()
     */
    @Override
    public Collection<CBRCase> retrieveAllCases() {
        java.util.ArrayList<CBRCase> res = new java.util.ArrayList<CBRCase>();
        try {
            Session session;
            Transaction transaction;

            List descList = null;
            HashMap<Object, CaseComponent> solList = null;
            HashMap<Object, CaseComponent> justSolList = null;
            HashMap<Object, CaseComponent> resList = null;

            if (solutionClassName != null) {
                session = sessionFactory.openSession();
                transaction = session.beginTransaction();

                solList = new HashMap<Object, CaseComponent>();
                List l = session
                        .createQuery("select cc from " + solutionClassName + " cc where cc.outcome <> 'Unknown'")
                        .list();

                transaction.commit();
                session.close();

                for (Iterator iter = l.iterator(); iter.hasNext();) {
                    CaseComponent cc = (CaseComponent) iter.next();
                    solList.put(cc.getIdAttribute().getValue(cc), cc);
                }
            }
            if (justOfSolutionClassName != null) {
                session = sessionFactory.openSession();
                transaction = session.beginTransaction();

                justSolList = new HashMap<Object, CaseComponent>();
                List l = session
                        .createQuery(
                                "select cc from " + justOfSolutionClassName + " cc where cc.outcome <> 'Unknown'")
                        .list();
                transaction.commit();
                session.close();

                for (Iterator iter = l.iterator(); iter.hasNext();) {
                    CaseComponent cc = (CaseComponent) iter.next();
                    justSolList.put(cc.getIdAttribute().getValue(cc), cc);
                }
            }
            if (resultClassName != null) {
                session = sessionFactory.openSession();
                transaction = session.beginTransaction();

                resList = new HashMap<Object, CaseComponent>();
                List l = session
                        .createQuery("select cc from " + resultClassName + " cc where cc.outcome <> 'Unknown'")
                        .list();
                transaction.commit();
                session.close();

                for (Iterator iter = l.iterator(); iter.hasNext();) {
                    CaseComponent cc = (CaseComponent) iter.next();
                    resList.put(cc.getIdAttribute().getValue(cc), cc);
                }
            }

            session = sessionFactory.openSession();
            transaction = session.beginTransaction();
            descList = session
                    .createQuery("select cc from " + descriptionClassName + " cc where cc.outcome <> 'Unknown'")
                    .list();
            transaction.commit();
            session.close();

            for (Iterator iter = descList.iterator(); iter.hasNext();) {
                CBRCase _case = new CBRCase();
                CaseComponent desc = (CaseComponent) iter.next();
                _case.setDescription(desc);

                if (solutionClassName != null) {
                    CaseComponent cc = solList.get(desc.getIdAttribute().getValue(desc));
                    if (cc != null)
                        _case.setSolution(cc);
                }
                if (justOfSolutionClassName != null) {
                    CaseComponent cc = justSolList.get(desc.getIdAttribute().getValue(desc));
                    if (cc != null)
                        _case.setJustificationOfSolution(cc);
                }
                if (resultClassName != null) {
                    CaseComponent cc = resList.get(desc.getIdAttribute().getValue(desc));
                    if (cc != null)
                        _case.setResult(cc);
                }

                res.add(_case);
            }
        } catch (Exception e) {
            LogFactory.getLog(this.getClass()).error(e);
        }
        LogFactory.getLog(this.getClass()).info(res.size() + " cases read from the database.");
        return res;
    }

    /* (non-Javadoc)
     * @see jcolibri.cbrcore.Connector#storeCases(java.util.Collection)
     */
    @Override
    public void storeCases(Collection<CBRCase> cases) {
        CBREngine engine = CBREngine.getInstance();
        for (CBRCase c : cases) {
            Session session = sessionFactory.openSession();
            Transaction transaction = session.beginTransaction();
            ArmyChangeStatus changeStatus = engine.getArmyChangeStatus(c);
            if (c.getSolution() != null && !changeStatus.isUnchanged()) {
                saveFullCase(session, c.getSolution());
                transaction.commit();
            } else if (c.getSolution() != null && changeStatus.isUnchanged()) {
                saveCase(session, c.getSolution());
            }
            session.close();
        }
        LogFactory.getLog(this.getClass()).info(cases.size() + " cases stored into the database.");
    }

    /**
     * Method which overrides the default hibernate saving scheme. This method
     * forces the connection to save only those parts of the case which is
     * neccessary in the neccessay order, by taking the saving power away from
     * hibernate and executing regular SQL's. <strong>NOTE:</strong> This method
     * saves the entire case (case, army and equipment/utility)
     * @param session The session with an open connection to the database
     * @param description The CaseComponent to be saved to the database.
     */
    private void saveFullCase(Session session, CaseComponent description) {
        System.out.println("SAVE FULL CASE");
        Case _case = (Case) description;
        Army army = _case.getArmy();
        //Create the army entry
        session.createSQLQuery(ARMIES_QUERY).setInteger(0, army.getID())
                .setString(1, army.getPlayerRace().toString()).setInteger(2, army.getArmyPoints()).executeUpdate();

        //Create the army unit entries (with equipment and utility units)
        Set<ArmyUnit> armyUnits = army.getArmyUnits();
        for (ArmyUnit armyUnit : armyUnits) {
            int id = armyUnit.getID();
            session.createSQLQuery(ARMY_UNITS_QUERY).setInteger(0, id).setInteger(1, armyUnit.getArmyID())
                    .setString(2, armyUnit.getUnit().getName()).setInteger(3, armyUnit.getNumberOfUnits())
                    .executeUpdate();
            //Create the utility unit entries
            Set<UtilityUnit> utSet = armyUnit.getUtility();
            for (UtilityUnit uu : utSet) {
                session.createSQLQuery(ARMY_UNIT_UT_QUERY).setInteger(0, id).setInteger(1, uu.getID())
                        .executeUpdate();
            }
            //Create the equipment entries
            Set<Equipment> eqSet = armyUnit.getEquipment();
            for (Equipment eq : eqSet) {
                session.createSQLQuery(ARMY_UNIT_EQ_QUERY).setInteger(0, id).setInteger(1, eq.getID())
                        .executeUpdate();
            }

        }
        //Create the case associated with this army
        session.createSQLQuery(CASE_QUERY).setInteger(0, _case.getID()).setInteger(1, army.getID())
                .setString(2, _case.getOpponent().toString()).setString(3, _case.getOutcome().toString())
                .executeUpdate();
    }

    /**
     * Method which overrides the default hibernate saving scheme. This method
     * forces the connection to save only those parts of the case which is
     * neccessary in the neccessay order, by taking the saving power away from
     * hibernate and executing regular SQL's. <strong>NOTE:</strong> This method
     * saves only te case. The army and equipment/utility is allready in the 
     * database.
     * @param session The session with an open connection to the database
     * @param description The CaseComponent to be saved to the database.
     */
    private void saveCase(Session session, CaseComponent description) {
        System.out.println("SAVE CASE ONLY");
        Case _case = (Case) description;
        Army army = _case.getArmy();
        session.createSQLQuery(CASE_QUERY).setInteger(0, _case.getID()).setInteger(1, army.getID())
                .setString(2, _case.getOpponent().toString()).setString(3, _case.getOutcome().toString())
                .executeUpdate();
    }

    /**
     * Method to update the outcome of a case
     * @param caseID int The case ID of the case to be updated
     * @param newOutcome Outcome The outcome to update the case with
     */
    public void updateOutcome(int caseID, Outcomes newOutcome) {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        session.createSQLQuery(CASE_UPDATE_OUTCOME_QUERY).setString(0, newOutcome.toString()).setInteger(1, caseID)
                .executeUpdate();
        transaction.commit();
        session.close();
    }

    /**
     * Method to delete a case with the given case ID from the database. The
     * method is intelligent and will delete the entire army
     * (army units, unit equipment and utility units) from the database if this
     * is the single case in the casebase utilizing this army.
     * @param caseID int The ID of the case to be deleted
     */
    public void deleteCase(int caseID) {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Case _case = CreateObjectFromDB.getCaseByID(caseID);
        List<Case> caseList = CreateObjectFromDB.getCasesWithArmyID(_case.getArmy().getID());
        boolean deleteArmy = true;
        if (caseList.size() > 1)
            deleteArmy = false;
        //Ensure that the army only is deleted if it not is used in other case
        //Also ensure that the deletion is done in the correct order to prevent
        //foreign key constraint violations
        if (deleteArmy) {
            Army army = _case.getArmy();
            Set<ArmyUnit> units = army.getArmyUnits();
            //Delete all the equipment and utility units for all the units
            //in the case
            for (ArmyUnit armyUnit : units) {
                session.createSQLQuery(DELETE_ARMY_UNIT_EQ_QUERY).setInteger(0, armyUnit.getID()).executeUpdate();
                session.createSQLQuery(DELETE_ARMY_UNIT_UT_QUERY).setInteger(0, armyUnit.getID()).executeUpdate();
            }
            //Delete all units associated with the army
            session.createSQLQuery(DELETE_ARMY_UNIT_QUERY).setInteger(0, army.getID()).executeUpdate();
        }
        //Delete the case
        session.createSQLQuery(DELETE_CASE_QUERY).setInteger(0, caseID).executeUpdate();
        //If applicable delete the last remains of the army
        if (deleteArmy) {
            Army army = _case.getArmy();
            session.createSQLQuery(DELETE_ARMY_QUERY).setInteger(0, army.getID()).executeUpdate();
        }
        transaction.commit();
        session.close();
    }
}