package context.arch.storage;
//import java.util.Vector;
//import java.util.Hashtable;
//import java.util.Enumeration;
//import java.util.Date;
//import java.math.BigInteger;
//import java.sql.DriverManager;
//import java.sql.Connection;
//import java.sql.Statement;
//import java.sql.ResultSet;
//import java.sql.SQLException;
/**
* This class allows storage and retrieval of data in String, Integer, Long, Float,
* Double, or Short format. It implements the Storage interface, using a Vector to
* store data temporarily. It can flush locally stored data to persistent data upon
* request.
*
* TODO: database design needs to be normalized to be more scalable
* TODO: actually needs a severe overhaul --Brian
*
* @author Anind Dey
* @author Brian Y. Lim
*/
public class VectorStorage
//implements Storage
{
//// private Hashtable<String, String> attributeTypes;
// private Attributes attributes;
// @SuppressWarnings("unused")
// private String storageClass = "";
// private long lastFlush = 0;
// private long numStored = 0;
// private int flushType;
// private long flushCondition;
// private String table;
// private boolean firstTime = true;
// private Vector<Attributes> data;
//
// /**
// * Debug flag. Set to true to see debug messages.
// */
// private static final boolean DEBUG = false;
//
// /**
// * Default flush type is by number of stores
// */
// public static final int DEFAULT_FLUSH_TYPE = DATA;
//
// /**
// * Default flush condition is 2 (i.e. flush after 2 stores)
// */
// public static final long DEFAULT_FLUSH_CONDITION = 2;
//
// /**
// * Separator used in structured info
// */
// public static final char OLD_SEPARATOR = Attributes.SEPARATOR;
//
// /**
// * Separator used in structured info - String
// */
// public static final String OLD_SEPARATOR_STRING = new Character(Attributes.SEPARATOR).toString();
//
// /**
// * Separator used by database in structured info
// */
// public static final char NEW_SEPARATOR = '_';
//
// /**
// * Separator used by database in structured info - String
// */
// public static final String NEW_SEPARATOR_STRING = new Character(NEW_SEPARATOR).toString();
//
// /**
// * Basic constructor that uses the default flush condition
// *
// * @param table Name of table to use
// * @exception SQLException if errors in accessing table info
// */
// public VectorStorage(String table) throws SQLException {
// this(table, new Integer(DEFAULT_FLUSH_TYPE),new Long(DEFAULT_FLUSH_CONDITION));
// }
//
// /**
// * Basic constructor that uses the given flush type and condition
// *
// * @param table Name of table to use
// * @param flushType Flush to database based on TIME or DATA
// * @param flushCondition Condition to flush local storage to database
// * @exception SQLException if errors in accessing table info
// */
// public VectorStorage(String tableName, Integer flushType, Long flushCondition) throws SQLException {
// try {
// Class.forName("gwe.sql.gweMysqlDriver");
// } catch (ClassNotFoundException cnfe) {
// System.out.println("VectorStorage constructor ClassNotFound: "+cnfe);
// }
// table = tableName.replace(' ','_');
// data = new Vector<Attributes>();
//
// this.flushType = flushType.intValue();
// this.flushCondition = flushCondition.longValue();
// if (this.flushType == TIME) {
// lastFlush = new Date().getTime();
// }
// }
//
// /**
// * This method stores the given AttributeNameValues object
// *
// * @param atts AttributeNameValues to store
// */
// public void store(Attributes atts) {
// data.addElement(atts);
// numStored++;
// }
//
// /**
// * This method returns a Vector containing AttributeNameValue objects that match
// * the given conditions in the Retrieval object. It takes in the accessorId of the
// * "user" requesting the information, but does nothing with it currently.
// *
// * @param accessorId Id of the "user" trying to retrieve the data
// * @param retrieval Retrievals object containing conditions for data retrieval
// * @return RetrievalResults containing AttributeNameValues objects that match the given conditions
// */
// public RetrievalResults retrieveAttributes(String accessorId, Retrieval retrieval) {
// return retrieveAttributes (retrieval);
// }
//
// /**
// * This method returns a Vector containing AttributeNameValue objects that match
// * the given conditions in the Retrieval object.
// *
// * @param retrieval Retrievals object containing conditions for data retrieval
// * @return RetrievalResults containing AttributeNameValues objects that match the given conditions
// */
// public RetrievalResults retrieveAttributes(Retrieval retrieval) {
// flushStorage();
// StringBuffer statement = new StringBuffer("SELECT ");
// AttributeFunctions atts = retrieval.getAttributeFunctions();
// if (atts.isEmpty()) { return null; }
//
// AttributeFunctions newAtts = new AttributeFunctions();
//
// // for each attribute, fix name for database use and check if struct data
// for (AttributeFunction<?> att : atts.values()) {
// String name = att.getName().replace(OLD_SEPARATOR,NEW_SEPARATOR);
// Attribute<?> attr = attributes.get(name);
//
// // if struct data, flatten struct data and put into newAtts
// if (attr.hasSubAttributes()) {
// Attributes flatAtts = attr.getSubAttributes();
// for (Attribute<?> subAtt : flatAtts.values()) {
// if (!subAtt.hasSubAttributes()) {
// newAtts.add(AttributeFunction.instance(
// name.replace(OLD_SEPARATOR,NEW_SEPARATOR),
// AttributeFunction.DEFAULT_TYPE,
// AttributeFunction.FUNCTION_NONE));
// }
// }
// }
// // els if not struct data, put attribute into newAtts
// else {
// newAtts.add(AttributeFunction.instance(
// name,
// AttributeFunction.DEFAULT_TYPE,
// att.getFunction()));
// }
// }
//
// boolean special = false;
// AttributeFunctions specialAtts = new AttributeFunctions();
// for (AttributeFunction<?> af : newAtts.values()) {
// if ((af.getFunction().equals(AttributeFunction.FUNCTION_MAX)) || (af.getFunction().equals(AttributeFunction.FUNCTION_MIN))) {
// if (!special) {
// specialAtts.add(AttributeFunction.instance(
// af.getName(),
// af.getFunction()));
// statement.append(af.getFunction()+"("+af.getName()+")");
// special = true;
// }
// }
// }
//
// if (special) {
// statement.append(" FROM " + table);
//
// @SuppressWarnings("unused")
// boolean where = false;
// Conditions conditions = retrieval.getConditions();
// for (int i=0; i<conditions.numConditions(); i++) {
// if (i == 0) {
// statement.append(" WHERE ");
// where = true;
// }
// else {
// statement.append(" AND ");
// }
// Condition condition = conditions.getConditionAt(i);
// statement.append (condition.getAttribute().replace(OLD_SEPARATOR,NEW_SEPARATOR));
// switch (condition.getCompare()) {
// case LESSTHAN: statement.append("<"); break;
// case LESSTHANEQUAL: statement.append("<="); break;
// case GREATERTHAN: statement.append(">"); break;
// case GREATERTHANEQUAL: statement.append(">="); break;
// case EQUAL: statement.append("="); break;
// }
// String attributeName = condition.getAttribute().replace(OLD_SEPARATOR, NEW_SEPARATOR);
// if (attributes.get(attributeName).isType(String.class)) {
// statement.append("'" + condition.getValue().toString() + "'");
// }
// else {
// statement.append(condition.getValue().toString());
// }
// }
//
// statement.append("\n");
//
// Vector<Hashtable<String, AttributeNameValue<?>>> preResults = executeRetrieveQuery(specialAtts, statement.toString());
//
// if (preResults == null) {
// return null;
// }
//
// RetrievalResults results = new RetrievalResults();
// AttributeFunctions attNames = specialAtts;
// for (int j=0; j<preResults.size(); j++) {
// Hashtable<String, AttributeNameValue> resultAtts = preResults.elementAt(j);
// Attributes newAttValues = new Attributes();
// for (int k=0; k<attNames.numAttributeFunctions(); k++) {
// String attName = attNames.getAttributeFunctionAt(k).getName();
// AttributeNameValue<?> newAttValue = resultAtts.get(attName);
// if (newAttValue.getValue() != null) {
// newAttValues.addAttributeNameValue(newAttValue);
// }
// }
// if (!newAttValues.isEmpty()) {
// results.addAttributes(newAttValues);
// }
// }
// if (results.numAttributeNameValues() != 0) {
// Attributes anvs = results.getAttributesAt(0);
// Attribute<?> anv = anvs.getAttributeAt(0);
// if (anv instanceof AttributeNameValue<?>) {
// conditions.addCondition(anv.getName(),EQUAL,((AttributeNameValue)anv).getValue());
// }
// }
// else {
// return null;
// }
// statement = new StringBuffer("SELECT ");
// }
//
// AttributeFunction af = newAtts.getAttributeFunctionAt(0);
// String func = af.getFunction();
// if (func == null) {
// statement.append(af.getName());
// }
// else {
// if ((func.equals(AttributeFunction.FUNCTION_NONE)) ||
// (func.equals(AttributeFunction.FUNCTION_MAX)) ||
// (func.equals(AttributeFunction.FUNCTION_MIN))) {
// statement.append(af.getName());
// }
// else {
// statement.append(func+"("+af.getName()+")");
// }
// }
// for (int i=1; i<newAtts.numAttributeFunctions(); i++) {
// af = newAtts.getAttributeFunctionAt(i);
// func = af.getFunction();
// if (func == null) {
// statement.append(","+af.getName());
// }
// if ((func.equals(AttributeFunction.FUNCTION_NONE)) ||
// (func.equals(AttributeFunction.FUNCTION_MAX)) ||
// (func.equals(AttributeFunction.FUNCTION_MIN))) {
// statement.append(","+af.getName());
// }
// else {
// statement.append(","+func+"("+af.getName()+")");
// }
// }
// statement.append(" FROM "+table);
//
// @SuppressWarnings("unused")
// boolean where = false;
// Conditions conditions = retrieval.getConditions();
// for (int i=0; i<conditions.numConditions(); i++) {
// if (i == 0) {
// statement.append(" WHERE ");
// where = true;
// }
// else {
// statement.append(" AND ");
// }
// Condition condition = conditions.getConditionAt(i);
// statement.append (condition.getAttribute().replace(OLD_SEPARATOR,NEW_SEPARATOR));
// switch (condition.getCompare()) {
// case LESSTHAN: statement.append("<"); break;
// case LESSTHANEQUAL: statement.append("<="); break;
// case GREATERTHAN: statement.append(">"); break;
// case GREATERTHANEQUAL: statement.append(">="); break;
// case EQUAL: statement.append("="); break;
// }
// String name = condition.getAttribute().replace(OLD_SEPARATOR, NEW_SEPARATOR);
// if (attributes.get(name).isType(String.class)) {
// statement.append("'" + condition.getValue().toString() + "'");
// }
// else {
// statement.append(condition.getValue().toString());
// }
// }
//
// statement.append("\n");
//
// Vector<Hashtable<String, AttributeNameValue>> preResults = executeRetrieveQuery(newAtts, statement.toString());
//
// if (preResults == null) {
// return null;
// }
//
// RetrievalResults results = new RetrievalResults();
// AttributeFunctions attNames = retrieval.getAttributeFunctions();
// if (attNames.getAttributeFunctionAt(0).getName().equals(Attributes.ALL)) {
// attNames = new AttributeFunctions();
// for (Attribute<?> att : attributes.values()) {
// attNames.addAttributeFunction(att.getName());
// }
// }
// for (int j=0; j<preResults.size(); j++) {
// Hashtable<String, AttributeNameValue> resultAtts = preResults.elementAt(j);
// Attributes newAttValues = new Attributes();
// for (int k=0; k<attNames.numAttributeFunctions(); k++) {
// String attName = attNames.getAttributeFunctionAt(k).getName();
// if (attributes.get(attName.replace(OLD_SEPARATOR, NEW_SEPARATOR)).hasSubAttributes()) {
// AttributeNameValue<?> newAttValue = getAttributeNameValue(attName,resultAtts);
// if (newAttValue.getValue() != null) {
// newAttValues.add(newAttValue);
// }
// }
// else {
// AttributeNameValue<?> newAttValue = resultAtts.get(attName);
// if (newAttValue.getValue() != null) {
// newAttValues.add(newAttValue);
// }
// }
// }
// if (!newAttValues.isEmpty()) {
// results.addAttributes(newAttValues);
// }
// }
// return results;
// }
//
// /**
// * This method takes an attribute name (whose attribute type is STRUCT)
// * and returns the complete attribute information for it.
// *
// * @param name Name of the attribute
// * @param values Hashtable containing all the values retrieved from a line
// * in the database table
// * @return AttributeNameValue containing all the STRUCT's values in a hierarchical
// * format
// */
// private AttributeNameValue getAttributeNameValue(String name, Hashtable<String, AttributeNameValue> values) {
// return getAttributeNameValue(name,values,"");
// }
//
// /**
// * This method takes an attribute name (whose attribute type is STRUCT)
// * and returns the complete attribute information for it.
// *
// * @param name Name of the attribute
// * @param values Hashtable containing all the values retrieved from a line
// * in the database table
// * @param prefix to use for structure info
// * @return AttributeNameValue containing all the STRUCT's values in a hierarchical
// * format
// */
// private AttributeNameValue<?> getAttributeNameValue(String name, Hashtable<String, AttributeNameValue> values, String prefix) {
// prefix = prefix.trim();
// if ((prefix.length() != 0) && !(prefix.endsWith(OLD_SEPARATOR_STRING))) {
// prefix = prefix + OLD_SEPARATOR_STRING;
// }
//
// Attribute<?> att = attributes.get(prefix + name);
// if (att.hasSubAttributes()) {
// Attributes subAtts = att.getSubAttributes();
// Attributes newSubAtts = new Attributes();
// for (int i=0; i<subAtts.numAttributes(); i++) {
// Attribute subAtt = subAtts.getAttributeAt(i);
// newSubAtts.addAttributeNameValue(getAttributeNameValue(prefix + name + OLD_SEPARATOR_STRING + subAtt.getName(), values));
// }
// return new AttributeNameValue(prefix + name, newSubAtts, Attribute.STRUCT);
// }
// else {
// return values.get(prefix+name);
// }
// }
//
// /**
// * Checks condition under which local data is sent to persistent storage.
// */
// public boolean checkFlushCondition() {
// if (flushType == TIME) {
// long tmp = new Date().getTime();
// if (lastFlush + flushCondition <= tmp) {
// return true;
// }
// }
// else if (flushType == DATA) {
// if (flushCondition <= numStored) {
// if (DEBUG) {
// System.out.println("flush is true");
// }
// return true;
// }
// }
// return false;
// }
//
// /**
// * Flushes local data to persistent storage
// */
// public void flushStorage() {
// if (data.size() == 0) {
// return;
// }
//
// if (DEBUG) {
// System.out.println("flushing");
// }
//
// try {
// if (firstTime) {
// firstTime = false;
// if (!tableExists(table)) {
// createTable();
// }
// }
//
// Connection conn = StorageObject.getConnection();
// Statement statement = conn.createStatement();
//
// for (Attributes atts : data) {
// String s = createInsertStatement(atts);
// statement.executeUpdate(s);
// }
//
// statement.close();
// conn.close();
//
// } catch (SQLException e) {
// e.printStackTrace();
// }
// resetForFlush();
// }
//
// /**
// * This private method creates and returns a SQL statement for inserting
// * data into a database.
// *
// * @param atts AttributeNameValues to put in the database
// * @return SQL statement for inserting the attributes into a database
// */
// private String createInsertStatement(Attributes atts) {
// StringBuffer statement = new StringBuffer("insert into "+ table +" (");
// StringBuffer values = new StringBuffer(" values (");
//
// for (Attribute<?> attr : atts.values()) {
// if (!(attr instanceof AttributeNameValue<?>)) {
// continue;
// }
//
// AttributeNameValue<?> att = (AttributeNameValue<?>) attr;
//
// statement.append(att.getName());
// if (att.isType(String.class)) {
// values.append("'"+att.getValue()+"'");
// }
// else if (att.hasSubAttributes()) {
// Attributes subAtts = att.getSubAttributes();
// values.append(subAtts.size());
// String subResult = createSubInsertStatement(subAtts, att.getName() + NEW_SEPARATOR);
// int index = subResult.indexOf("()");
// statement.append(subResult.substring(0,index));
// values.append(subResult.substring(index + 2));
// }
// else {
// values.append(att.getValue());
// }
//
// statement.append(",");
// values.append(",");
// }
// values.append(")");
// statement.append(")"+values.toString());
// return statement.toString();
// }
//
// /**
// * This private method creates and returns a SQL statement for inserting
// * data into a database. It uses prefix information for structures.
// *
// * @param atts AttributeNameValues to put in the database
// * @return SQL statement for inserting the attributes into a database
// */
// private String createSubInsertStatement(Attributes atts, String prefix) {
// String statement = "";
// String values = "";
//
// for (Attribute<?> attr : atts.values()) {
// if (!(attr instanceof AttributeNameValue<?>)) { continue; }
// AttributeNameValue<?> att = (AttributeNameValue<?>) attr;
//
// statement += "," + prefix + att.getName();
//
// if (att.isType(String.class)) {
// values += ",'" + att.getValue() + "'";
// }
// else if (att.hasSubAttributes()) {
// Attributes subAtts = (Attributes)att.getValue();
// values += "," + subAtts.size();
//
// String subResult = createSubInsertStatement(subAtts, prefix
// + NEW_SEPARATOR_STRING + att.getName() + NEW_SEPARATOR);
// int index = subResult.indexOf("()");
//
// statement += subResult.substring(0,index);
// values += subResult.substring(index + 2);
// }
// else {
// values += "," + att.getValue();
// }
// }
// statement += "()" + values.toString();
// return statement;
// }
//
// /**
// * This private method resets the data for local storage. It should be called
// * after data is flushed to persistent storage.
// */
// private void resetForFlush() {
// numStored = 0;
// lastFlush = new Date().getTime();
// data = new Vector<Attributes>();
// }
//
// /**
// * This method contacts the database with the given query and returns a Vector
// * of AttributeNameValues objects that match the query, if any. If the query fails for
// * any reason, null is returned
// *
// * @param attnames Vector of attribute names to return
// * @param query SELECT query to execute on the database
// * @return Vector of AttributeNameValues objects that the query returns
// */
// private Vector<Hashtable<String, AttributeNameValue<?>>> executeRetrieveQuery(AttributeFunctions atts, String query) {
// try {
// Connection con = StorageObject.getConnection();
// Statement stmt = con.createStatement();
// ResultSet rs = stmt.executeQuery(query);
//
// Vector<Hashtable<String, AttributeNameValue<?>>> v = new Vector<Hashtable<String, AttributeNameValue>>();
// while (rs.next()) {
// Hashtable<String, AttributeNameValue<?>> returnAtts = new Hashtable<String, AttributeNameValue>();
// for (int i=0; i<atts.numAttributeFunctions(); i++) {
// AttributeFunction att = atts.getAttributeFunctionAt(i);
// String name = att.getName();
// Class<?> type = att.getType();
// String value = (String)rs.getString(i + 1); // TODO: how to extract native format?
// name = name.replace(NEW_SEPARATOR, OLD_SEPARATOR);
// returnAtts.put(name, AttributeNameValue.instance(name, value, type));
// }
// v.addElement(returnAtts);
// }
// rs.close();
// stmt.close();
// con.close();
// return v;
// } catch(SQLException sqle) {
// System.out.println("VectorStorage executeRetrieveQuery SQL: "+sqle);
// }
// return null;
// }
//
// /**
// * Checks to see if the given table exists
// *
// * @param stmt SQL statement to use
// * @param tablename Name of the table to check on
// * @return whether the table exists or not
// * @throws SQLException when problems with check occur
// */
// private boolean tableExists(String tablename) throws SQLException {
// Connection con = StorageObject.getConnection();
// Statement stmt = con.createStatement();
//
// ResultSet rs = stmt.executeQuery("SHOW TABLES");
// while(rs.next()) {
// String result = rs.getString(1);
// if (result.equals(tablename)) {
// return true;
// }
// }
// rs.close();
// stmt.close();
// con.close();
// return false;
// }
//
// /**
// * This private method returns attribute type information from the database.
// *
// * @param stmt SQL statement to use
// * @param tablename Name of table to get type information from
// * @return hashtable containing type information, with attribute names as keys
// * @throws SQLException when problems with retrieving the type info occur
// */
// @SuppressWarnings("unused")
// private static Hashtable<String, String> getTypeInfo(String tablename) throws SQLException {
// Hashtable<String, String> hash = new Hashtable<String, String>();
// Connection con = StorageObject.getConnection();
// Statement stmt = con.createStatement();
// ResultSet rs = stmt.executeQuery("SELECT * FROM " + tablename);
// while (rs.next()) {
// hash.put(rs.getString(1), rs.getString(2));
// }
// rs.close();
// stmt.close();
// con.close();
// return hash;
// }
//
// /**
// * This private method creates a database table for storing attribute values.
// *
// * @param stmt SQL statement to use
// * @throws SQLException when problems creating the table occur
// */
// private void createTable() throws SQLException {
// String s = "CREATE TABLE " + table + " (";
//
// for (Attribute<?> att : attributes.values()) {
// s += att + " ";
//
// /*
// * Data type of attribute
// */
// if (att.isType(Integer.class)) {
// s += "INT";
// }
// else if (att.isType(Short.class)) {
// s += "SMALLINT";
// }
// else if (att.isType(Double.class)) {
// s += "DOUBLE";
// }
// else if (att.isType(Float.class)) {
// s += "FLOAT";
// }
// else if (att.isType(BigInteger.class)) {
// s += "BIGINT";
// }
// else if (att.isType(String.class)) {
// s += "TEXT"; // TODO: consider using VARCHAR instead of TEXT --Brian
// }
// else if (att.hasSubAttributes()) {
// s += "INT"; // for ID of struct? --Brian
// }
//
// s += ", ";
// }
// s = s.substring(0, s.length()-2); // truncate last ", " // TODO: use String.join instead
// s += ")";
//
// Connection conn = StorageObject.getConnection();
// Statement stmt = conn.createStatement();
// stmt.executeUpdate(s);
// stmt.close();
// conn.close();
// }
//
// /**
// * This method sets the attributes to use for storage. The attributes
// * are used to set up the columns in a database table.
// *
// * @param attributes Attributes object containing attributes and type info
// * @param attTypes Flattened hashtable version of Attributes
// */
// @Override
// public void setAttributes(Attributes attributes) {
// attributeTypes = new Hashtable<String, String>();
// for (String name : attTypes.keySet()) {
// attributeTypes.put(name.replace(OLD_SEPARATOR,NEW_SEPARATOR), attTypes.get(name));
// }
// this.attributes = attributes;
// }
}