package com.coder.client; import java.io.IOException; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import com.coder.server.CoderServer; import com.coder.server.message.CoderMessage; import com.coder.server.message.ConfigData; import com.coder.server.message.ProjectListData; import com.coder.server.message.ProjectListReqMsg; import com.coder.server.message.ProjectRspMsg; import zutil.log.CompactLogFormatter; import zutil.log.LogUtil; public class CoderClient extends Thread{ public static final Logger logger = LogUtil.getLogger(); private static final int DEFAULT_CONNECTION_RETRIES = 5; private String url; private int port; private Session session; private ProjectEditorWindow projectEditorWindow; private ProjectSelectDialog projectSelectDialog; private String username = null; private char[] password = null; private int connectionRetriesLimit = DEFAULT_CONNECTION_RETRIES; //if zero, try forever public CoderClient(String url, int port) { this.url = url; this.port = port; this.projectEditorWindow = new ProjectEditorWindow("CoderClient"); this.projectSelectDialog = new ProjectSelectDialog(null); LogUtil.setGlobalLevel(Level.INFO); LogUtil.setGlobalFormatter(new CompactLogFormatter()); } public void run(){ //keep track of the number of connection retries to the server int connectionRetries = 0; while(true){ //close previous session if applicable closeCurrentSession(); //setup a new session if(connectionRetries > 0){ logger.fine("This is reconnection try number: " + connectionRetries); } logger.fine("Setting up a connected session"); this.session = Session.setupConnection(url, port); if(session == null){ logger.warning("Could not setup a connection to " + url + ":" + port); connectionRetries++; if(connectionRetriesLimit > 0 && connectionRetries > connectionRetriesLimit){ //stop trying to connect logger.severe("Was not able to conenct to the remote host."); break; }else{ //wait for awhile and try to connect one more logger.info("Will retry to connect once more in 2 seconds."); try { Thread.sleep(2000); } catch (InterruptedException e) { } continue; } } //get user credentials if(username != null && !username.isEmpty() && password != null && password.length > 0){ //do nothing, already have all credentials we need logger.fine("All login credentials have already been given. No need for a login dialog."); }else{ //ask for username and password in a dialog window logger.info("All or some login credentials have not been given. Using a dialog for input."); LoginDialog loginDialog = new LoginDialog(username, null); loginDialog.setVisible(true); //blocking loginDialog.dispose(); if(loginDialog.getAction() == LoginDialog.LoginDialogAction.CANCEL){ logger.fine("Login dialog closed or canceled by the user. terminating."); break; } username = loginDialog.getUsername(); password = loginDialog.getPassword(); } logger.fine("The username: \"" + username + "\" will be used as the credential holder"); //authenticate the user boolean authenticated = session.authenticate(username, password); if(!authenticated){ JOptionPane.showMessageDialog(null, "Wrong username or password", "Authentication Failed", JOptionPane.INFORMATION_MESSAGE); logger.severe("Authentication failed: wrong username or password"); continue; } //forget the password for(int i = 0; i < password.length; ++i){ password[i] = '*'; } password = null; //resister a message listener to the session session.addCoderMessageReceivedListener(new CoderMessageReceivedListener() { @Override public void projectListRspReceived(Map projectListRsp) { for(String projectName : projectListRsp.keySet()){ ProjectListData projectData = projectListRsp.get(projectName); projectSelectDialog.addProjectToList(projectName, projectData.type); } } @Override public void projectTypeRspReceived(Map projectTypeRsp) { // TODO Auto-generated method stub } @Override public void projectRspReceived(ProjectRspMsg projectRspMsg) { // TODO Auto-generated method stub } }); //start receiving traffic from the server session.start(); //clear the current local project list this.projectSelectDialog.clearProjectList(); //request a new project list from the server CoderMessage msg = new CoderMessage(); msg.ProjectListReq = new ProjectListReqMsg(); try { session.send(msg); } catch (IOException e) { logger.log(Level.SEVERE, "Unable to send ProjectListReqMsg", e); continue; } //show the project selector dialog this.projectSelectDialog.setVisible(true); //blocking if(this.projectSelectDialog.getAction() == ProjectSelectDialog.ProjectSelectDialogAction.CANCEL){ logger.fine("Project select dialog closed or canceled by the user. terminating."); break; } String selectedProjectName = this.projectSelectDialog.getSelecteProjectName(); logger.info("Project \"" +selectedProjectName+ "\" was selected."); //add a listener to forward messages from the editor GUI to the server this.projectEditorWindow.addMessageSentListener(new GUIMessageSentListener(){ @Override public void sendMessage(CoderMessage msg) { try { session.send(msg); } catch (IOException e) { logger.log(Level.SEVERE, "could not forward message from editor to the server", e); } } }); //show the user the editor GUI this.projectEditorWindow.setVisible(true); try {Thread.sleep(1000);} catch (InterruptedException e) {} //wait here until the session is closed for some reason while(session.isConnected()){ Thread.yield(); } //hide the main GUI logger.fine("The socket was closed."); this.projectEditorWindow.setVisible(false); Thread.yield(); } logger.info("The program till now terminate"); closeCurrentSession(); this.projectEditorWindow.dispose(); System.exit(0); } private void closeCurrentSession(){ if(this.session != null){ session.close(); session = null; } } public void setPassword(char[] password) { this.password = password; } public void setUsername(String username) { this.username = username; } public void setRetryConnectForever(boolean tryForever) { if(tryForever){ this.connectionRetriesLimit = 0; }else{ this.connectionRetriesLimit = DEFAULT_CONNECTION_RETRIES; } } public static void main(String[] args){ int port = CoderServer.SERVER_PORT; String username = null; char[] password = null; boolean reconnectForever = false; //parse program arguments for(int i = 0; i < args.length; ++i){ String arg = args[i]; if(arg.equals("-h") || arg.equals("--help")){ System.out.println("Usage: CoderClient [options]"); System.out.println("Options:"); System.out.println("-h|--help Print this help."); System.out.println("-u|--username Set the username to use when authenticating."); System.out.println("-p|--password Set the password used when authenticating. The password will not be safetly"); System.out.println(" stored and ths option should not be used in anything but debuging."); System.out.println(" A password cannot be defined without a username. If booth"); System.out.println(" a username and a password has been defined by arguments the software will not."); System.out.println(" prompt for this."); System.out.println(" If not a port have been defined, the deafult port will be used."); System.out.println("--retry-connect-forever Make the software never stop trying to reconnect to its peer."); System.exit(0); }else if(arg.equals("-u") || arg.equals("--username")){ i++; if(i < args.length){ username = args[i]; }else{ System.err.println("missing username argument"); System.exit(1); } }else if(arg.equals("-p") || arg.equals("--password")){ i++; if(i < args.length){ password = args[i].toCharArray(); }else{ System.err.println("missing password argument"); System.exit(1); } }else if(arg.equals("--retry-connect-forever")){ reconnectForever = true; } } //create a client instance CoderClient client = new CoderClient("127.0.0.1", port); if(username != null){ client.setUsername(username); if(password != null){ client.setPassword(password); } } client.setRetryConnectForever(reconnectForever); client.start(); } }