package envoy.client; import java.util.HashMap; import java.util.Map; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import envoy.exception.EnvoyException; import envoy.schema.ObjectFactory; import envoy.schema.Sync; import envoy.schema.User; /** * Project: envoy-client
* File: Client.java
* Created: 28 Sep 2019
* * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister * @since Envoy v0.1-alpha */ public class Client { private ObjectFactory objectFactory = new ObjectFactory(); private Config config; private User sender, recipient; private boolean online = false; /** * Initializes the client. At this state, the client user has yet to be * initialized, which can be done by calling {@link Client#onlineInit(String)}. * * @param config The {@link Config} instance to use in this client * @since Envoy v0.2-alpha */ public Client(Config config) { this.config = config; } /** * Enters the online mode by acquiring a user ID from the server. * * @param userName the name of the client user * @throws EnvoyException if the online mode could not be entered or the request * failed for some other reason * @since Envoy v0.2-alpha */ public void onlineInit(String userName) throws EnvoyException { sender = getUser(userName); online = true; } private R post(String uri, T body, Class responseBodyClass) { javax.ws.rs.client.Client client = ClientBuilder.newClient(); WebTarget target = client.target(uri); Response response = target.request().post(Entity.entity(body, "application/xml")); R responseBody = response.readEntity(responseBodyClass); response.close(); client.close(); return responseBody; } /** * @return a {@code Map} of all users on the server with their * user names as keys * @since Envoy v0.2-alpha */ public Map getUsers() { Sync sendSync = objectFactory.createSync(); User user = objectFactory.createUser(); user.setID(-1); sendSync.getUsers().add(user); Sync returnSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), sendSync, Sync.class); Map users = new HashMap<>(); returnSync.getUsers().forEach(u -> users.put(u.getName(), u)); return users; } /** * Returns a {@link User} with a specific id by name. * * @param name - the name of the {@link User} * @return a {@link User} with the specified name * @throws EnvoyException if the server does not return the requested ID * @since Envoy v0.1-alpha */ private User getUser(String name) throws EnvoyException { // Create a sync with only a user with the requested name Sync senderSync = objectFactory.createSync(); User user = objectFactory.createUser(); user.setName(name); senderSync.getUsers().add(user); try { Sync sync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), senderSync, Sync.class); // Expecting a single user with an ID if (sync.getUsers().size() == 1) { online = true; return sync.getUsers().get(0); } else throw new EnvoyException("Unexpected response from Envoy Server"); } catch (Exception e) { throw new EnvoyException("Could not connect to server", e); } } /** * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync * Object as response.
* It is also used to get the own sender at the start of the client * (Client sends "sync" Sync Object with single user in it(name: the name * entered at login, id: 0, UserStatus:null))
* and to get a complete list of all users saved on the server. * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: * -1, UserStatus:null))
* This method also processes the response Sync Object.
* It sorts its users and messages by specific variables and does certain things * with them.
*
* Messages:
* -State SENT: Update Local message(s) with State WAITING (add Message ID and * change State to SENT). (server sends these informations to the client if * message(s) with State WAITING were successfully sent to the server)
* -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the * server in the latest sync to the "unreadMessagesSync" Sync Object.
* -State RECEIVED, SenderID == 0: Update message(s) in localDB to state * RECEIVED. * (server sends these informations to the client if the other client received * the message(s).)
* -State READ: Update message(s) in the LocalDB to state READ. (server sends * these informations to the client if the other client read * the message(s).)
*
* Users:
* Updating UserStatus of all users in LocalDB. (Server sends all users with * their updated UserStatus to the client.)
* * @param userId the id of the {@link Client} who sends the {@link Sync} * @param sync the sync object (yet to be converted from java class to * sync.xml) * @return a returnSync.xml file * @throws EnvoyException if the client is not in online mode * @since Envoy v0.1-alpha */ public Sync sendSync(long userId, Sync sync) throws EnvoyException { if(!isOnline()) throw new EnvoyException("Client is not in online mode"); // Print sync XML to console JAXBContext jc; try { jc = JAXBContext.newInstance("envoy.schema"); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.marshal(sync, System.out); } catch (JAXBException e) { e.printStackTrace(); } // Send sync return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class); } /** * @return the sender object that represents this client. * @since Envoy v0.1-alpha */ public User getSender() { return sender; } /** * Sets the client user which is used to send messages. * * @param sender the client user to set * @since Envoy v0.2-alpha */ public void setSender(User sender) { this.sender = sender; } /** * @return the current recipient of the current chat. * @since Envoy v0.1-alpha */ public User getRecipient() { return recipient; } /** * Sets the recipient. * * @param recipient the recipient to set * @since Envoy v0.1-alpha */ public void setRecipient(User recipient) { this.recipient = recipient; } /** * @return true, if a recipient is selected * @since Envoy v0.1-alpha */ public boolean hasRecipient() { return recipient != null; } /** * @return {@code true} if a connection to the server could be established * @since Envoy v0.2-alpha */ public boolean isOnline() { return online; } }