Receiving objects from server on separate thread

This commit is contained in:
Kai S. K. Engelbart 2019-12-30 18:18:03 +02:00
parent 61d3d44ee5
commit e66dba8812
4 changed files with 88 additions and 16 deletions

View File

@ -1,7 +1,5 @@
package envoy.client; package envoy.client;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket; import java.net.Socket;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -9,6 +7,7 @@ import java.util.logging.Logger;
import envoy.client.util.EnvoyLog; import envoy.client.util.EnvoyLog;
import envoy.data.LoginCredentials; import envoy.data.LoginCredentials;
import envoy.data.User; import envoy.data.User;
import envoy.exception.EnvoyException;
import envoy.util.SerializationUtils; import envoy.util.SerializationUtils;
/** /**
@ -25,7 +24,8 @@ public class Client {
private Socket socket; private Socket socket;
private Config config = Config.getInstance(); private Config config = Config.getInstance();
private User sender, recipient; private volatile User sender;
private User recipient;
private boolean online; private boolean online;
private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName());
@ -34,11 +34,11 @@ public class Client {
* Enters the online mode by acquiring a user ID from the server. * Enters the online mode by acquiring a user ID from the server.
* *
* @param credentials the login credentials of the user * @param credentials the login credentials of the user
* @throws IOException if the online mode could not be entered or the request * @throws Exception if the online mode could not be entered or the request
* failed for some other reason * failed for some other reason
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void onlineInit(LoginCredentials credentials) throws IOException { public void onlineInit(LoginCredentials credentials) throws Exception {
logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort()));
socket = new Socket(config.getServer(), config.getPort()); socket = new Socket(config.getServer(), config.getPort());
logger.info("Successfully connected to server."); logger.info("Successfully connected to server.");
@ -47,14 +47,20 @@ public class Client {
logger.finest("Sending login credentials..."); logger.finest("Sending login credentials...");
SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream());
// Read response (user object) // Create message receiver
InputStream in = socket.getInputStream(); Receiver receiver = new Receiver(socket.getInputStream());
// Read object // Register user creation processor
try { receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; });
sender = SerializationUtils.read(in, User.class);
} catch (ClassNotFoundException e) { // Start receiver
throw new IOException(e); new Thread(receiver).start();
// Wait for a maximum of five seconds to acquire the sender object
long start = System.currentTimeMillis();
while (sender == null) {
if (System.currentTimeMillis() - start > 5000) throw new EnvoyException("Did not log in after 5 seconds");
Thread.sleep(500);
} }
online = true; online = true;

View File

@ -0,0 +1,15 @@
package envoy.client;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>ObjectProcessor.java</strong><br>
* Created: <strong>30.12.2019</strong><br>
*
* @author Kai S. K. Engelbart
* @since Envoy v0.3-alpha
*/
public interface ObjectProcessor<T> {
void process(T input);
}

View File

@ -0,0 +1,50 @@
package envoy.client;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import envoy.client.util.EnvoyLog;
/**
* Project: <strong>envoy-client</strong><br>
* File: <strong>Receiver.java</strong><br>
* Created: <strong>30.12.2019</strong><br>
*
* @author Kai S. K. Engelbart
* @since Envoy v0.3-alpha
*/
public class Receiver implements Runnable {
private InputStream in;
private Map<Class<?>, ObjectProcessor<?>> processors = new HashMap<>();
private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName());
public Receiver(InputStream in) { this.in = in; }
@SuppressWarnings("unchecked")
@Override
public void run() {
try (ObjectInputStream oin = new ObjectInputStream(in)) {
while (true) {
Object obj = oin.readObject();
logger.finest("Received object " + obj);
// Get appropriate processor
ObjectProcessor processor = processors.get(obj.getClass());
if (processor == null)
logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass()));
else
processor.process(obj);
}
} catch(Exception e) {
logger.log(Level.SEVERE, "Error on receiver thread", e);
}
}
public <T> void registerProcessor(Class<T> processorClass, ObjectProcessor<T> processor) { processors.put(processorClass, processor); }
}

View File

@ -101,6 +101,7 @@ public class Startup {
client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); client.onlineInit(new LoginCredentials(userName, pass.toCharArray()));
} catch (Exception e1) { } catch (Exception e1) {
logger.warning("Could not connect to server. Trying offline mode..."); logger.warning("Could not connect to server. Trying offline mode...");
e1.printStackTrace();
try { try {
// Try entering offline mode // Try entering offline mode
localDB.loadUsers(); localDB.loadUsers();