/*
* Copyright (c) 2012, NTT Multimedia Communications Laboratories, Inc. and Koushik Sen
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package tests;
import catg.CATG;
import database.table.SymbolicTable;
import database.table.internals.*;
import database.table.where.Where;
import janala.Main;
import janala.utils.DebugAction;
import janala.utils.Debugger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
public class BookStoreNoSQL {
// --variables related to control concolic execution--------------------
private static final int SCREEN_VISIT_MAX = 1;
private static final int SCREEN_COUNT_MAX = 25;
private static final int S01_LOGIN_SCREEN = 1;
private static final int S02_LOGIN_ERROR_SCREEN = 2;
private static final int S03_MENU_SCREEN = 3;
private static final int S04_SEARCH_BOOKS_SCREEN = 4;
private static final int S05_NO_BOOK_SCREEN = 5;
private static final int S06_SELECT_BOOKS_SCREEN = 6;
private static final int S07_NO_SELECTION_SCREEN = 7;
private static final int S08_TOO_EXPENSIVE_SCREEN = 8;
private static final int S09_FINAL_CHECK_TO_ORDER_SCREEN = 9;
private static final int S10_THANK_YOU_ORDER_SCREEN = 10;
private static final int S11_DUPLICATE_ORDER_SCREEN = 11;
private static final int S20_NO_ORDER_SCREEN = 20;
private static final int S21_SELECT_ORDERS_SCREEN = 21;
private static final int S22_NO_SELECTED_ORDER_SCREEN = 22;
private static final int S23_FINAL_CHECK_TO_CANCEL_SCREEN = 23;
private static final int S24_FINISHED_CANCEL_SCREEN = 24;
private int[] screenVisitCountTable;
private ArrayList<VisitState> visitStateList = new ArrayList<VisitState>();
// Current inputs
private BookStoreScreenInputs cis;
// ---------------------------------------------------------------------------
// BookStoreScreenInputs screenInputs;
// --input variables of concolic execution--------------------------------
// screen inputs
private BookStoreScreenInputs[] screenInputsList;
// global inputs
private int g_customerId;
// inner variables
private ArrayList<Integer> orderIdList;
private ArrayList<Integer> selectedOrderIdList;
private ArrayList<Tuple2<Integer, Integer>> selectedBookIdPriceList;
private ArrayList<Tuple2<Integer, Integer>> orderedBookIdPriceList;
// private ArrayList<Integer> selectedOrderIdList;
private Table Customers;
private Table Orders;
private Table Publishers;
private Table Books;
// local variables for where clause (we can not use clouser...)
private int l_orderedBookId;
private int l_selectedOrderId;
// ---------------------------------------------------------------------------
class VisitState {
public int state;
public int visitCount;
public VisitState(int state, int visitCount) {
this.state = state;
this.visitCount = visitCount;
}
}
public static void main(String[] argv) {
try {
//System.out.println();
//System.out.println();
BookStoreNoSQL bookStore = new BookStoreNoSQL();
bookStore.initialize();
//bookStore.printPreConditions();
bookStore.execute();
//bookStore.printPostConditions();
bookStore.dispose();
//System.out.println();
//System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
public void printPreConditions() {
Debugger.Debug(new DebugAction() {
public void execute() {
System.out.println("--initial database state--");
PrintDBTables();
}
});
}
public void printPostConditions() {
Debugger.Debug(new DebugAction() {
public void execute() {
System.out.println("--inputs and updated database state--");
PrintVisitStatesInputs();
PrintDBTables();
}
});
}
private void PrintDBTables() {
try {
PrintDBTable(Customers);
PrintDBTable(Books);
PrintDBTable(Publishers);
PrintDBTable(Orders);
} catch (SQLException e) {
}
}
private void PrintDBTable(Table table) throws SQLException {
System.out.println("Table " + table.getName());
String[] names = table.getColumnNames();
for (String columnName : names) {
System.out.print(columnName + " ");
}
System.out.println();
TableIterator ite = table.iterator();
while (ite.hasNext()) {
Map<String, Object> record = ite.next();
for (String columnName : names) {
System.out.print(record.get(columnName) + " ");
}
System.out.println();
}
System.out.println();
}
private void PrintVisitStatesInputs() {
System.out.print("[[**visited screens = ");
for (VisitState visitState : visitStateList) {
System.out.print(visitState.state + " ");
}
System.out.println(" **]]");
for (VisitState visitState : visitStateList) {
System.out.println("Screen " + visitState.state + " (the "
+ (visitState.visitCount + 1) + " round)");
BookStoreScreenInputs is = screenInputsList[visitState.visitCount];
switch (visitState.state) {
case S01_LOGIN_SCREEN:
System.out.println("customerId=" + is.customerId);
System.out.println("password=" + is.password);
break;
case S03_MENU_SCREEN:
System.out.println("whereGoto=" + is.whereGoto);
break;
case S04_SEARCH_BOOKS_SCREEN:
System.out.println("isBackToMenue=" + is.isBackToMenu);
System.out.println("title=" + is.title);
System.out.println("publisherName=" + is.publisherName);
System.out.println("maxYear=" + is.maxYear);
System.out.println("minYear=" + is.minYear);
break;
case S06_SELECT_BOOKS_SCREEN:
printSelectedIndexes("selectedBooksIndexes",
is.selectedBooksIndexes);
break;
case S08_TOO_EXPENSIVE_SCREEN:
System.out.println("isTooExpensiveOk=" + is.isTooExpensiveOk);
break;
case S09_FINAL_CHECK_TO_ORDER_SCREEN:
System.out.println("isOrderOk=" + is.isOderderOK);
break;
case S11_DUPLICATE_ORDER_SCREEN:
System.out.println("isDuplicateOrderOk="
+ is.isDuplicateOrderOK);
break;
case S21_SELECT_ORDERS_SCREEN:
printSelectedIndexes("selectedOrdersIndexes",
is.selectedOrdersIndexes);
break;
case S23_FINAL_CHECK_TO_CANCEL_SCREEN:
System.out.println("isCancelOk=" + is.isCancelOk);
break;
}
}
System.out.println();
}
private void printSelectedIndexes(String variableName, int[] selectedIndexes) {
System.out.print(variableName + "={ ");
for (int i = 0; i < selectedIndexes.length; i++) {
System.out.print(selectedIndexes[i]);
}
System.out.println(" }");
}
public void initialize() {
screenVisitCountTable = new int[SCREEN_COUNT_MAX];
screenInputsList = new BookStoreScreenInputs[SCREEN_VISIT_MAX];
for (int i = 0; i < SCREEN_VISIT_MAX; i++) {
screenInputsList[i] = new BookStoreScreenInputs();
}
try {
Customers = TableFactory.create("Customers", new String[]{"Id",
"Name", "PasswordHash", "Age"}, new int[]{Table.INT,
Table.STRING, Table.INT, Table.INT}, new int[]{Table.PRIMARY,
Table.NONE, Table.NONE, Table.NONE}, new ForeignKey[]{null, null, null,
null});
Orders = TableFactory.create("Orders", new String[] { "Id",
"CustomerId", "OrderDateTime", "CancelDate", "BookId",
"IsCanceled" }, new int[] { Table.INT, Table.INT,
Table.INT, Table.INT, Table.INT, Table.INT },
new int[] { Table.PRIMARY, Table.NONE, Table.NONE, Table.NONE, Table.NONE, Table.NONE },
new ForeignKey[] { null, new ForeignKey(Customers, "Id"),
null, null, null, null });
Publishers = TableFactory.create("Publishers", new String[] { "Id",
"Name" }, new int[] { Table.INT, Table.STRING },
new int[] { Table.PRIMARY, Table.NONE }, new ForeignKey[] { null,
null });
Books = TableFactory.create("Books", new String[] { "Id", "ISBN",
"Title", "Price", "Year", "PublisherId", "Stock" },
new int[] { Table.INT, Table.INT, Table.STRING, Table.INT,
Table.INT, Table.INT, Table.INT }, new int[] {Table.PRIMARY,
Table.NONE, Table.NONE, Table.NONE, Table.NONE, Table.NONE, Table.NONE },
new ForeignKey[] { null, null, null, null, null,
new ForeignKey(Publishers, "Id"), null });
// create an example of inputs and initial database state
createExampleInitialDatabaseState();
createExampleInitialInputsList();
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
public void createExampleInitialDatabaseState() throws SQLException {
SymbolicTable.insertSymbolicRows(Customers, 4); // 4*4
SymbolicTable.insertSymbolicRows(Orders, 4); // 4*6
SymbolicTable.insertSymbolicRows(Publishers, 4); // 4*2
SymbolicTable.insertSymbolicRows(Books, 4); // 4*7
}
public void createExampleInitialInputsList() {
for (int i = 0; i < SCREEN_VISIT_MAX; i++) {
BookStoreScreenInputs is = screenInputsList[i];
is.customerId = Main.readInt(0);
Main.MakeSymbolic(is.customerId);
is.password = Main.readInt(1);
Main.MakeSymbolic(is.password);
is.isBackToMenu = CATG.readBool(false);
//Main.MakeSymbolic(is.isBackToMenu);
is.title = Main.readString("The Art of C#");
Main.MakeSymbolic(is.title);
is.publisherName = Main.readString("O Reilly");
Main.MakeSymbolic(is.publisherName);
is.minYear = Main.readInt(2000);
Main.MakeSymbolic(is.minYear);
is.maxYear = Main.readInt(2010);
Main.MakeSymbolic(is.maxYear);
// is.isCancelOk = Main.readBool(true);
// Main.MakeSymbolic(is.isCancelOk);
is.isCancelOk = true;
// is.isDuplicateOrderOK = Main.readBool(true);
// Main.MakeSymbolic(is.isDuplicateOrderOK);
is.isDuplicateOrderOK = true;
// is.isOderderOK = Main.readBool(is.isOderderOK);
// Main.MakeSymbolic(true);
is.isOderderOK = true;
is.isTooExpensiveOk = CATG.readBool(true);
//Main.MakeSymbolic(is.isTooExpensiveOk);
// is.whereGoto = Main.readInt(BookStoreScreenInputs.GOTO_CANCEL);
// Main.MakeSymbolic(is.whereGoto);
is.whereGoto = BookStoreScreenInputs.GOTO_ORDER;
is.selectedBooksIndexes = createExampleSelectedIndexes();
is.selectedOrdersIndexes = createExampleSelectedIndexes();
}
}
private int[] createExampleSelectedIndexes() {
int selectedIndexesSize = 1;
int[] selectedIndexes = new int[selectedIndexesSize];
for (int i = 0; i < selectedIndexesSize; i++) {
selectedIndexes[i] = i;
// selectedIndexes[i] = Main.readInt(i);
// Main.MakeSymbolic(selectedIndexes[i]);
}
return selectedIndexes;
}
public void execute() {
try {
int state = S01_LOGIN_SCREEN;
while (true) {
if (state == -1) {
System.err.println("Invalid state");
return;
}
// check screen visit count
int screenVisitCount = screenVisitCountTable[state];
if (screenVisitCount >= SCREEN_VISIT_MAX) {
System.out.println("Exceed the max count of screen visit");
return;
}
screenVisitCountTable[state]++;
cis = screenInputsList[screenVisitCount];
visitStateList.add(new VisitState(state, screenVisitCount));
// execution the business logic related to state (screen)
switch (state) {
case S01_LOGIN_SCREEN:
state = s01_loginScreen();
break;
case S02_LOGIN_ERROR_SCREEN:
state = s02_loginErrorScreen();
break;
case S03_MENU_SCREEN:
state = s03_menuScreen();
break;
case S04_SEARCH_BOOKS_SCREEN:
state = s04_searchBooksScreen();
break;
case S05_NO_BOOK_SCREEN:
state = s05_noBookScreen();
break;
case S06_SELECT_BOOKS_SCREEN:
state = s06_selectBooksScreen();
break;
case S07_NO_SELECTION_SCREEN:
state = s07_noSelectionScreen();
break;
case S08_TOO_EXPENSIVE_SCREEN:
state = s08_tooExpensiveScreen();
break;
case S09_FINAL_CHECK_TO_ORDER_SCREEN:
state = S09_finalCheckToOrderScreen();
break;
case S10_THANK_YOU_ORDER_SCREEN:
state = S10_thankYouOrderScreen();
break;
case S11_DUPLICATE_ORDER_SCREEN:
state = S11_duplicateOrderScreen();
break;
case S20_NO_ORDER_SCREEN:
state = S20_noOrderScreen();
break;
case S21_SELECT_ORDERS_SCREEN:
state = S21_selectOrdersScreen();
break;
case S22_NO_SELECTED_ORDER_SCREEN:
state = S22_noSelectedOrderScreen();
break;
case S23_FINAL_CHECK_TO_CANCEL_SCREEN:
state = S23_finalCheckToCancelScreen();
break;
case S24_FINISHED_CANCEL_SCREEN:
state = S24_finishedCannelScreen();
break;
}
CATG.equivalent("test1", "loc1", state);
}
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
public int s01_loginScreen() throws SQLException {
Main.assume(cis.customerId >= 0 ? 1 : 0);
Main.assume(cis.customerId <= 1000 ? 1 : 0);
// ResultSet rs =
// statement.executeQuery("select Id from Customers where Id="+customerId+" and PasswordHash="
// + hash(password));
ResultSet rs = Customers.select(new Where() {
public boolean where(Row[] rows) {
Integer i = (Integer) rows[0].get("Id");
if (i == null || i != cis.customerId)
return false;
i = (Integer) rows[0].get("PasswordHash");
if (i == null || i != hash(cis.password)) {
return false;
}
return true;
}
}, new String[][] { { "Id" } }, null).getResultSet();
ArrayList<Integer> customerIdList = new ArrayList<Integer>();
while (rs.next()) {
customerIdList.add(rs.getInt("Id"));
}
if (customerIdList.size() > 0) {
g_customerId = cis.customerId;
return S03_MENU_SCREEN;
} else {
return S02_LOGIN_ERROR_SCREEN;
}
}
private int s02_loginErrorScreen() {
return S01_LOGIN_SCREEN;
}
private int s03_menuScreen() throws SQLException {
Main.assume((cis.whereGoto == BookStoreScreenInputs.GOTO_ORDER || cis.whereGoto == BookStoreScreenInputs.GOTO_CANCEL) ? 1
: 0);
if (cis.whereGoto == BookStoreScreenInputs.GOTO_ORDER) {
return S04_SEARCH_BOOKS_SCREEN;
} else if (cis.whereGoto == BookStoreScreenInputs.GOTO_CANCEL) {
ResultSet rs = Orders.select(new Where() {
public boolean where(Row[] rows) {
Integer i = (Integer) rows[0].get("CustomerId");
Integer isCanceled = (Integer) rows[0].get("IsCanceled");
if (i == null || i != g_customerId)
return false;
if (isCanceled == null || isCanceled == 1) {
return false;
}
return true;
}
}, new String[][] { { "Id" } }, null).getResultSet();
orderIdList = new ArrayList<Integer>();
while (rs.next()) {
orderIdList.add(rs.getInt("Id"));
}
if (orderIdList.size() > 0) {
return S21_SELECT_ORDERS_SCREEN;
} else {
return S20_NO_ORDER_SCREEN;
}
} else {
return -1;
}
}
private int s04_searchBooksScreen() throws SQLException {
if (cis.isBackToMenu) {
return S03_MENU_SCREEN;
}
Main.assume(cis.title.length() >= 0 ? 1 : 0);
Main.assume(cis.title.length() <= 20 ? 1 : 0);
Main.assume(cis.publisherName.length() >= 0 ? 1 : 0);
Main.assume(cis.publisherName.length() <= 20 ? 1 : 0);
Main.assume(cis.minYear >= 1950 ? 1 : 0);
Main.assume(cis.minYear <= 2050 ? 1 : 0);
Main.assume(cis.maxYear >= 1950 ? 1 : 0);
Main.assume(cis.maxYear <= 2050 ? 1 : 0);
ResultSet rs = Books.select(new Where() {
public boolean where(Row[] rows) {
if (!rows[0].get("PublisherId").equals(rows[1].get("Id")))
return false;
if (!cis.title.equals(rows[0].get("Title")))
return false;
if ((Integer) rows[0].get("Stock") <= 0)
return false;
if ((Integer) rows[0].get("Year") < cis.minYear)
return false;
if ((Integer) rows[0].get("Year") > cis.maxYear)
return false;
if (!cis.publisherName.equals(rows[1].get("Name")))
return false;
return true;
}
}, new String[][] { { "Id", "Price" }, null },
new Table[] { Publishers }).getResultSet();
// ResultSet rs =
// statement.executeQuery("select Books.Id, Books.Price from Books inner join Publishers on Books.PublisherId = Publishers.Id "
// +
// "where Books.Title= '" + title +
// "' and Publishers.Name='"+publisherName+"' and Books.Year>=" +
// minYear +
// " and Books.Year<=" + maxYear + " and Books.Stock > 0");
selectedBookIdPriceList = new ArrayList<Tuple2<Integer, Integer>>();
while (rs.next()) {
selectedBookIdPriceList.add(new Tuple2<Integer, Integer>(rs
.getInt("Id"), rs.getInt("Price")));
}
if (selectedBookIdPriceList.size() > 0) {
return S06_SELECT_BOOKS_SCREEN;
} else {
return S05_NO_BOOK_SCREEN;
}
}
private int s05_noBookScreen() {//
return S04_SEARCH_BOOKS_SCREEN;
}
private int s06_selectBooksScreen() throws SQLException {
orderedBookIdPriceList = new ArrayList<Tuple2<Integer, Integer>>();
for (int selectedIndex : cis.selectedBooksIndexes) {
orderedBookIdPriceList.add(selectedBookIdPriceList
.get(selectedIndex));
}
int sumPrice = 0;
for (Tuple2<Integer, Integer> orderedBookIdPrice : orderedBookIdPriceList) {
sumPrice += orderedBookIdPrice.snd;
}
if (sumPrice > 10000) {
return S08_TOO_EXPENSIVE_SCREEN;
}
ResultSet rs = Orders.select(new Where() {
public boolean where(Row[] rows) {
Integer i = (Integer) rows[0].get("CustomerId");
if (i == null || i != g_customerId)
return false;
return true;
}
}, new String[][] { { "Id" } }, null).getResultSet();
ArrayList<Integer> alreadyOrderedBookIdList = new ArrayList<Integer>();
while (rs.next()) {
alreadyOrderedBookIdList.add(rs.getInt("Id"));
}
int dupulicateOrderCount = 0;
for (Tuple2<Integer, Integer> orderedBookIdPrice : orderedBookIdPriceList) {
if (alreadyOrderedBookIdList.contains(orderedBookIdPrice.fst)) {
dupulicateOrderCount++;
}
}
if (dupulicateOrderCount > 0) {
return S11_DUPLICATE_ORDER_SCREEN;
}
return S09_FINAL_CHECK_TO_ORDER_SCREEN;
}
private int s07_noSelectionScreen() {
return S06_SELECT_BOOKS_SCREEN;
}
private int s08_tooExpensiveScreen() {
if (cis.isTooExpensiveOk) {
return S09_FINAL_CHECK_TO_ORDER_SCREEN;
} else {
return S06_SELECT_BOOKS_SCREEN;
}
}
public int orderId = 0;
private int S09_finalCheckToOrderScreen() {
if (!cis.isOderderOK) {
return S04_SEARCH_BOOKS_SCREEN;
}
final int CURREMT_TIME_STAMP = 20120714;
for (Tuple2<Integer, Integer> orderedBookIdPrice : orderedBookIdPriceList) {
orderId++;
// Object[] newOrder = {orderId ,g_customerId, CURREMT_TIME_STAMP,
// null,
Object[] newOrder = { orderId, g_customerId, CURREMT_TIME_STAMP,
null, orderedBookIdPrice.fst, 0 };
try {
Orders.insert(newOrder);
} catch (AssertionError e) {
return -1;
}
l_orderedBookId = orderedBookIdPrice.fst;
try {
Books.update(new Where() {
public boolean modify(Row rows) {
Integer id = (Integer) rows.get("Id");
if (id == null || id != l_orderedBookId) {
return false;
} else {
Integer stock = (Integer) rows.get("Stock");
rows.put("Stock", stock - 1);
return true;
}
}
public boolean where(Row[] rows) {
return true;
}
});
} catch (AssertionError e) {
return -1;
}
}
return S10_THANK_YOU_ORDER_SCREEN;
}
private int S10_thankYouOrderScreen() {
return S04_SEARCH_BOOKS_SCREEN;
}
private int S11_duplicateOrderScreen() {
if (cis.isDuplicateOrderOK) {
return S09_FINAL_CHECK_TO_ORDER_SCREEN;
} else {
return S06_SELECT_BOOKS_SCREEN;
}
}
private int S20_noOrderScreen() {
return S03_MENU_SCREEN;
}
private int S21_selectOrdersScreen() {
selectedOrderIdList = new ArrayList<Integer>();
for (int selectedIndex : cis.selectedOrdersIndexes) {
selectedOrderIdList.add(orderIdList.get(selectedIndex));
}
if (selectedOrderIdList.size() > 0) {
return S23_FINAL_CHECK_TO_CANCEL_SCREEN;
} else {
return S22_NO_SELECTED_ORDER_SCREEN;
}
}
private int S22_noSelectedOrderScreen() {
return S21_SELECT_ORDERS_SCREEN;
}
private int S23_finalCheckToCancelScreen() {
final int CURREMT_TIME_STAMP = 20120721;
if (cis.isCancelOk) {
for (int selectedOrderId : selectedOrderIdList) {
l_selectedOrderId = selectedOrderId;
Orders.update(new Where() {
public boolean modify(Row rows) {
Integer id = (Integer) rows.get("Id");
if (id == null || id != l_selectedOrderId) {
return false;
} else {
rows.put("IsCanceled", 1);
rows.put("CancelDate", CURREMT_TIME_STAMP);
return true;
}
}
public boolean where(Row[] rows) {
return true;
}
});
}
return S24_FINISHED_CANCEL_SCREEN;
} else {
return S23_FINAL_CHECK_TO_CANCEL_SCREEN;
}
}
private int S24_finishedCannelScreen() {
return S21_SELECT_ORDERS_SCREEN;
}
private int hash(int password) {
return password;
}
public void dispose() {
}
}