Closed SverreNystad closed 5 months ago
It seems like we now have added all needed dependencies for FireBase (Android Studio did not add all required dependencies). Now we need to write and read values from the real-time database.
I worked on the firebase and I realized that the DAO interface might not be the best for performance due to the nature of confirming if the actions FireBase.update(K id, T object)
and FireBase.delete(K id)
was successful. ChatGPT game this example on how to implement the remaining class but it is blocking actions, and as this is needed to be fast it might be problematic:
package com.softwarearchitecture.networking.persistence;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class FirebaseDAO<K, T> extends DAO<K, T> {
private FirebaseDatabase database;
private String databasePath = "your_collection"; // Define your database path here
public FirebaseDAO(boolean create, boolean read, boolean update, boolean delete) {
this.create = create;
this.read = read;
this.update = update;
this.delete = delete;
String DatabaseName = "https://besieged-8b842-default-rtdb.europe-west1.firebasedatabase.app/";
database = FirebaseDatabase.getInstance(DatabaseName);
}
@Override
public List<T> loadAll() {
CompletableFuture<List<T>> future = new CompletableFuture<>();
DatabaseReference ref = database.getReference(databasePath);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<T> result = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
T element = snapshot.getValue(T.class);
result.add(element);
}
future.complete(result);
}
@Override
public void onCancelled(DatabaseError databaseError) {
future.completeExceptionally(new Exception(databaseError.getMessage()));
}
});
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
@Override
public Optional<T> get(K id) {
CompletableFuture<Optional<T>> future = new CompletableFuture<>();
DatabaseReference ref = database.getReference(databasePath).child(id.toString());
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
T object = dataSnapshot.getValue(T.class);
future.complete(Optional.ofNullable(object));
}
@Override
public void onCancelled(DatabaseError databaseError) {
future.completeExceptionally(new Exception(databaseError.getMessage()));
}
});
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
@Override
public boolean update(K id, T object) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
DatabaseReference ref = database.getReference(databasePath).child(id.toString());
ref.setValue(object, (databaseError, databaseReference) -> {
if (databaseError != null) {
future.completeExceptionally(new Exception(databaseError.getMessage()));
} else {
future.complete(true);
}
});
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
@Override
public boolean delete(K id) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
DatabaseReference ref = database.getReference(databasePath).child(id.toString());
ref.removeValue((databaseError, databaseReference) -> {
if (databaseError != null) {
future.completeExceptionally(new Exception(databaseError.getMessage()));
} else {
future.complete(true);
}
});
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
@Override
public K add(T object) {
DatabaseReference ref = database.getReference(databasePath);
String key = ref.push().getKey();
CompletableFuture<K> future = new CompletableFuture<>();
ref.child(key).setValue(object, (databaseError, databaseReference) -> {
if (databaseError != null) {
future.completeExceptionally(new Exception(databaseError.getMessage()));
} else {
future.complete((K) key);
}
});
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
Either we need to change the interface to make it not promise to confirm if the value actually was updated or deleted or the class must lie. I lean towards changing the interface.
Firbase has an offline persistent mechnism in the case of loss of connecting making it so that we do not need a LocalDAO
The persistence submodule is a crucial component of our project, responsible for managing data access and manipulation across different storage solutions. This issue aims to outline the development and testing requirements for the persistence submodule, including the implementation of the DAO interface, DAOBuilder, and specific DAO implementations (LocalDAO, FirebaseDAO, MockDAO). Comprehensive tests are required to ensure reliability, functionality, and integration with Firebase and local storage solutions.
Acceptance Criteria: