diff --git a/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/controller/SimpleMessageHandler.java b/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/controller/SimpleMessageHandler.java index 182100a5..e60176bd 100644 --- a/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/controller/SimpleMessageHandler.java +++ b/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/controller/SimpleMessageHandler.java @@ -8,22 +8,18 @@ import com.pqt.core.entities.product.LightweightProduct; import com.pqt.core.entities.product.Product; import com.pqt.core.entities.product.ProductUpdate; import com.pqt.core.entities.sale.Sale; +import com.pqt.core.entities.server_config.ServerConfig; +import com.pqt.core.entities.user_account.Account; import com.pqt.core.entities.user_account.AccountLevel; import com.pqt.server.exception.ServerQueryException; import com.pqt.server.module.account.AccountService; -import com.pqt.server.module.client.ClientService; import com.pqt.server.module.sale.SaleService; import com.pqt.server.module.state.ServerStateService; import com.pqt.server.module.statistics.StatisticsService; import com.pqt.server.module.stock.StockService; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; -//TODO ajouter des messages d'erreur spécifiques pour les NullPointerException si le param du message vaut null -//TODO mettre à jour la liste des query supportées lorsque la version du serveur sera proche de la release -//TODO ne pas oublier de préciser le niveau de permission requis pour chaque requête //TODO Paramétrer les supports de query et leurs permissions via un meilleur système (config file, etc ...) /** * Implémentation de l'interface {@link IMessageHandler}. Cette classe définit le gestionnaire de message par défaut du @@ -31,12 +27,20 @@ import java.util.Map; *

* Liste des requêtes supportées :
*

*

* Liste des requêtes non-supportées :
*

* @see IMessageHandler * @version 1.0 @@ -72,24 +76,26 @@ public class SimpleMessageHandler implements IMessageHandler { manager = new MessageManager(); - //TODO ajouter support des query de connexion de compte utilisateur - manager.support(MessageType.QUERY_STOCK, (message)->{ + /* + WAITER-restricted queries + */ + manager.supportForConnectedAccounts(MessageType.QUERY_STOCK, (message)->{ Map fields = new HashMap<>(); fields.put("stock", messageToolFactory.getListFormatter(Product.class).format(stockService.getProductList())); return new Message(MessageType.MSG_STOCK, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); }, AccountLevel.WAITER); - manager.support(MessageType.QUERY_SALE, (message)->{ + manager.supportForConnectedAccounts(MessageType.QUERY_SALE, (message)->{ Map fields = new HashMap<>(); try { long saleId = saleService.submitSale(messageToolFactory.getObjectParser(Sale.class).parse(message.getField("sale"))); fields.put("saleId", Long.toString(saleId)); return new Message(MessageType.ACK_SALE, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); - }catch(ServerQueryException | NullPointerException e){ + }catch(NullPointerException e){ fields.put(header_ref_query, e.toString()); return new Message(MessageType.REFUSED_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); } }, AccountLevel.WAITER); - manager.support(MessageType.QUERY_STAT, (message)->{ + manager.supportForConnectedAccounts(MessageType.QUERY_STAT, (message)->{ Map fields = new HashMap<>(); fields.put("total_sale_worth", Double.toString(statisticsService.getTotalSaleWorth())); fields.put("total_sale_amount", Integer.toString(statisticsService.getTotalAmountSale())); @@ -102,7 +108,11 @@ public class SimpleMessageHandler implements IMessageHandler { return new Message(MessageType.MSG_STAT, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); }, AccountLevel.WAITER); - manager.support(MessageType.QUERY_UPDATE, (message)->{ + + /* + MASTER-restricted queries + */ + manager.supportForConnectedAccounts(MessageType.QUERY_UPDATE, (message)->{ try{ List updates = messageToolFactory.getListParser(ProductUpdate.class).parse(message.getField("updates")); stockService.applyUpdateList(updates); @@ -113,19 +123,82 @@ public class SimpleMessageHandler implements IMessageHandler { return new Message(MessageType.ERROR_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); } }, AccountLevel.MASTER); - /* - manager.support(MessageType.QUERY_REVERT_SALE, (message)->{ - try{ - saleService.submitSaleRevert(messageToolFactory.getObjectParser(Long.class).parse(message.getField("saleId"))); - return new Message(MessageType.ACK_REVERT_SALE, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, null); - }catch(ServerQueryException | NullPointerException e){ - Map fields = new HashMap<>(); - fields.put(header_err_query, e.toString()); - return new Message(MessageType.ERROR_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); - } - }, AccountLevel.MASTER); + /* + Queries without account connection requirements */ + manager.support(MessageType.QUERY_ACCOUNT_LIST, (message)->{ + Map fields = new HashMap<>(); + fields.put("accounts", messageToolFactory.getListFormatter(Account.class).format(accountService.getAccountList())); + return new Message(MessageType.MSG_ACCOUNT_LIST, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); + }, AccountLevel.getLowest(), false); + manager.support(MessageType.QUERY_CONNECT_ACCOUNT, (message)->{ + final String desiredStateFieldHeader = "desired_state", + accountCredentialsFieldHeader = "account"; + + if(message.getFields().containsKey(desiredStateFieldHeader)){ + if(message.getFields().containsKey(accountCredentialsFieldHeader)){ + boolean desiredState = messageToolFactory.getObjectParser(Boolean.class).parse(message.getField(desiredStateFieldHeader)); + Account accountCredentials = messageToolFactory.getObjectParser(Account.class).parse(message.getField(accountCredentialsFieldHeader)); + + if(accountService.submitAccountCredentials(accountCredentials, desiredState)){ + return new Message(MessageType.ACK_CONNECT_ACCOUNT, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, null); + }else{ + Map fields = new HashMap<>(); + fields.put(header_ref_query, "Impossible d'effectuer l'action : identifiants invalides ou état désiré déjà atteint"); + + return new Message(MessageType.REFUSED_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); + } + }else{ + return getMissingArgumentQueryReplyMessage(message, accountCredentialsFieldHeader); + } + }else{ + return getMissingArgumentQueryReplyMessage(message, desiredStateFieldHeader); + } + }, AccountLevel.getLowest(), false); + manager.support(MessageType.QUERY_PING, (message)->new Message(MessageType.ACK_PING, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, null), AccountLevel.getLowest(), false); + manager.support(MessageType.QUERY_CONFIG_LIST, (message)->{ + Map fields = new HashMap<>(); + fields.put("config", messageToolFactory.getObjectFormatter(ServerConfig.class).format(serverStateService.getConfig())); + return new Message(MessageType.MSG_CONFIG_LIST, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); + }, AccountLevel.getLowest(), false); + } + + private Message getUnsupportedQueryReplyMessage(Message message){ + final String msg_ref_unsupported_query = "Ce type de requêtes n'est actuellement pas supportée par ce serveur."; + Map fields = new HashMap<>(); + fields.put(header_ref_query, msg_ref_unsupported_query); + + return new Message(MessageType.REFUSED_QUERY, + serverStateService.getServer(), + message.getEmitter(), + message.getUser(), + message, + fields); + } + + private Message getMissingArgumentQueryReplyMessage(Message message, String missingArgumentHeader){ + Map fields = new HashMap<>(); + fields.put(header_err_query, "The following required header is missing : "+missingArgumentHeader); + + return new Message(MessageType.ERROR_QUERY, + serverStateService.getServer(), + message.getEmitter(), + message.getUser(), + message, + fields); + } + + private Message getExceptionOccuredQueryReplyMessage(Message message, Exception exception){ + Map fields = new HashMap<>(); + fields.put(header_err_query, exception.getMessage()); + + return new Message(MessageType.ERROR_QUERY, + serverStateService.getServer(), + message.getEmitter(), + message.getUser(), + message, + fields); } @Override @@ -133,20 +206,25 @@ public class SimpleMessageHandler implements IMessageHandler { Map fields = new HashMap<>(); - if(!isAccountRegisteredAndConnected(message)){ - fields.put(header_ref_query, "Compte utilisateur inconnu"); - return new Message(MessageType.REFUSED_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); - } - if(!checkAccountPermission(message)){ - fields.put(header_ref_query, "Compte utilisateur avec permission trop faible"); - return new Message(MessageType.REFUSED_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); - } if(manager.contains(message.getType())){ - return manager.getProcess(message.getType()).execute(message); + if(manager.isQueryRestrictedToConnectedAccount(message.getType())) { + if (!isAccountRegisteredAndConnected(message)) { + fields.put(header_ref_query, "Compte utilisateur inconnu ou déconnecté."); + return new Message(MessageType.REFUSED_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); + } + if (!checkAccountPermission(message)) { + fields.put(header_ref_query, "Compte utilisateur avec permission trop faible"); + return new Message(MessageType.REFUSED_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); + } + } + try{ + return manager.getProcess(message.getType()).execute(message); + }catch(Exception e){ + return getExceptionOccuredQueryReplyMessage(message, e); + } } - fields.put(header_err_query, "Type requête non pris en charge par ce serveur"); - return new Message(MessageType.ERROR_QUERY, serverStateService.getServer(), message.getEmitter(), message.getUser(), message, fields); + return getUnsupportedQueryReplyMessage(message); } /** @@ -156,30 +234,97 @@ public class SimpleMessageHandler implements IMessageHandler { Message execute(Message request); } - private class MessageManager{ - private Map processes; - private Map levels; + private class MessageTypeEntry{ + private MessageType type; + private IMessageProcess process; + private AccountLevel level; + private boolean connectedAccountRestriction; - MessageManager(){ - processes = new HashMap<>(); - levels = new HashMap<>(); + MessageTypeEntry(MessageType type, IMessageProcess process, AccountLevel level, boolean connectedAccountRestriction) { + this.type = type; + this.process = process; + this.level = level; + this.connectedAccountRestriction = connectedAccountRestriction; } - void support(MessageType type, IMessageProcess process, AccountLevel permissionLevel){ - processes.put(type, process); - levels.put(type, permissionLevel); + IMessageProcess getProcess() { + return process; + } + + AccountLevel getLevel() { + return level; + } + + boolean isConnectedAccountRestriction() { + return connectedAccountRestriction; + } + + boolean matches(MessageType type){ + return type.equals(this.type); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MessageTypeEntry that = (MessageTypeEntry) o; + + return connectedAccountRestriction == that.connectedAccountRestriction && type == that.type && process.equals(that.process) && level == that.level; + } + + @Override + public int hashCode() { + int result = type.hashCode(); + result = 31 * result + process.hashCode(); + result = 31 * result + level.hashCode(); + result = 31 * result + (connectedAccountRestriction ? 1 : 0); + return result; + } + } + + private class MessageManager{ + private Set entries; + + MessageManager(){ + entries = new HashSet<>(); + } + + void supportForConnectedAccounts(MessageType type, IMessageProcess process, AccountLevel permissionLevel){ + support(type, process, permissionLevel, true); + } + + void support(MessageType type, IMessageProcess process, AccountLevel permissionLevel, boolean accountConnectionRequired){ + entries.add(new MessageTypeEntry(type, process, permissionLevel, accountConnectionRequired)); + } + + private MessageTypeEntry getFirstMatch(MessageType type){ + return entries.stream().filter(entry->entry.matches(type)).findFirst().orElse(null); } IMessageProcess getProcess(MessageType messageType){ - return processes.get(messageType); + MessageTypeEntry entry = getFirstMatch(messageType); + if(entry!=null) + return entry.getProcess(); + + return null; } AccountLevel getLevel(MessageType messageType){ - return levels.get(messageType); + MessageTypeEntry entry = getFirstMatch(messageType); + if(entry!=null) + return entry.getLevel(); + + return null; } boolean contains(MessageType type) { - return processes.containsKey(type); + return getFirstMatch(type)!=null; + } + + boolean isQueryRestrictedToConnectedAccount(MessageType type) { + MessageTypeEntry entry = getFirstMatch(type); + return entry != null && entry.isConnectedAccountRestriction(); } } diff --git a/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/module/state/ServerStateService.java b/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/module/state/ServerStateService.java index 6a49d4b8..3e32ed93 100644 --- a/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/module/state/ServerStateService.java +++ b/Workspace/server/src/main/WEB-INF/classes/com/pqt/server/module/state/ServerStateService.java @@ -1,6 +1,8 @@ package com.pqt.server.module.state; import com.pqt.core.entities.members.DataServer; +import com.pqt.core.entities.server_config.ConfigFields; +import com.pqt.core.entities.server_config.ServerConfig; import java.util.Date; @@ -16,10 +18,16 @@ public class ServerStateService { private ServerState serverState; private DataServer server; + private ServerConfig config; public ServerStateService() { this.server = new DataServer(); this.serverState = new ServerState(); + this.config = new ServerConfig( + ConfigFields.ALLOW_ACCOUNT_CONNECT, + ConfigFields.ALLOW_SALE_COMMIT, + ConfigFields.ALLOW_STOCK_UPDATE, + ConfigFields.ALLOW_STOCK_VIEW); //TODO config adresse IP //this.com.pqt.server.setAddress(...); @@ -49,4 +57,7 @@ public class ServerStateService { return serverState.copy(); } + public ServerConfig getConfig() { + return config; + } }