package envoy.server.net; import java.io.*; import java.lang.reflect.ParameterizedType; import java.util.Set; import java.util.logging.*; import com.jenkov.nioserver.*; import envoy.data.AuthenticatedRequest; import envoy.util.EnvoyLog; import envoy.server.data.PersistenceManager; import envoy.server.processors.ObjectProcessor; /** * Handles incoming objects. * * @author Kai S. K. Engelbart * @since Envoy Server Standalone v0.1-alpha */ public final class ObjectMessageProcessor implements IMessageProcessor { private final Set> processors; private static final Logger logger = EnvoyLog.getLogger(ObjectMessageProcessor.class); /** * The constructor to set the {@link ObjectProcessor}s. * * @param processors the {@link ObjectProcessor} to set * @since Envoy Server Standalone v0.1-alpha */ public ObjectMessageProcessor(Set> processors) { this.processors = processors; } @Override public void process(Message message, WriteProxy writeProxy) { try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(message.sharedArray, message.offset + 4, message.length - 4))) { Object obj = in.readObject(); if (obj == null) { logger.warning("Received a null object"); return; } // authenticate requests if necessary boolean authenticated = false; if (obj instanceof AuthenticatedRequest) try { authenticated = PersistenceManager .getInstance().getUserByID(((AuthenticatedRequest) obj).getUserID()) .getID() == ConnectionManager.getInstance() .getUserIDBySocketID(message.socketId); // Class cast exception and NullPointerException are valid here and signify a // failed authentication } catch (ClassCastException | NullPointerException e) {} finally { obj = ((AuthenticatedRequest) obj).getRequest(); } logger.log(Level.INFO, "Received " + (authenticated ? "" : "un") + "authenticated " + obj); refer(message.socketId, writeProxy, obj, authenticated); } catch (IOException | ClassNotFoundException e) { logger.log(Level.WARNING, "An exception occurred when reading in an object: " + e); } } /** * Executes the appropriate {@link ObjectProcessor} for the given input ({@code obj}), if any is * present. */ @SuppressWarnings("unchecked") private void refer(long socketID, WriteProxy writeProxy, Object obj, boolean authenticated) { // Get processor and input class and process object for (@SuppressWarnings("rawtypes") ObjectProcessor p : processors) { Class c = (Class) ((ParameterizedType) p.getClass().getGenericInterfaces()[0]) .getActualTypeArguments()[0]; if (c.equals(obj.getClass())) { if (!authenticated && p.isAuthenticationRequired()) { logger.log(Level.INFO, "Discarding request as no authentication has been provided"); return; } try { p.process(c.cast(obj), socketID, new ObjectWriteProxy(writeProxy)); break; } catch (IOException e) { logger.log(Level.SEVERE, "Exception during processor execution: ", e); } } } } }