Skip to content

Commit

Permalink
Implemented notifications and ionic-app for notification viewing
Browse files Browse the repository at this point in the history
  • Loading branch information
IMS94 committed Oct 27, 2018
1 parent 1b8004b commit 9238217
Show file tree
Hide file tree
Showing 99 changed files with 11,038 additions and 2,337 deletions.
25 changes: 25 additions & 0 deletions cramp-api/src/main/java/org/eduze/fyp/api/Condition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* <Paste your header here>
*/
package org.eduze.fyp.api;

import org.eduze.fyp.api.model.CameraGroup;
import org.eduze.fyp.api.resources.Notification;
import org.eduze.fyp.api.resources.PersonSnapshot;

import java.util.List;

/**
* Represents a condition to be evaluated/checked for generating notifications.
*
* @author Imesha Sudasingha
*/
public interface Condition {

/**
* Evaluates a given logic and determines whether any notification requires to be sent
*
* @return list of notifications to be sent | not null
*/
List<Notification> evaluate(CameraGroup cameraGroup, List<List<PersonSnapshot>> snapshots);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* <Paste your header here>
*/
package org.eduze.fyp.api.resources;

public class Notification {

private String title;
private String message;
private long timestamp;

public Notification() {
}

public Notification(String title, String message, long timestamp) {
this.title = title;
this.message = message;
this.timestamp = timestamp;
}

public Notification(String message) {
this.message = message;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public long getTimestamp() {
return timestamp;
}

public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}
6 changes: 6 additions & 0 deletions cramp-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@
<!--<artifactId>libtensorflow_jni_gpu</artifactId>-->
<!--</dependency>-->

<!-- Firebase -->
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* <Paste your header here>
*/
package org.eduze.fyp.core;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import org.eduze.fyp.api.Condition;
import org.eduze.fyp.api.annotations.AutoStart;
import org.eduze.fyp.api.annotations.Mode;
import org.eduze.fyp.api.config.Startable;
import org.eduze.fyp.api.listeners.ProcessedMapListener;
import org.eduze.fyp.api.model.CameraGroup;
import org.eduze.fyp.api.resources.Notification;
import org.eduze.fyp.api.resources.PersonSnapshot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@AutoStart(mode = Mode.ACTIVE)
public class NotificationProcessor implements ProcessedMapListener, Startable {

private static final Logger logger = LoggerFactory.getLogger(NotificationProcessor.class);

private static final String DATABASE_URL = "https://augur-bia.firebaseio.com/";

private ExecutorService executor;
private List<Condition> conditions;
private DatabaseReference databaseReference;

@Override
public void start() {
executor = Executors.newSingleThreadExecutor();

// Initialize Firebase
try {
// [START initialize]
FileInputStream serviceAccount = new FileInputStream("src/main/resources/etc/service-account.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl(DATABASE_URL)
.build();
FirebaseApp.initializeApp(options);
// [END initialize]
} catch (IOException e) {
logger.error("Unable to create firebase app", e);
}

// Shared Database reference
databaseReference = FirebaseDatabase.getInstance().getReference();

logger.info("Notification processor started successfully");
}

@Override
public void mapProcessed(CameraGroup cameraGroup, List<List<PersonSnapshot>> snapshots) {
executor.submit(() -> process(cameraGroup, snapshots));
}

private void process(CameraGroup cameraGroup, List<List<PersonSnapshot>> snapshots) {
List<Notification> notifications = conditions.stream()
.map(condition -> condition.evaluate(cameraGroup, snapshots))
.reduce(new ArrayList<>(), (l1, l2) -> {
l1.addAll(l2);
return l1;
});

notifications.forEach(notification -> {
logger.debug("Sending notification: {}", notification);
databaseReference.child("notifications").push()
.setValueAsync(notification);
});
}

@Override
public void stop() {
executor.shutdownNow();
logger.info("Notification processor stopped");
}

public List<Condition> getConditions() {
return conditions;
}

public void setConditions(List<Condition> conditions) {
this.conditions = conditions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* <Paste your header here>
*/
package org.eduze.fyp.core.conditions;

import org.eduze.fyp.api.Condition;
import org.eduze.fyp.api.model.CameraGroup;
import org.eduze.fyp.api.model.Zone;
import org.eduze.fyp.api.resources.Notification;
import org.eduze.fyp.api.resources.PersonSnapshot;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* A Condition to check whether the zones have have exceeding number of people in it
*
* @author Imesha Sudasingha
*/
public class ZoneLimitCondition implements Condition {

@Override
public List<Notification> evaluate(CameraGroup cameraGroup, List<List<PersonSnapshot>> snapshots) {
Map<Zone, List<List<PersonSnapshot>>> byZone = new HashMap<>();

Map<Integer, Zone> zones = new HashMap<>();
cameraGroup.getZones().forEach(zone -> zones.put(zone.getId(), zone));

snapshots.forEach(snapshotList -> {
if (snapshotList.size() > 0 && snapshotList.get(0).getInstanceZone() != null) {
Zone z = snapshotList.get(0).getInstanceZone();
byZone.computeIfAbsent(zones.get(z.getId()), key -> new ArrayList<>())
.add(snapshotList);
}
});

List<Notification> notifications = new ArrayList<>();
byZone.forEach((zone, snapshotLists) -> {
if (zone.getZoneLimit() < snapshotLists.size()) {
String title = String.format("'%s' is overcrowded", zone.getZoneName());
String message = String.format("Zone '%s' has %d people in it", zone.getZoneName(), snapshotLists.size());
long timestamp = snapshotLists.get(0).get(0).getTimestamp();
Notification notification = new Notification(title, message, timestamp);
notifications.add(notification);
}
});

return notifications;
}
}
12 changes: 12 additions & 0 deletions cramp-ui/src/main/resources/etc/service-account.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "service_account",
"project_id": "augur-bia",
"private_key_id": "010635ad344e4576f7edd194b4cdcbdc8d4d2a6f",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDx4DdJ3D+sG942\nuxXbwR/KoVkzU1aEnDQCL4H18XViau/tPKSGRdTIq7O8Se20Cpi5dgbTbpowB7/C\nlxnPUDTf2oMBEV1lSRlnoTKvoNjDyE1FQtV/nImHD9vK7ZZbymFfmzB0erxwDnXd\nq7ZZETalY95TIG9X627ehr3E5yW57KG66BGRtoRilZcGuITZIsKyMp7I/5r1JodN\n5O5xZiXwVI8ZPaVxQUDj1dvhIrimDJbS28dCOY7RY9d9y20CeQUwrbyll/h4ZZuu\nifgfEzHiicI1VgSKISTHLPmRyI0Bxs0ta97Modqnf7KOi2ygeYKOAncRwQPwXp0S\ngOyT0rKZAgMBAAECggEAUwfuwt6mRu1MI4qmrskFolgwGFPv+9bpbaSkXurUKoRe\nN5jdO7DGIlr6+NSCEo+erO/M2RD7Qiiu1dxsAkRc2kmXNishXg8xducZ0LuNHexp\nRjDyvHtepKw3fdqAhqMbOSg7gojNnkQAhyeWkc28bhsx62RThKFv7ljf1TOqOj/L\nwQLNYOTNDDIGK6REqdsYIgEzTAoccNhL1YU4iiJbxs1NJAen26Zh/4gp8zDrrAwA\njLs6e1Es/fPATdFo7rMk0WRGULIbpw7ErteovuCqgbcopmcFFI9Iz0EL+GRFBu7T\n5ZFqAdbGGpjPTO1+0oBKN7cSr7myFPmHVAreZjVEjwKBgQD/OFsVPlyWH5A5gdsE\nHRzyPGfEWpn5mY+5sCxddsdNEKmUjCP/Bmls/Sn6y9Wi51HpHyP7KSuQ6Ac8tGDm\nKMUBrTZA66m8Ha0S2K2KXpreYbpRTAsjCAQWMmlWLGf0ha3zi3ChGR+LkLapqOng\nVuoipNEdZCvLHpRrTE5MaR+89wKBgQDynWv0G5G2IQfr4tEnM+dXYtBlqCKi7EJv\n2tk6q6yCO1qHj+s4Gv5cdkAUgEVyCnL2BNSOLC/NGBHnbID5idx7q43Vx8Yqi1a0\nxjjsGT6f1z/T5CWxwsmvJ/E/pG/vfgcIUQKi9Glw0WWZpDK8bSnvBmqiLpJFcsMe\ncL6d8m747wKBgGqjKnOC3f6f64wLtO5QF8Mi+Bxz2rgOsJ3efXsD4RxTJPf7YiLx\nk+VFFmBDAN2TF4d3Snpr5lcii7uShpZEXKRpsiyICyCdqa4hOMmC4+SdItNLGbAm\nbka0A41M+paRsG/9SC8XpzWSXrAe8rGYvzWAdht4uk+hVFRMyr5kgi1bAoGAUTHo\nCBkV6dsiGIqfLryLJs62Kd9cQCRLk72tR5pesHMGuCmtMeiuyej1RycqlqDymm1B\naZdWJBBzJX1FqL2/oU/ntu0V3/Uj/nn8YN+N+taB0Psgtl4XO1xlu8PfhkoqNllO\nRZUAmLYrh4DRTghGqWz/UOm/ICjpLg3TbW7OPtcCgYB7d69KfajED5Xf6dJ970fi\nqx3PDH8DCNF+RRDMMX9uDuaixfKanTiz5PQJweTmIB50Bj4rDI2HG7bobuJ4W1Qh\nHkpx0RzNHvD0Rj3zIjZd7rGnswGd7OUbtiGO0RDThjGDKHxt7VMVS8LKQmFCfciw\nuXwwLOmGE8NuT+uaLagycQ==\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "110828200372826322606",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-t6z7g%40augur-bia.iam.gserviceaccount.com"
}
9 changes: 9 additions & 0 deletions cramp-ui/src/main/resources/etc/spring.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<set>
<ref bean="db-handler"/>
<ref bean="analytics-service"/>
<ref bean="notification-processor"/>
</set>
</property>
<property name="zonePersistentScanCount" value="5"/>
Expand All @@ -44,6 +45,14 @@
<property name="mapProcessor" ref="map-processor"/>
</bean>

<bean id="notification-processor" class="org.eduze.fyp.core.NotificationProcessor">
<property name="conditions">
<list>
<bean class="org.eduze.fyp.core.conditions.ZoneLimitCondition"/>
</list>
</property>
</bean>

<!-- ============================================================================ -->
<!-- Database Related Configuration -->
<!-- ============================================================================ -->
Expand Down
71 changes: 71 additions & 0 deletions cramp-ui/src/test/java/org/eduze/fyp/ui/FirebaseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* <Paste your header here>
*/
package org.eduze.fyp.ui;

import com.google.api.core.ApiFuture;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import org.eduze.fyp.api.resources.Notification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Random;

public class FirebaseTest {

private static final Logger logger = LoggerFactory.getLogger(FirebaseTest.class);

private static final String DATABASE_URL = "https://augur-bia.firebaseio.com/";

public static void main(String[] args) throws InterruptedException {
// Initialize Firebase
try {
// [START initialize]
FileInputStream serviceAccount = new FileInputStream("src/main/resources/etc/service-account.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl(DATABASE_URL)
.build();
FirebaseApp.initializeApp(options);
// [END initialize]
} catch (IOException e) {
System.out.println("ERROR: invalid service account credentials. See README.");
System.out.println(e.getMessage());

System.exit(1);
}

// Shared Database reference
DatabaseReference database = FirebaseDatabase.getInstance().getReference();

DatabaseReference notifications = database.child("notifications");

Random random = new Random();
for (int i = 0; i < 100; i++) {
Notification notification = new Notification("Notification " + i,
"Zone " + i + " is crowded", new Date().getTime());

ApiFuture<Void> future = notifications.push()
.setValueAsync(notification);

while (!future.isDone()) {
// logger.debug("{}: Not added yet", notification);
Thread.sleep(1000);
}

logger.debug("Added notification: {}", i);
try {
Thread.sleep(random.nextInt(10000) + 3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
17 changes: 17 additions & 0 deletions ionic-app/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
# editorconfig.org

root = true

[*]
indent_style = space
indent_size = 2

# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
Loading

0 comments on commit 9238217

Please sign in to comment.