001    /*
002     * $Id: LoginService.java,v 1.9 2005/11/30 05:21:56 rbair Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     *
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     *
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.auth;
022    
023    import java.awt.EventQueue;
024    import java.util.Iterator;
025    import java.util.Vector;
026    import java.util.logging.Logger;
027    
028    import javax.swing.SwingUtilities;
029    import org.jdesktop.swingx.util.SwingWorker;
030    
031    /**
032     * <b>LoginService</b> is the abstract base class for all classes implementing
033     * a login mechanism. It allows you to customize the threading behaviour
034     * used to perform the login. Subclasses need to override the <b>authenticate</b>
035     * method.
036     * Subclasses may implement the getUserRoles() method to return a meaningful value
037     * this method will be called once upon a successful login to determine the user roles.
038     * It is not defined as abstract to simplify the task of implementing a login service
039     * for those who do not require this functionality.
040     *
041     * @author Bino George
042     * @author Shai Almog
043     */
044    public abstract class LoginService {
045        private Logger LOG = Logger.getLogger(LoginService.class.getName());
046        private Vector<LoginListener> listenerList = new Vector<LoginListener>();
047        private SwingWorker loginWorker;
048        
049         /*
050          * Controls the authentication behaviour to be either
051          * synchronous or asynchronous
052          */
053        private boolean synchronous;
054        private String server;
055        
056        public LoginService() {
057        }
058        
059        public LoginService(String server) {
060            setServer(server);
061        }
062        
063        /**
064         * This method is intended to be implemented by clients
065         * wishing to authenticate a user with a given password.
066         * Clients should implement the authentication in a
067         * manner that the authentication can be cancelled at
068         * any time.
069         *
070         * @param name username
071         * @param password password
072         * @param server server (optional)
073         *
074         * @return <code>true</code> on authentication success
075         * @throws Exception
076         */
077        public abstract boolean authenticate(String name, char[] password, String server) throws Exception;
078        
079        /**
080         * Called immediately after a successful authentication. This method should return an array
081         * of user roles or null if role based permissions are not used.
082         *
083         * @return per default <code>null</code>
084         */
085        public String[] getUserRoles() {
086            return null;
087        }
088        
089        /**
090         * Notifies the LoginService that an already running
091         * authentication request should be cancelled. This
092         * method is intended to be used by clients who want
093         * to provide user with control over cancelling a long
094         * running authentication request.
095         */
096        public void cancelAuthentication() {
097            if (loginWorker != null) {
098                loginWorker.cancel(true);
099            }
100        }
101        
102        /**
103         * This method starts the authentication process and is either
104         * synchronous or asynchronous based on the synchronous property
105         *
106         * @param user user
107         * @param password password
108         * @param server server
109         * @throws Exception
110         */
111        public void startAuthentication(final String user, final char[] password, final String server) throws Exception {
112            if (getSynchronous()) {
113                try {
114                    if (authenticate(user,password,server)) {
115                        fireLoginSucceeded(new LoginEvent(this));
116                    } else {
117                        fireLoginFailed(new LoginEvent(this));
118                    }
119                } catch (Throwable e) {
120                    fireLoginFailed(new LoginEvent(this, e));
121                }
122            } else {
123                loginWorker = new SwingWorker() {
124                    protected Object doInBackground() throws Exception {
125                        try {
126                            final boolean result = authenticate(user,password,server);
127                            if (isCancelled()) {
128                                EventQueue.invokeLater(new Runnable() {
129                                    public void run() {
130                                        fireLoginCanceled(new LoginEvent(this));
131                                    }
132                                });
133                                return false;
134                            }
135                            EventQueue.invokeLater(new Runnable() {
136                                public void run() {
137                                    if (result) {
138                                        fireLoginSucceeded(new LoginEvent(LoginService.this));
139                                    } else {
140                                        fireLoginFailed(new LoginEvent(LoginService.this));
141                                    }
142                                }
143                            });
144                            return result;
145                        } catch (final Throwable failed) {
146                            if (!isCancelled()) {
147                                SwingUtilities.invokeLater(new Runnable() {
148                                    public void run() {
149                                        fireLoginFailed(new LoginEvent(LoginService.this, failed));
150                                    }
151                                });
152                            } else {
153                                EventQueue.invokeLater(new Runnable() {
154                                    public void run() {
155                                        fireLoginCanceled(new LoginEvent(this));
156                                    }
157                                });
158                            }
159                            return false;
160                        }
161                    }
162                };
163                loginWorker.execute();
164                fireLoginStarted(new LoginEvent(this));
165            }
166        }
167        
168        /**
169         * Get the synchronous property
170         * @return the synchronous property
171         */
172        public boolean getSynchronous() {
173            return synchronous;
174        }
175        /**
176         * Sets the synchronous property
177         *
178         * @param synchronous synchronous property
179         */
180        public void setSynchronous(boolean synchronous) {
181            this.synchronous = synchronous;
182        }
183        
184        /**
185         * Adds a <strong>LoginListener</strong> to the list of listeners
186         *
187         * @param listener listener
188         */
189        
190        public void addLoginListener(LoginListener listener) {
191            listenerList.add(listener);
192        }
193        
194        /**
195         * Removes a <strong>LoginListener</strong> from the list of listeners
196         *
197         * @param listener listener
198         */
199        public void removeLoginListener(LoginListener listener) {
200            listenerList.remove(listener);
201        }
202        
203        
204        void fireLoginStarted(final LoginEvent source) {
205            Iterator iter = listenerList.iterator();
206            while (iter.hasNext()) {
207                LoginListener listener = (LoginListener) iter.next();
208                listener.loginStarted(source);
209            }
210        }
211        
212        void fireLoginSucceeded(final LoginEvent source) {
213            Iterator iter = listenerList.iterator();
214            while (iter.hasNext()) {
215                LoginListener listener = (LoginListener) iter.next();
216                listener.loginSucceeded(source);
217            }
218        }
219        
220        void fireLoginFailed(final LoginEvent source) {
221            Iterator iter = listenerList.iterator();
222            while (iter.hasNext()) {
223                LoginListener listener = (LoginListener) iter.next();
224                listener.loginFailed(source);
225            }
226        }
227        
228        void fireLoginCanceled(final LoginEvent source) {
229            Iterator iter = listenerList.iterator();
230            while (iter.hasNext()) {
231                LoginListener listener = (LoginListener) iter.next();
232                listener.loginCanceled(source);
233            }
234        }
235        
236        
237        /**
238         * @return Returns the server.
239         */
240        public String getServer() {
241            return server;
242        }
243        /**
244         * @param server The server to set.
245         */
246        public void setServer(String server) {
247            this.server = server;
248        }
249    }