1 /**
2  * Jin - a chess client for internet chess servers.
3  * More information is available at http://www.jinchess.com/.
4  * Copyright (C) 2003 Alexander Maryanovsky.
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  */
21 
22 package free.jin;
23 
24 import java.util.List;
25 
26 import free.jin.plugin.PluginStartException;
27 import free.jin.ui.LoginPanel;
28 import free.jin.ui.OptionPanel;
29 import free.jin.ui.ServerChoicePanel;
30 import free.util.EventListenerList;
31 import free.util.TextUtilities;
32 import free.util.Utilities;
33 
34 
35 /**
36  * Manages the creation, initiation and closing of the connection to the server.
37  */
38 
39 public class ConnectionManager{
40 
41 
42 
43   /**
44    * The current Session. Null when none.
45    */
46 
47   private Session session = null;
48 
49 
50 
51   /**
52    * The model whose state matches whether a session is currently established.
53    */
54 
55   private final EventListenerList listenerList = new EventListenerList();
56 
57 
58 
59   /**
60    * Creates a new <code>ConnectionManager</code>.
61    */
62 
ConnectionManager()63   public ConnectionManager(){
64 
65   }
66 
67 
68 
69   /**
70    * Displays UI which allows the user to login to one of the supported servers.
71    * This method is invoked (usually by the class responsible for the start-up
72    * of the application) when all the start up initialization (preferences,
73    * ui factory etc.) has finished and it's ok to start the normal flow of the
74    * application.
75    */
76 
start()77   public void start(){
78     Server server = findLoginServer();
79     if (server == null)
80       return;
81 
82     User user = findLoginUser(server);
83 
84     ConnectionDetails connDetails = findConnDetails(server, user);
85     if (connDetails == null){
86       Jin.getInstance().quitIfNoUiVisible();
87       return;
88     }
89 
90     login(connDetails);
91   }
92 
93 
94 
95   /**
96    * Determines and returns the server we should login to, based on
97    * (in that order):
98    * <ol>
99    *   <li> Application parameters.
100    *   <li> Last logged in user.
101    *   <li> Sole supported server.
102    *   <li> Server choice panel displayed to the user.
103    * </ol>
104    * Returns <code>null</code> if all the above methods fail (implies that
105    * the user canceled the server choice panel).
106    */
107 
findLoginServer()108   private Server findLoginServer(){
109     Jin jin = Jin.getInstance();
110 
111     // Application parameters
112     String serverId = jin.getParameter("login.server");
113     if (serverId != null){
114       Server server = jin.getServerById(serverId);
115       if (server == null){
116         I18n i18n = I18n.get(getClass());
117         i18n.error("unknownServerParam", new Object[]{serverId});
118       }
119       else
120         return server;
121     }
122 
123     // Last logged in user
124     User lastUser = getLastUser();
125     if (lastUser != null)
126       return lastUser.getServer();
127 
128     // Sole supported server
129     if (jin.getServers().length == 1)
130       return jin.getServers()[0];
131 
132     // Server choice panel
133     Server askedServer = new ServerChoicePanel().askServer();
134     if (askedServer != null)
135       return askedServer;
136 
137     return null;
138   }
139 
140 
141 
142   /**
143    * Determines and returns the user account we should login with, based on
144    * (in that order):
145    * <ol>
146    *   <li> Application parameters.
147    *   <li> Last logged in user.
148    *   <li> Sole known user for the server.
149    * </ol>
150    * Returns <code>null</code> if all the above methods fail.
151    */
152 
findLoginUser(Server server)153   private User findLoginUser(Server server){
154     Jin jin = Jin.getInstance();
155 
156     // Application parameters
157     boolean isGuest = new Boolean(jin.getParameter("login.guest")).booleanValue();
158     String username = jin.getParameter("login.username");
159     if (isGuest)
160       return server.getGuest();
161     else if (username != null){
162       User user = jin.getUser(server, username);
163       if (user == null) // New user
164         return new User(server, username);
165       else
166         return user;
167     }
168 
169     // Last logged in user
170     User lastUser = getLastUser();
171     if ((lastUser != null) && (lastUser.getServer() == server))
172       return lastUser;
173 
174     // Only one known user on the server
175     List serverUsers = jin.getUsers(server);
176     if (serverUsers.size() == 1)
177       return (User)serverUsers.get(0);
178 
179     return null;
180   }
181 
182 
183 
184   /**
185    * Determines the connection details we should use when logging in, based on
186    * (in that order, for each connection detail):
187    * <ol>
188    *   <li> Application parameters.
189    *   <li> Specified user.
190    *   <li> Specified server.
191    * </ol>
192    * Additionally, if the applications parameters allow displaying the login
193    * panel, any connection details modified by the user there override all
194    * others.
195    * Returns <code>null</code> if all the above methods fail (implies that the
196    * user canceled the login panel).
197    * The specified user may be <code>null</code>, but not the server.
198    */
199 
findConnDetails(Server server, User user)200   private ConnectionDetails findConnDetails(Server server, User user){
201     if (user == null)
202       return new LoginPanel(server).askConnectionDetails();
203 
204     Jin jin = Jin.getInstance();
205     ConnectionDetails connDetails = user.getPreferredConnDetails();
206 
207     String password = jin.getParameter("login.password");
208     if (password == null)
209       password = connDetails.getPassword();
210 
211     String savePassString = jin.getParameter("login.savepassword");
212     boolean savePassword = new Boolean(savePassString).booleanValue();
213     if ((savePassString == null) && !connDetails.isGuest())
214       savePassword = connDetails.isSavePassword();
215 
216     String hostname = jin.getParameter("login.hostname");
217     if (hostname == null){
218       hostname = connDetails.getHost();
219     }
220 
221     String portsString = jin.getParameter("login.ports");
222     int [] ports;
223     if (portsString != null)
224       ports = TextUtilities.parseIntList(portsString, ",");
225     else
226       ports = connDetails.getPorts();
227 
228 
229     if (user.isGuest())
230       connDetails = ConnectionDetails.createGuest(server, user.getUsername(), hostname, ports);
231     else
232       connDetails = ConnectionDetails.create(server, user, user.getUsername(), password, savePassword, hostname, ports);
233 
234     if (!(new Boolean(jin.getParameter("autologin")).booleanValue()))
235       connDetails = new LoginPanel(connDetails).askConnectionDetails();
236 
237     return connDetails;
238   }
239 
240 
241 
242   /**
243    * Displays UI for creating a new connection (from scratch).
244    */
245 
displayNewConnUI()246   public void displayNewConnUI(){
247     Server server;
248 
249     Server [] servers = Jin.getInstance().getServers();
250     // Sole supported server
251     if (servers.length == 1)
252       server = servers[0];
253     else{  // Server choice panel
254       server = new ServerChoicePanel().askServer();
255       if (server == null)
256         return;
257     }
258 
259     ConnectionDetails connDetails = new LoginPanel(server).askConnectionDetails();
260 
261     if (connDetails == null){ // user canceled the dialog
262       Jin.getInstance().quitIfNoUiVisible();
263       return;
264     }
265 
266     login(connDetails);
267   }
268 
269 
270 
271   /**
272    * Displays UI for connecting with the specified account.
273    */
274 
displayNewConnUI(User user)275   public void displayNewConnUI(User user){
276     ConnectionDetails connDetails =
277       new LoginPanel(user.getPreferredConnDetails()).askConnectionDetails();
278 
279     if (connDetails == null){ // user canceled the dialog
280       Jin.getInstance().quitIfNoUiVisible();
281       return;
282     }
283 
284     login(connDetails);
285   }
286 
287 
288 
289 
290   /**
291    * Initiates login with the specified connection details.
292    */
293 
login(ConnectionDetails connDetails)294   private void login(ConnectionDetails connDetails){
295     try{
296       session = new Session(connDetails);
297       fireSessionEvent(new SessionEvent(this, SessionEvent.SESSION_ESTABLISHED, session));
298       session.initiateLogin();
299     } catch (PluginStartException e){
300         e.printStackTrace();
301         Exception reason = e.getReason();
302 
303         String errorMessage = e.getMessage() + "\n" +
304           (reason == null ? "" : reason.getClass().getName() + ": " + reason.getMessage());
305         OptionPanel.error("Error", errorMessage);
306       }
307   }
308 
309 
310 
311   /**
312    * Invoked by Session if login fails.
313    *
314    * @param message The message with which login failed.
315    */
316 
loginFailed(String message)317   void loginFailed(String message){
318     I18n i18n = I18n.get(getClass());
319     i18n.error("loginErrorDialog", new Object[]{message});
320 
321     // Reopen the connection UI
322     User user = session.getUser();
323     closeSession();
324     displayNewConnUI(user);
325   }
326 
327 
328 
329   /**
330    * Closes the current session. The call is ignored if there is no current
331    * session.
332    */
333 
closeSession()334   public void closeSession(){
335     if (session == null)
336       return;
337 
338     // Close the session
339     session.close();
340 
341     User user = session.getUser();
342     int connPort = session.getPort();
343 
344     if (connPort != -1){ // A connection really was established
345 
346       // Set preferred connection details for this account
347       ConnectionDetails connDetails = session.getConnDetails().usePort(connPort);
348       user.setPreferredConnDetails(connDetails);
349 
350       // Add the user to the known users list
351       if (!user.isGuest() && !Jin.getInstance().isKnownUser(user)){
352         I18n i18n = I18n.get(getClass());
353 
354         boolean rememberUser =
355           !Jin.getInstance().isSavePrefsCapable() ||
356           OptionPanel.YES == i18n.question(OptionPanel.YES, "rememberAccountDialog", new Object[]{user.getUsername()});
357 
358         if (rememberUser){
359           Jin.getInstance().addUser(user);
360           saveLastUser(user);
361         }
362       }
363       else{
364         user.markDirty();
365         saveLastUser(user);
366       }
367     }
368 
369     Session tempSession = session;
370 
371     session = null;
372 
373     fireSessionEvent(new SessionEvent(this, SessionEvent.SESSION_CLOSED, tempSession));
374   }
375 
376 
377 
378   /**
379    * Returns the current <code>Session</code>, or <code>null</code> if none.
380    */
381 
getSession()382   public Session getSession(){
383     return session;
384   }
385 
386 
387 
388   /**
389    * Adds a session listener.
390    */
391 
addSessionListener(SessionListener l)392   public void addSessionListener(SessionListener l){
393     listenerList.add(SessionListener.class, l);
394   }
395 
396 
397 
398   /**
399    * Removes a session listener.
400    */
401 
removeSessionListener(SessionListener l)402   public void removeSessionListener(SessionListener l){
403     listenerList.remove(SessionListener.class, l);
404   }
405 
406 
407 
408   /**
409    * Fires a session event.
410    */
411 
fireSessionEvent(SessionEvent evt)412   private void fireSessionEvent(SessionEvent evt){
413     Object [] listeners = listenerList.getListenerList();
414     for (int i = 0; i < listeners.length; i += 2){
415       if (listeners[i] == SessionListener.class){
416         SessionListener listener = (SessionListener)listeners[i+1];
417         switch (evt.getId()){
418           case SessionEvent.SESSION_ESTABLISHED:
419             listener.sessionEstablished(evt);
420             break;
421           case SessionEvent.SESSION_CLOSED:
422             listener.sessionClosed(evt);
423             break;
424         }
425       }
426     }
427 
428   }
429 
430 
431 
432   /**
433    * Returns the <code>User</code> object of the last account that logged on.
434    * Returns <code>null</code> if none.
435    */
436 
getLastUser()437   private User getLastUser(){
438     Preferences prefs = Jin.getInstance().getPrefs();
439     String serverId = prefs.getString("last-login.serverId", null);
440     String username = prefs.getString("last-login.username", null);
441 
442     if (serverId == null)
443       return null;
444 
445     Server server = Jin.getInstance().getServerById(serverId);
446     if (username == null)
447       return server.getGuest();
448     else
449       return Jin.getInstance().getUser(server, username);
450   }
451 
452 
453 
454   /**
455    * Saves the information about the last account that logged in into
456    * preferences.
457    */
458 
saveLastUser(User user)459   private void saveLastUser(User user){
460     Preferences prefs = Jin.getInstance().getPrefs();
461     String serverId = user.getServer().getId();
462     String oldServerId = prefs.getString("last-login.serverId", null);
463 
464     prefs.setString("last-login.serverId", serverId);
465     if (!Utilities.areEqual(serverId, oldServerId))
466       prefs.setString("last-login.username",
467         user.isGuest() || !Jin.getInstance().isKnownUser(user) ? null : user.getUsername());
468     else if (!user.isGuest())
469       prefs.setString("last-login.username", user.getUsername());
470   }
471 
472 
473 
474 }