samedi 17 mars 2018

Using Command Pattern in multi-client/server application based on Java RMI

I am trying to implement a client-server application to manage a group of students.

Each student can:

  • Register himself to the system providing some information
  • Login into the system using an email and a password
  • Send a collaboration request to another student
  • Accept a request sent to him
  • Reject a request sent to him
  • Get the list of all students registrated into the system
  • Get a list of all collaboration requests recived by him
  • Get all the collaboration requests sent to him

Every information about a student and a request are stored on a database. The access to the database is managed using a DAO Pattern. So I have the following DAOs: LoginDAO, StudentDAO, RequestDAO

I have implemented a solution using the Command Pattern but I am having some problem and not sure if the this pattern can actually fit in this context. Briefly my problem is returning results like true or false in case the client tries to login, or returning a list of Student object if the client requests them. There are other cases also where the server do not have to return any value.

What so far I have implemented:

Client side: A client can obtain a reference to an object capable to set the desired commands. The implementation of this object is server side but the Interface is shared between the client and the server. This object is used so i do not have to exposes the implementation of each commands to the client.

ClientMain:

package client;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.JOptionPane;

import common.*;

public class ClientMain {

    public static void main(String[] args) {

        ServerCommandsSetterInterface scsi = null;

        System.setProperty("java.security.policy","file:///policy");
        if (System.getSecurityManager() == null)
            System.setSecurityManager(new SecurityManager());
        try {
            String name = "ServerTC";
            Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1111);
            scsi = (ServerCommandsSetterInterface) registry.lookup(name);
            //ClientCommandsSetterInterface ccsi = new ClientCommandsSetter();
            //ClientCommandsSetterInterface ccsiStub = (ClientCommandsSetterInterface) UnicastRemoteObject.exportObject(ccsi, 0);

        } catch (RemoteException e) {
            System.err.println("Exception while getting remote object 'ServerTC':");
            e.printStackTrace();
            System.exit(1);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        boolean loginSuccess = scsi.setCommandLogin("studentemail", "studentpassword");

    }

}

ServerCommandsSetterInterface:

package common;

import java.rmi.*;

public interface ServerCommandsSetterInterface extends Remote{
    public boolean setCommandLogin(String email, String password) throws RemoteException;


}

On the server side we have:

ServerMain:

package server;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;

import common.ServerCommandsSetterInterface;
import common.Student;

public class ServerMain {

    public static void main(String[] args) {
        System.setProperty("java.security.policy","file:///policy");
        if (System.getSecurityManager() == null) 
            System.setSecurityManager(new SecurityManager());
        try {

            String name = "ServerTC";
            ServerCommandsSetterInterface scsi = new ServerCommandsSetter();
            ServerCommandsSetterInterface scsiStub =
                (ServerCommandsSetterInterface) UnicastRemoteObject.exportObject(scsi, 0);
            Registry registry = LocateRegistry.createRegistry(1111);
            registry.rebind(name, scsiStub);
            System.out.println("ServerTC bound, press [enter] to unbound and terminate");
            while(System.in.read() != '\n');
            UnicastRemoteObject.unexportObject(scsi, true);
            System.out.println("ServerTC unbound, System goes down ...");
        }catch (RemoteException e) {
            System.err.println("Remote exception:");
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ServerCommandsSetter:

package server;

import java.rmi.RemoteException;

import common.*;

public class ServerCommandsSetter implements ServerCommandsSetterInterface {
    SynchCommandsInvoker sServerCommandsInvoker;
    LoginJDBCDAO lDAO;
    StudentJDBCDAO sDAO;
    RegistrationJDBCDAO rDAO;

    public ServerCommandsSetter() {
        sServerCommandsInvoker = new SynchCommandsInvoker();
         lDAO = new LoginJDBCDAO();
         sDAO = new StudentJDBCDAO();
         rDAO = new RegistrationJDBCDAO();
    }

    public boolean setCommandLogin(String email, String password) throws RemoteException{
        Command loginCommand = new Login(lDAO, email, password);
        sServerCommandsInvoker.invokeCommand(loginCommand);
        return ((Login) loginCommand).getResult();
    }

}

Command:

package common;

public interface Command {
    public void execute();
}

Login:

package server;

import java.rmi.RemoteException;

import common.*;


public class Login implements Command {
    LoginJDBCDAO lDAO;
    String email, password;
    boolean status;
    public Login(LoginJDBCDAO lDAO, String email, String password) {
        this.lDAO = lDAO;
        this.email = email;
        this.password = password;
        status = false;
    }



    public void execute() {
        status = lDAO.login(email, password);
    }

    public boolean getResult() {
        return status;
    }

}

LoginDAO:

package server;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class LoginJDBCDAO {
    Connection connection = null;
    PreparedStatement ptmt = null;
    ResultSet resultSet = null;
    public boolean login(String email, String password) {
        boolean success=false;
        try {
            String queryString = "SELECT * FROM STUDENTS WHERE email=? AND password=?";
            connection = getConnection();
            ptmt = connection.prepareStatement(queryString);
            ptmt.setString(1,email);
            ptmt.setString(2, password);
            resultSet = ptmt.executeQuery();
            if(resultSet.next()) {
                queryString = "UPDATE STUDENTS SET online=1 WHERE email=?";
                ptmt = connection.prepareStatement(queryString);
                ptmt.setString(1, email);
                if(ptmt.executeUpdate()>0)
                success = true;
            } 


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (ptmt != null) {
                    ptmt.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return success;
    }

    public boolean logout(String email) {
        boolean success=false;
        try {
            String queryString = "UPDATE STUDENTS SET online=0 WHERE email=?";
            connection = getConnection();
            ptmt = connection.prepareStatement(queryString);
            ptmt.setString(1, email);
            if(ptmt.executeUpdate()>0)
            success = true;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (ptmt != null) {
                    ptmt.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return success;
    }

    private Connection getConnection() throws SQLException {
        Connection conn;
        conn = DatabaseConnectionFactory.getInstance().getConnection();
        return conn;
    }
}

CommandsInvoker:

package common;

public class CommandsInvoker {
public CommandsInvoker() {

    }

    public void invokeCommand(Command c) {
        c.execute();
    }

}

Questions: Is there a way to return results from the execution of a command in this case? Would it make sense to use sockets to return the result? Are there other design patterns suitable in this case(possibly well documented and with examples)?

Aucun commentaire:

Enregistrer un commentaire