Skip to content

Commit

Permalink
Introducing the notification queue
Browse files Browse the repository at this point in the history
It will one day be able to consolidate recent several events to notify users about into a single email.

Right now it's an untested system.out.println(), but we'll get there.
  • Loading branch information
arc12012 committed Apr 17, 2017
1 parent 3b4e711 commit b473947
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 10 deletions.
7 changes: 7 additions & 0 deletions WebContent/html/webpages/redirect/ticketAdminRedirect.jsp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<%@ page import = "database.*" %>
<%@ page import = "utilities.NotificationQueue" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
Expand Down Expand Up @@ -37,6 +38,12 @@ int locationid = Integer.parseInt(locationidstr);
//add form was submitted
if(request.getParameter("approve") != null){
TicketQueries.acceptTicket(ticketid,deviceid,locationid,Integer.parseInt(navsso));
User client = EmployeeQueries.getEmployeeByID(TicketQueries.getUserID(ticketid));
boolean notificationPreferences = true; //TODO get real preference
if(notificationPreferences){
NotificationQueue q = new NotificationQueue(client,"ticketConfirmations");
q.run();
}
}
//modify form was submitted
if(request.getParameter("reject") != null){
Expand Down
2 changes: 1 addition & 1 deletion src/database/DeviceQueries.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public static void addDevice(Device device) throws SQLException, ClassNotFoundEx
id = results.getInt("Device_ID");
id++;
//tries this statement, otherwise tries again with a new id
String command = "INSERT INTO devices (Device_ID,Device_Name,Device_Description,MAC_Address,Manufacturer,Hardware,Model,Serial_Num,Status,Added_By,NFC_ID) " + "VALUES (" + id +",\"" + device.getName() + "\",\"" + device.getDesc()+ "\",\"" + device.getMAC() + "\",\"" + device.getManufacturer() + "\",\""+device.getHardware()+ "\",\"" + device.getModel() + "\",\"" + device.getSerial() + "\",\"" + device.getStatus() + "\",30,\"" + device.getNFC() + "\");"; //TODO update the Added_By to include cookies
String command = "INSERT INTO devices (Device_ID,Device_Name,Device_Description,MAC_Address,Manufacturer,Hardware,Model,Serial_Num,Status,Added_By,NFC_ID) " + "VALUES (" + id +",\"" + device.getName() + "\",\"" + device.getDesc()+ "\",\"" + device.getMAC() + "\",\"" + device.getManufacturer() + "\",\""+device.getHardware()+ "\",\"" + device.getModel() + "\",\"" + device.getSerial() + "\",\"" + device.getStatus() + "\",30,\"" + device.getNFC() + "\");";
System.out.println(command);
i = stmt.executeUpdate(command);
}
Expand Down
2 changes: 1 addition & 1 deletion src/database/LocationQueries.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static Location[] getLocations() throws ClassNotFoundException, SQLExcept

public static Location[] getLocations(int userID) throws SQLException, ClassNotFoundException
{
String query = "SELECT * FROM location WHERE Employee_Flag = 0 OR Employee_Flag = "+userID+" ORDER BY Name ASC"; //TODO filter for custom locations (needs db change)
String query = "SELECT * FROM location WHERE Employee_Flag = 0 OR Employee_Flag = "+userID+" ORDER BY Name ASC";
System.getenv("VCAP_SERVICES");
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(database, user, password);
Expand Down
43 changes: 41 additions & 2 deletions src/database/TicketQueries.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ public Ticket[] getTickets() throws SQLException, ClassNotFoundException{
tickets[i] = new Ticket(
resultSet.getInt("Ticket_ID"),
resultSet.getInt("Requestor"),
//resultSet.getInt("Request_Date"),
resultSet.getLong("Request_Date"),
resultSet.getInt("Location"),
resultSet.getInt("Device_ID"),
status,
resultSet.getLong("Status_Date_Fields"),
resultSet.getString("Return_Date")
);
i++;
Expand All @@ -71,8 +72,9 @@ public static void acceptTicket(int ticketid, int deviceid, int locationid, int
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection(database, user, password);
Statement stmt = connect.createStatement();
long milliseconds = new java.util.Date().getTime();
stmt.executeUpdate("UPDATE ticket SET Status = \"Approved\" WHERE Ticket_ID = " + ticketid);
stmt.executeUpdate("UPDATE devices SET Ticket_ID = " + ticketid + ", Status = \"Shipped\", Renter = " + sso + ", Location = " + locationid + " WHERE Device_ID = " + deviceid);
stmt.executeUpdate("UPDATE devices SET Ticket_ID = " + ticketid + ", Status = \"Shipped\", Renter = " + sso + ", Location = " + locationid + " Status_Date_Fields = "+milliseconds+" WHERE Device_ID = " + deviceid);
stmt.close();
connect.close();
}
Expand All @@ -86,5 +88,42 @@ public static void rejectTicket(int id) throws SQLException, ClassNotFoundExcept
stmt.close();
connect.close();
}

// Returns all tickets approved since 'millieconds' and associated with 'employee'
public static Ticket[] getApprovedTickets(int userID, long milliseconds) throws SQLException, ClassNotFoundException {
System.getenv("VCAP_SERVICES");
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection(database, user, password);
Statement stmt = connect.createStatement();
String query = "SELECT COUNT(Ticket_ID) FROM ticket WHERE Requestor = "+userID+" AND Status = 'Approved' AND Status_Date_Fields > "+milliseconds+";";
ResultSet results = stmt.executeQuery(query);
results.next();
Ticket[] tickets = new Ticket[results.getInt("COUNT(Ticket_ID)")];
query= "SELECT * FROM ticket WHERE Requestor = "+userID+" AND Status = 'Approved' AND Status_Date_Fields > "+milliseconds+";";
int i=0;
while(results.next())
{
tickets[i]=new Ticket( results.getInt("Ticket_ID"),
results.getInt("Requestor"),
results.getLong("Request_Date"),
results.getInt("Location"),
results.getInt("Device_ID"),
results.getString("Status"),
results.getLong("Status_Date_Fields"),
results.getString("ReturnDate"));
i++;
}
return null;
}
public static int getUserID(int ticketID) throws ClassNotFoundException, SQLException{
System.getenv("VCAP_SERVICES");
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection(database, user, password);
Statement stmt = connect.createStatement();
String query = "SELECT Requestor FROM ticket WHERE Ticket_ID = "+ticketID+";";
ResultSet results = stmt.executeQuery(query);
results.next();
return results.getInt("Requestor");
}
}

20 changes: 14 additions & 6 deletions src/entities/Ticket.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@
public class Ticket {
private int _id;
private int _requestor;
//private BigInteger _requestDate;
private long _requestDate;
private int _location;
private int _deviceId;
private String _status;
private long _statusDateFields;
private String _returnDate;

public Ticket(int id, int requestor, int location, int deviceId, String status, String returnDate){
public Ticket(int id, int requestor, long requestDate, int location, int deviceId, String status, long statusDateFields, String returnDate){
this._id = id;
this._requestor = requestor;
//this._requestDate = requestDate;
this._requestDate = requestDate;
this._location = location;
this._deviceId = deviceId;
this._status = status;
this._statusDateFields=statusDateFields;
this._returnDate = returnDate;
}

Expand Down Expand Up @@ -62,12 +64,12 @@ public void setRequestor(int requestor){
this._requestor = requestor;
}

/*public BigInteger getRequestDate(){
public long getRequestDate(){
return _requestDate;
}
public void setRequestDate(BigInteger requestDate){
public void setRequestDate(long requestDate){
this._requestDate = requestDate;
}*/
}

public int getLocation(){
return _location;
Expand Down Expand Up @@ -96,4 +98,10 @@ public String getReturnDate(){
public void setReturnDate(String returnDate){
this._returnDate = returnDate;
}
public void setStatusDatefields(long milliseconds){
_statusDateFields=milliseconds;
}
public long getStatusDatefields(){
return _statusDateFields;
}
}
61 changes: 61 additions & 0 deletions src/utilities/NotificationQueue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package utilities;
import java.util.Set;

import entities.User;


public class NotificationQueue extends Thread{
// The purpose of this class is to help reduce notification spam.
// Instead of firing off emails immediately, spawn a thread in this class which
// waits patiently for a few minutes and then collects all relevent activity that happened
// after the event that created it. Then send a single email summerizing it all.
// Right now I'm using it when admins approve tickets. It may be usefull for notifications to admins as well.
private String instructions="";
// this determines what information the notification queue will collect when it is finished waiting.
// >'ticketConfirmations' will cause it to query approved tickets since initialization associated with 'employee'
private User employee;
public NotificationQueue(User employee, String initialize){
instructions=initialize;
this.employee=employee;
}
public void run(){
try {
String threadName = instructions+employee.getID();
// We don't want this to do anything if there is already a thread waiting to send a summary email
// That would defeat the purpose of this class
// So first we check active threads for one that matches threadName; which would be another thread that is
// both assigned to the user in question, and monitoring the same activity.
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
boolean match = false;
for (int i=0; i<threadArray.length; i++) {
if(threadArray[i].getName().equals(threadName)) match=true;
}
if(match){
return; //should kill thread
}
else{
// If there's not yet a queue of the type in question then go ahead and declare this thread as that type,
// so similar notification activity in the future doesn't make a redundant thread.
// Note: I know this is far from a proper mutex, but the only 'race condition' occurs when multiple people click a button
// at the same time so I'm not too worried. Worst case someone gets 2 emails.
Thread.currentThread().setName(threadName);
// Finally do the thing we came for
switch(instructions){
case "ticketConfirmations":
startTicketConfirmQueue(employee);
break;
default:
System.out.println("NotificationQueue: Did not recognize instruction string");
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void startTicketConfirmQueue(User employee) throws InterruptedException{
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName()+" will send summary email now");
}
}

0 comments on commit b473947

Please sign in to comment.