Skip to content

Commit

Permalink
Merge pull request #58 from SorinPopteanu/add-factories
Browse files Browse the repository at this point in the history
Add factories
  • Loading branch information
SorinPopteanu authored Apr 26, 2024
2 parents 60f6eb4 + 43329c3 commit 29605ba
Show file tree
Hide file tree
Showing 76 changed files with 1,764 additions and 1,329 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
<version>9.0.10</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.chainoptim.desktop.core.user.service.AuthenticationService;
import org.chainoptim.desktop.core.user.service.UserService;
import org.chainoptim.desktop.core.user.util.TokenManager;
import org.chainoptim.desktop.shared.httphandling.Result;

import java.net.URI;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -77,36 +78,34 @@ public void initialize() {
private void fetchAndSetUser(String username) {
userService.getUserByUsername(username)
.thenApply(this::handleUserResponse)
.exceptionally(ex -> Optional.empty());
.exceptionally(ex -> new Result<>());
}

private Optional<User> handleUserResponse(Optional<User> userOptional) {
private Result<User> handleUserResponse(Result<User> result) {
Platform.runLater(() -> {
System.out.println("User loaded: " + userOptional);
if (userOptional.isEmpty()) {
if (result.getError() != null) {
return;
}

User user = userOptional.get();
User user = result.getData();

user.getOrganization().setSubscriptionPlanTier(PRO);
System.out.println("Subscription plan: " + user.getOrganization().getSubscriptionPlanTier().toString());

// Set user to TenantContext for reuse throughout the app
TenantContext.setCurrentUser(user);

// Fetch user settings and set them to TenantSettingsContext
userSettingsService.getUserSettings(user.getId())
.thenAccept(userSettingsOptional -> {
if (userSettingsOptional.isEmpty()) return;
TenantSettingsContext.setCurrentUserSettings(userSettingsOptional.get());
.thenAccept(result1 -> {
if (result1.getError() != null) return;
TenantSettingsContext.setCurrentUserSettings(result1.getData());
});

// Start WebSocket connection
startWebSocket(user);
});

return userOptional;
return result;
}

private void startWebSocket(User user) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public NavigationServiceImpl(FXMLLoaderService fxmlLoaderService,
Map.entry("Overview", "/org/chainoptim/desktop/core/overview/OverviewView.fxml"),

Map.entry("Organization", "/org/chainoptim/desktop/core/organization/OrganizationView.fxml"),
Map.entry("Update-Organization", "/org/chainoptim/desktop/core/organization/UpdateOrganizationView.fxml"),
Map.entry("Add-New-Members", "/org/chainoptim/desktop/core/organization/AddNewMembersView.fxml"),

Map.entry("Products", "/org/chainoptim/desktop/features/product/ProductsView.fxml"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.chainoptim.desktop.core.notification.service;

import org.chainoptim.desktop.core.notification.model.NotificationUser;
import org.chainoptim.desktop.shared.httphandling.Result;
import org.chainoptim.desktop.shared.search.model.PaginatedResults;
import org.chainoptim.desktop.shared.search.model.SearchParams;

Expand All @@ -10,7 +11,7 @@

public interface NotificationPersistenceService {

CompletableFuture<Optional<List<NotificationUser>>> getNotificationsByUserId(String userId);
CompletableFuture<Result<List<NotificationUser>>> getNotificationsByUserId(String userId);

CompletableFuture<Optional<PaginatedResults<NotificationUser>>> getNotificationsByUserIdAdvanced(String userId, SearchParams searchParams);
CompletableFuture<Result<PaginatedResults<NotificationUser>>> getNotificationsByUserIdAdvanced(String userId, SearchParams searchParams);
}
Original file line number Diff line number Diff line change
@@ -1,100 +1,66 @@
package org.chainoptim.desktop.core.notification.service;

import org.chainoptim.desktop.core.notification.model.Notification;
import org.chainoptim.desktop.core.notification.model.NotificationUser;
import org.chainoptim.desktop.core.user.util.TokenManager;
import org.chainoptim.desktop.features.factory.dto.FactoriesSearchDTO;
import org.chainoptim.desktop.features.supplier.model.Supplier;
import org.chainoptim.desktop.core.user.service.TokenManager;
import org.chainoptim.desktop.shared.caching.CacheKeyBuilder;
import org.chainoptim.desktop.shared.caching.CachingService;
import org.chainoptim.desktop.shared.httphandling.RequestBuilder;
import org.chainoptim.desktop.shared.httphandling.RequestHandler;
import org.chainoptim.desktop.shared.httphandling.Result;
import org.chainoptim.desktop.shared.search.model.PaginatedResults;
import org.chainoptim.desktop.shared.search.model.SearchParams;
import org.chainoptim.desktop.shared.util.JsonUtil;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.inject.Inject;

import java.net.HttpURLConnection;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

public class NotificationPersistenceServiceImpl implements NotificationPersistenceService {

private final CachingService<PaginatedResults<NotificationUser>> cachingService;
private final HttpClient client = HttpClient.newHttpClient();
private final RequestHandler requestHandler;
private final RequestBuilder requestBuilder;
private final TokenManager tokenManager;

private static final String HEADER_KEY = "Authorization";
private static final String HEADER_VALUE_PREFIX = "Bearer ";
private static final int STALE_TIME = 300;

@Inject
public NotificationPersistenceServiceImpl(CachingService<PaginatedResults<NotificationUser>> cachingService) {
public NotificationPersistenceServiceImpl(
CachingService<PaginatedResults<NotificationUser>> cachingService,
RequestHandler requestHandler,
RequestBuilder requestBuilder,
TokenManager tokenManager) {
this.cachingService = cachingService;
this.requestHandler = requestHandler;
this.requestBuilder = requestBuilder;
this.tokenManager = tokenManager;
}

public CompletableFuture<Optional<List<NotificationUser>>> getNotificationsByUserId(String userId) {
public CompletableFuture<Result<List<NotificationUser>>> getNotificationsByUserId(String userId) {
String routeAddress = "http://localhost:8080/api/v1/notifications/user/" + userId;

String jwtToken = TokenManager.getToken();
if (jwtToken == null) return new CompletableFuture<>();
String headerValue = HEADER_VALUE_PREFIX + jwtToken;

HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(routeAddress))
.GET()
.headers(HEADER_KEY, headerValue)
.build();
HttpRequest request = requestBuilder.buildReadRequest(routeAddress, tokenManager.getToken());

return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> {
if (response.statusCode() != HttpURLConnection.HTTP_OK) return Optional.<List<NotificationUser>>empty();
try {
List<NotificationUser> notifications = JsonUtil.getObjectMapper().readValue(response.body(), new TypeReference<List<NotificationUser>>() {});
return Optional.of(notifications);
} catch (Exception e) {
e.printStackTrace();
return Optional.<List<NotificationUser>>empty();
}
});
return requestHandler.sendRequest(request, new TypeReference<List<NotificationUser>>() {});
}

public CompletableFuture<Optional<PaginatedResults<NotificationUser>>> getNotificationsByUserIdAdvanced(String userId, SearchParams searchParams) {
public CompletableFuture<Result<PaginatedResults<NotificationUser>>> getNotificationsByUserIdAdvanced(String userId, SearchParams searchParams) {
String rootAddress = "http://localhost:8080/api/v1/";
String cacheKey = CacheKeyBuilder.buildAdvancedSearchKey("notifications", "user", userId, searchParams);
String routeAddress = rootAddress + cacheKey;

String jwtToken = TokenManager.getToken();
if (jwtToken == null) return new CompletableFuture<>();
String headerValue = HEADER_VALUE_PREFIX + jwtToken;

HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(routeAddress))
.GET()
.headers(HEADER_KEY, headerValue)
.build();
HttpRequest request = requestBuilder.buildReadRequest(routeAddress, tokenManager.getToken());

if (cachingService.isCached(cacheKey) && !cachingService.isStale(cacheKey)) {
return CompletableFuture.completedFuture(Optional.of(cachingService.get(cacheKey)));
return CompletableFuture.completedFuture(new Result<>(cachingService.get(cacheKey), null, HttpURLConnection.HTTP_OK));
}

return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> {
if (response.statusCode() != HttpURLConnection.HTTP_OK) return Optional.<PaginatedResults<NotificationUser>>empty();
try {
PaginatedResults<NotificationUser> notifications = JsonUtil.getObjectMapper().readValue(response.body(), new TypeReference<PaginatedResults<NotificationUser>>() {});

cachingService.remove(cacheKey); // Ensure there isn't a stale cache entry
cachingService.add(cacheKey, notifications, STALE_TIME);

return Optional.of(notifications);
} catch (Exception e) {
e.printStackTrace();
return Optional.<PaginatedResults<NotificationUser>>empty();
}
});
return requestHandler.sendRequest(request, new TypeReference<PaginatedResults<NotificationUser>>() {}, notifications -> {
cachingService.remove(cacheKey); // Ensure there isn't a stale cache entry
cachingService.add(cacheKey, notifications, STALE_TIME);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import org.chainoptim.desktop.core.abstraction.ControllerFactory;
import org.chainoptim.desktop.core.context.TenantContext;
import org.chainoptim.desktop.core.main.service.NavigationService;
import org.chainoptim.desktop.core.organization.model.CustomRole;
import org.chainoptim.desktop.core.organization.model.Organization;
import org.chainoptim.desktop.core.organization.model.OrganizationViewData;
import org.chainoptim.desktop.core.organization.service.CustomRoleService;
import org.chainoptim.desktop.core.organization.service.OrganizationService;
import org.chainoptim.desktop.core.user.model.User;
import org.chainoptim.desktop.shared.fallback.FallbackManager;
import org.chainoptim.desktop.shared.httphandling.Result;
import org.chainoptim.desktop.shared.util.DataReceiver;
import org.chainoptim.desktop.shared.util.resourceloader.CommonViewsLoader;
import org.chainoptim.desktop.shared.util.resourceloader.FXMLLoaderService;

import com.google.inject.Inject;
Expand All @@ -35,7 +38,8 @@ public class OrganizationController implements Initializable {
// Services
private final OrganizationService organizationService;
private final CustomRoleService customRoleService;
private final FXMLLoaderService fxmlLoaderService;
private final NavigationService navigationService;
private final CommonViewsLoader commonViewsLoader;
private final ControllerFactory controllerFactory;

private final FallbackManager fallbackManager;
Expand Down Expand Up @@ -68,21 +72,24 @@ public class OrganizationController implements Initializable {

@Inject
public OrganizationController(OrganizationService organizationService,
CustomRoleService customRoleService,
FXMLLoaderService fxmlLoaderService,
CustomRoleService customRoleService,
NavigationService navigationService,
CommonViewsLoader commonViewsLoader,
ControllerFactory controllerFactory,
FallbackManager fallbackManager) {
this.organizationService = organizationService;
this.customRoleService = customRoleService;
this.fxmlLoaderService = fxmlLoaderService;
this.navigationService = navigationService;
this.commonViewsLoader = commonViewsLoader;
this.controllerFactory = controllerFactory;
this.fallbackManager = fallbackManager;
}

@Override
public void initialize(URL location, ResourceBundle resourceBundle) {
loadFallbackManager();
commonViewsLoader.loadFallbackManager(fallbackContainer);
setupListeners();

User currentUser = TenantContext.getCurrentUser();
if (currentUser == null) {
Platform.runLater(() -> fallbackManager.setLoading(false));
Expand All @@ -101,15 +108,6 @@ public void initialize(URL location, ResourceBundle resourceBundle) {
loadCustomRoles(); // Multi-thread this as custom roles are not immediately needed
}

private void loadFallbackManager() {
// Load view into fallbackContainer
Node fallbackView = fxmlLoaderService.loadView(
"/org/chainoptim/desktop/shared/fallback/FallbackManagerView.fxml",
controllerFactory::createController
);
fallbackContainer.getChildren().add(fallbackView);
}

private void setupListeners() {
overviewTab.selectedProperty().addListener((observable, wasSelected, isNowSelected) -> {
if (Boolean.TRUE.equals(isNowSelected) && overviewTab.getContent() == null) {
Expand Down Expand Up @@ -160,18 +158,16 @@ private void loadOrganization() {
.exceptionally(this::handleOrganizationException);
}

private Optional<Organization> handleOrganizationResponse(Optional<Organization> organizationOptional) {
private Result<Organization> handleOrganizationResponse(Result<Organization> result) {
Platform.runLater(() -> {
if (organizationOptional.isEmpty()) {
if (result.getError() != null) {
fallbackManager.setErrorMessage("Failed to load organization.");
return;
}
organizationViewData.setOrganization(organizationOptional.get());
organizationViewData.setOrganization(result.getData());

organizationViewData.getOrganization().setSubscriptionPlanTier(PRO);

System.out.println("Organization: " + organizationViewData.getOrganization());

initializeUI();

organizationOverviewController.setData(organizationViewData); // Feed organization data to overview tab
Expand All @@ -181,7 +177,7 @@ private Optional<Organization> handleOrganizationResponse(Optional<Organization>
fallbackManager.setLoading(false);
});

return organizationOptional;
return result;
}

private void loadCustomRoles() {
Expand All @@ -191,24 +187,24 @@ private void loadCustomRoles() {
.thenRun(() -> Platform.runLater(() -> fallbackManager.setLoading(false)));
}

private Optional<List<CustomRole>> handleCustomRolesResponse(Optional<List<CustomRole>> customRolesOptional) {
private Result<List<CustomRole>> handleCustomRolesResponse(Result<List<CustomRole>> result) {
Platform.runLater(() -> {
if (customRolesOptional.isEmpty()) {
if (result.getError() != null) {
fallbackManager.setErrorMessage("Failed to load custom roles.");
return;
}
organizationViewData.setCustomRoles(customRolesOptional.get());
organizationViewData.setCustomRoles(result.getData());
if (organizationOverviewController != null) {
organizationOverviewController.setData(organizationViewData);
}
System.out.println("Custom Roles: " + organizationViewData.getCustomRoles());
});
return customRolesOptional;
return result;
}

private Optional<List<CustomRole>> handleCustomRolesException(Throwable ex) {
private Result<List<CustomRole>> handleCustomRolesException(Throwable ex) {
Platform.runLater(() -> fallbackManager.setErrorMessage("Failed to load custom roles."));
return Optional.empty();
return new Result<>();
}

private void initializeUI() {
Expand All @@ -217,13 +213,13 @@ private void initializeUI() {
planLabel.setText("Subscription Plan: " + organizationViewData.getOrganization().getSubscriptionPlanTier().toString());
}

private Optional<Organization> handleOrganizationException(Throwable ex) {
private Result<Organization> handleOrganizationException(Throwable ex) {
Platform.runLater(() -> fallbackManager.setErrorMessage("Failed to load organization."));
return Optional.empty();
return new Result<>();
}

@FXML
private void handleEditOrganization() {
System.out.println("Edit organization clicked");
navigationService.switchView("Update-Organization", true);
}
}
Loading

0 comments on commit 29605ba

Please sign in to comment.