com.claresco.tinman.sql.XapiStatementSQLReader.java Source code

Java tutorial

Introduction

Here is the source code for com.claresco.tinman.sql.XapiStatementSQLReader.java

Source

/**
 * ClarescoExperienceAPI
 * Copyright 
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * Please contact Claresco, www.claresco.com, if you have any questions.
 **/

package com.claresco.tinman.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.TimeZone;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

import com.claresco.tinman.json.JsonUtility;
import com.claresco.tinman.lrs.XapiAgent;
import com.claresco.tinman.lrs.XapiContext;
import com.claresco.tinman.lrs.XapiGroup;
import com.claresco.tinman.lrs.XapiInverseFunctionalIdentifier;
import com.claresco.tinman.lrs.XapiObject;
import com.claresco.tinman.lrs.XapiResult;
import com.claresco.tinman.lrs.XapiStatement;
import com.claresco.tinman.lrs.XapiVerb;
import com.claresco.tinman.lrs.XapiActor;
import com.claresco.tinman.servlet.XapiBadParamException;
import com.google.gson.Gson;

/**
 * XapiStatementSqlReader.java
 *
 * Read from database
 *
 *
 *
 * @author rheza
 * on Feb 26, 2014
 * 
 */

class XapiStatementSQLReader extends SQLReader {

    protected PreparedStatement myUUIDRetrievalStatement;
    protected PreparedStatement myIDRetrievalStatement;
    protected PreparedStatement myRetrievalByActorStatement;
    protected PreparedStatement myRetrievalByActorAsObjectStatement;
    protected PreparedStatement myRetrievalByVerbStatement;
    protected PreparedStatement myVoidedRetrievalStatement;

    private String myTableName = "statement";

    private XapiActorSQLReader myActorReader;
    private XapiVerbSQLReader myVerbReader;
    private XapiObjectSQLReader myObjectReader;
    private XapiContextSQLReader myContextReader;
    private XapiResultSQLReader myResultReader;

    /**
    * Description:
    *   Constructor
    *
    * Params:
    *   
    */
    public XapiStatementSQLReader(Connection conn, XapiActorSQLReader theActorReader,
            XapiVerbSQLReader theVerbReader, XapiObjectSQLReader theObjectReader,
            XapiContextSQLReader theContextReader, XapiResultSQLReader theResultReader) throws SQLException {
        this.myConn = conn;
        this.myUUIDRetrievalStatement = SQLUtility.createRetrievalStatement(super.myConn, myTableName,
                new String[] { "statementuuid", "isvoided" });
        this.myIDRetrievalStatement = SQLUtility.createRetrievalStatement(super.myConn, myTableName, "statementid");
        this.myRetrievalByActorStatement = SQLUtility.createRetrievalStatement(myConn, myTableName, "actorid");
        this.myRetrievalByVerbStatement = SQLUtility.createRetrievalStatement(myConn, myTableName, "verbid");
        this.myRetrievalByActorAsObjectStatement = createActorAsObjectStatement();
        this.myVoidedRetrievalStatement = SQLUtility.createRetrievalStatement(myConn, myTableName,
                new String[] { "statementid", "isvoided" });

        this.myActorReader = theActorReader;
        this.myVerbReader = theVerbReader;
        this.myObjectReader = theObjectReader;
        this.myContextReader = theContextReader;
        this.myResultReader = theResultReader;
    }

    /**
     * 
     * Description:
     *   Return a statement object from the database based on its uuid
     *
     * Params:
     *   theUUID
     */
    protected HashMap<Integer, XapiStatement> retrieveByUUID(String theUUID) throws SQLException {
        this.myUUIDRetrievalStatement.setString(1, theUUID);
        this.myUUIDRetrievalStatement.setInt(2, 0);
        myResult = this.myUUIDRetrievalStatement.executeQuery();

        HashMap<Integer, XapiStatement> statementArray = getStatementFromResult();

        assert statementArray.size() <= 1;

        return statementArray;
    }

    protected HashMap<Integer, XapiStatement> retrieveByUUID(UUID theUUID) throws SQLException {
        return this.retrieveByUUID(theUUID.toString());
    }

    /**
     * 
     * Description:
     *   Retrieve a statement object from the database based on its uuid
     *
     * Params:
     *
     */
    protected HashMap<Integer, XapiStatement> retrieveByID(int theID)
            throws SQLException, XapiDataIntegrityException {
        this.myIDRetrievalStatement.setInt(1, theID);

        myResult = this.myIDRetrievalStatement.executeQuery();

        HashMap<Integer, XapiStatement> statementArray = getStatementFromResult();

        if (statementArray.size() > 1) {
            throw new XapiDuplicateStatementIDException("something went wrong");
        }

        return statementArray;
    }

    protected boolean doesStatementExists(String theUUID) throws SQLException {
        this.myUUIDRetrievalStatement.setString(1, theUUID);
        this.myUUIDRetrievalStatement.setInt(2, 0);
        myResult = this.myUUIDRetrievalStatement.executeQuery();

        if (!myResult.isBeforeFirst()) {
            return false;
        }
        return true;
    }

    /**
     * 
     * Definition:
     *   Retrieve Statement based on its UUID
     *
     * Params:
     *
     *
     */
    protected int findIDByUUID(String theUUID) throws SQLException {
        this.myUUIDRetrievalStatement.setString(1, theUUID);
        this.myUUIDRetrievalStatement.setInt(2, 0);
        myResult = this.myUUIDRetrievalStatement.executeQuery();

        if (!myResult.isBeforeFirst()) {
            return -1;
        }

        myResult.next();
        return myResult.getInt(1);
    }

    /**
     * 
     * Definition:
     *   Retrieve statements based on its actor id
     *
     * Params:
     *
     *
     */
    protected HashMap<Integer, XapiStatement> retrieveStatementByActor(int actorID) throws SQLException {
        // Find statements where actor is a subject
        myRetrievalByActorStatement.setInt(1, actorID);
        myResult = myRetrievalByActorStatement.executeQuery();
        HashMap<Integer, XapiStatement> statementMap = getStatementFromResult();

        // Find statements where actor is an object
        myRetrievalByActorAsObjectStatement.setInt(1, actorID);
        myResult = myRetrievalByActorAsObjectStatement.executeQuery();
        statementMap.putAll(getStatementFromResult());

        // Find groups which the actor belongs to and then find statement which those groups are in
        ArrayList<Integer> groupIDArray = myActorReader.retrieveGroupsOfAgent(actorID);
        for (Integer i : groupIDArray) {
            statementMap.putAll(retrieveStatementByActor(i));
        }

        return statementMap;
    }

    /**
     * 
     * Definition:
     *   Return statements whose verbs match the IRI
     *
     * Params:
     *
     *
     */
    protected HashMap<Integer, XapiStatement> retrieveStatementByVerb(String theVerbIRI) throws SQLException {
        int theVerbID = myVerbReader.retrieveIDByValue(theVerbIRI);

        myRetrievalByVerbStatement.setInt(1, theVerbID);
        myResult = myRetrievalByVerbStatement.executeQuery();
        HashMap<Integer, XapiStatement> statementMap = getStatementFromResult();

        return statementMap;
    }

    private HashMap<Integer, XapiStatement> retrieveVoidedStatementByID(String theUUID) throws SQLException {
        myVoidedRetrievalStatement.setString(1, theUUID);
        myVoidedRetrievalStatement.setInt(2, 1);

        myResult = myVoidedRetrievalStatement.executeQuery();

        HashMap<Integer, XapiStatement> myVoidedStatementMap = getStatementFromResult();

        return myVoidedStatementMap;
    }

    /**
     * 
     * Definition:
     *   Helper method that will create a hashmap from result
     *
     * Params:
     *
     *
     */
    private HashMap<Integer, XapiStatement> getStatementFromResult() throws SQLException {
        HashMap<Integer, XapiStatement> statementArray = new HashMap<Integer, XapiStatement>();

        while (myResult.next()) {
            UUID theId = UUID.fromString(myResult.getString("statementuuid"));
            XapiActor theActor = myActorReader.retrieveByID(myResult.getInt("actorid"));
            XapiVerb theVerb = myVerbReader.retrieveByID(myResult.getInt("verbid"));
            XapiObject theObject = myObjectReader.retrieveByID(myResult.getInt("objectid"));
            XapiResult theResult = null;
            int theResultID = myResult.getInt("resultid");
            if (!myResult.wasNull()) {
                theResult = myResultReader.retrieveByID(theResultID);
            }

            XapiContext theContext = null;
            int theContextID = myResult.getInt("contextid");
            if (!myResult.wasNull()) {
                theContext = myContextReader.retrieveByID(theContextID);
            }

            String theTSString = null;

            Timestamp theTS = myResult.getTimestamp("sttime");
            if (!myResult.wasNull()) {
                DateTime theTimestamp = SQLUtility.getDatetime(theTS);
                theTSString = theTimestamp.withZoneRetainFields(DateTimeZone.UTC).toString();
            }

            // Voided statement should not be returned
            int isVoided = myResult.getInt("isVoided");
            if (isVoided == 0) {
                statementArray.put(myResult.getInt("statementid"),
                        new XapiStatement(theId, theActor, theVerb, theObject, theResult, theContext, theTSString));
            }
        }

        return statementArray;
    }

    protected HashMap<Integer, XapiStatement> handleConjuctionQuery(HashMap<String, String> myParamMap)
            throws SQLException, XapiDataIntegrityException, XapiSQLOperationProblemException {
        if (myParamMap.size() == 0) {
            throw new XapiConflictingParamException("There is no parameter");
        }

        if (myParamMap.containsKey("statementId") && myParamMap.size() > 1) {
            throw new XapiConflictingParamException("Other parameters are not suitable with statementId");
        } else if (myParamMap.containsKey("voidedStatementId") && myParamMap.size() > 1) {
            throw new XapiConflictingParamException("Other parameters are not suitable with voidedStatementId");
        } else if (myParamMap.containsKey("statementId") && myParamMap.containsKey("voidedStatementId")) {
            throw new XapiConflictingParamException("Can't have both statementId and voidedStatementId");
        } else if (myParamMap.containsKey("statementId") && myParamMap.size() == 1) {
            return retrieveByUUID(myParamMap.get("statementId"));
        } else if (myParamMap.containsKey("voidedStatementId") && myParamMap.size() == 1) {
            return retrieveVoidedStatementByID(myParamMap.get("voidedStatementId"));
        } else {
            ArrayList<Integer> myStatementIDs = retrieveStatementsByParameter(myParamMap);

            HashMap<Integer, XapiStatement> myResultMap = new HashMap<Integer, XapiStatement>();

            if (myStatementIDs == null) {
                return null;
            }

            for (Integer i : myStatementIDs) {
                myResultMap.put(i, retrieveByID(i.intValue()).get(i));
            }

            return myResultMap;
        }
    }

    private ArrayList<Integer> retrieveStatementsByParameter(HashMap<String, String> paramMaps)
            throws SQLException, XapiDataIntegrityException, XapiSQLOperationProblemException {
        String topHalf = "select st.statementid from statement st";
        String bottomHalf = "where";

        // This is the conjuction query
        int i = 1;
        HashMap<String, Integer> positionMap = new HashMap<String, Integer>();
        for (String s : paramMaps.keySet()) {
            if (s.equals("statementId")) {
                bottomHalf += "st.statementid = ?";
                positionMap.put(s, new Integer(i));
                i++;
            } else if (s.equals("agent")) {
                topHalf += createTopHalfString("actor", "a", "actorid");
                bottomHalf += createBottomHalfString("a", "actorid");
                positionMap.put(s, new Integer(i));
                i++;
            } else if (s.equals("verb")) {
                topHalf += createTopHalfString("verb", "v", "verbid");
                bottomHalf += createBottomHalfString("v", "verbiri");
                positionMap.put(s, new Integer(i));
                i++;
            } else if (s.equals("activity")) {
                topHalf += createTopHalfString("object", "obj", "objectid");
                topHalf += createTopHalfString("activity", "actv", "activityid");
                bottomHalf += createBottomHalfString("actv", "actviri");
                positionMap.put(s, new Integer(i));
                i++;
            } else if (s.equals("since")) {
                bottomHalf += createBottomHalfString("st", "ststored", ">");
                positionMap.put(s, new Integer(i));
                i++;
            } else if (s.equals("until")) {
                bottomHalf += createBottomHalfString("st", "ststored", "<");
                positionMap.put(s, new Integer(i));
                i++;
            }
        }

        bottomHalf += createBottomHalfString("st", "isvoided");
        positionMap.put("isvoided", i);

        bottomHalf = bottomHalf.replace("where and", "where");

        // Always order by stored time in desceding onder
        String ending = " order by ststored desc;";

        String fullString = topHalf + " " + bottomHalf + ending;

        return executeConjQueryStatement(paramMaps, positionMap, fullString);
    }

    private String createTopHalfString(String tableName, String tableNickname, String fieldName) {
        String theString = " left join %s %s using (%s)";

        return String.format(theString, tableName, tableNickname, fieldName);
    }

    private String createBottomHalfString(String tableNickname, String fieldName) {
        String theS = " and %s.%s = ?";

        return String.format(theS, tableNickname, fieldName);
    }

    private String createBottomHalfString(String tableNickname, String fieldName, String operator) {
        String theS = " and %s.%s %s ?";

        return String.format(theS, tableNickname, fieldName, operator);
    }

    private ArrayList<Integer> executeConjQueryStatement(HashMap<String, String> paramMaps,
            HashMap<String, Integer> locationMaps, String conjQueryStatement)
            throws SQLException, XapiSQLOperationProblemException {
        PreparedStatement myConjQueryStatement = myConn.prepareStatement(conjQueryStatement);
        DateTimeFormatter theFormatter = ISODateTimeFormat.dateTimeParser();
        for (String paramName : paramMaps.keySet()) {
            String paramValue = paramMaps.get(paramName);
            int locationIndex = locationMaps.get(paramName).intValue();
            if (paramName.equals("statementId")) {
                myConjQueryStatement.setString(locationIndex, paramValue);
            } else if (paramName.equals("agent")) {

                myConjQueryStatement.setInt(locationIndex, Integer.parseInt(paramValue));
            } else if (paramName.equals("verb")) {
                myConjQueryStatement.setString(locationIndex, paramValue);
            } else if (paramName.equals("activity")) {
                myConjQueryStatement.setString(locationIndex, paramValue);
            } else if (paramName.equals("since")) {
                try {
                    DateTime myTimeStamp = theFormatter.parseDateTime(paramValue);
                    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
                    myConjQueryStatement.setTimestamp(locationIndex, SQLUtility.getTimestamp(myTimeStamp), cal);
                } catch (IllegalArgumentException exc) {
                    throw new XapiSQLOperationProblemException("Having trouble reading the timestamp");
                }
            } else if (paramName.equals("until")) {
                try {
                    DateTime myTimeStamp = theFormatter.parseDateTime(paramValue);
                    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
                    myConjQueryStatement.setTimestamp(locationIndex, SQLUtility.getTimestamp(myTimeStamp), cal);
                } catch (IllegalArgumentException exc) {
                    throw new XapiSQLOperationProblemException("Having trouble parsing the timestamp");
                }
            }
        }

        myConjQueryStatement.setInt(locationMaps.get("isvoided").intValue(), 0);

        myResult = myConjQueryStatement.executeQuery();

        ArrayList<Integer> arrayIDs = new ArrayList<Integer>();

        while (myResult.next()) {
            arrayIDs.add(new Integer(myResult.getInt("statementid")));
        }

        if (arrayIDs.isEmpty()) {
            return null;
        }

        return arrayIDs;
    }

    /**
     * 
     * Definition:
     *   Helper method to create statement to retrieve actor as object
     *
     * Params:
     *
     *
     */
    private PreparedStatement createActorAsObjectStatement() throws SQLException {
        String theString = "select * from statement where objectid in (select objectid from object where "
                + "actorid = ?)";

        return super.myConn.prepareStatement(theString);
    }

    /**
     * Description:
     *    Close everything makes everything safe
     */
    protected void close() throws SQLException {
        super.close();
        SQLUtility.closeStatement(this.myIDRetrievalStatement);
        SQLUtility.closeStatement(this.myUUIDRetrievalStatement);
        SQLUtility.closeStatement(myRetrievalByActorAsObjectStatement);
        SQLUtility.closeStatement(myRetrievalByActorStatement);
        SQLUtility.closeStatement(myRetrievalByVerbStatement);
    }

    public static void main(String[] args) {
        try {

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}