001    /* PAVLOV -- Multiple Choice Study System
002     * Copyright (C) 2000 - 2004 T.J. Willis
003     * 
004     * This program is free software; you can redistribute it and/or
005     * modify it under the terms of the GNU General Public License
006     * as published by the Free Software Foundation; either version 2
007     * of the License, or (at your option) any later version.
008     *      
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *          
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, write to the Free Software
016     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
017     *  
018     * $Header: /cvsroot/pavlov/net/sourceforge/pavlov/main/AbstractPavlovApplication.java,v 1.9 2004/06/27 08:11:09 tj_willis Exp $
019     */ 
020    package net.sourceforge.pavlov.main;
021    
022    import java.util.MissingResourceException;
023    import java.util.ResourceBundle;
024    import net.sourceforge.pavlov.event.*;
025    import net.sourceforge.pavlov.main.standalone.ResourceBroker;
026    import net.sourceforge.pavlov.library.AbstractLibrary;
027    import net.sourceforge.pavlov.library.LibraryLoader;
028    import net.sourceforge.pavlov.pluglets.*;
029    import net.sourceforge.pavlov.pluglets.feedback.velocity.*;
030    import net.sourceforge.pavlov.pluglets.strategy.*;
031    import net.sourceforge.pavlov.user.*;
032    import org.apache.log4j.*;
033    
034    /**
035     * An abstract class that handles most of the work of a Pavlov Application,
036     * whether it be applet, servlet, client-server, or standalone.
037     *
038     * @author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a>
039     * @version 1.0
040     */
041    public abstract class AbstractPavlovApplication 
042        implements LogonListener
043    {
044    
045        // FIXED: factor out JFrame
046        /**
047         * The current user.
048         *
049         */
050        protected User user;  //FIXED: de-static all fields
051        /**
052         * The user's name, used before login.
053         *
054         */
055        protected String userName;
056        /**
057         * The user's password, used before login.
058         *
059         */
060        protected String password;
061        /**
062         * The directory containing book files.
063         *
064         */
065        protected String libraryFile;// = "library"; //^
066        /**
067         * Describe variable <code>library</code> here.
068         *
069         */
070        protected AbstractLibrary library;
071        //static ResourceBundle resources = null;
072        /**
073         * Describes the quiz in progress, if any.
074         *
075         */
076        protected Quiz quiz;
077    
078        private Category cat
079            = Category.getInstance(AbstractPavlovApplication.class.getName());
080    
081        /**
082         * Manages Velocity feedback pluglets.
083         */
084        protected VelocityPlugletLoader velocityPlugins; 
085        /**
086         * Manages non-Velocity feedback pluglets.
087         *
088         */
089        protected PlugletLoader feedbackPlugins; // FIXED: can't be static
090        /**
091         * Manages question selection strategy pluglets.
092         *
093         */
094        protected StrategyLoader strategyPlugins;// FIXED: can't be static 
095        /**
096         * Manages tool pluglets.
097         *
098         */
099        protected PlugletLoader toolPluglets;    // FIXED: can't be static
100    
101    
102        protected ResourceBroker rb;
103        
104        /**
105         * Creates a new <code>AbstractPavlovApplication</code> instance.
106         *
107         * @param args[] a <code>String</code> value
108         */
109        protected AbstractPavlovApplication(final String args[])
110        {
111             rb = ResourceBroker.getInstance();
112             libraryFile = rb.getString(rb.LIBRARY_DIR);
113            // FIXME; should be in Pavlov.java
114            processArguments(args);
115            BasicConfigurator.configure();
116        }
117        
118        
119        protected void setup(){
120            showSplashScreen();
121            newSetStatus(33,rb.STATUS_LOADING_PLUGLETS);
122            loadPluglets();
123            newSetStatus(40,rb.STATUS_LOADING_LIBRARY);
124            library = loadLibrary();
125            newSetStatus(50,rb.STATUS_LOGGING_IN);
126            login(userName,password);
127        }
128    
129        // HERE
130            private void login(final User u){
131            if( u == null) return;  // FIXME: IllegalArgumentException?
132            //cat.debug("in step 2");
133            setUser(u);
134            newSetStatus(60, rb.STATUS_VALIDATING_STATISTICS);
135            validate(user, library);
136            //newSetStatus(70, rb.STATUS_CONFIGURING_THEMES);
137            //configureThemes();
138            newSetStatus(90, rb.STATUS_CREATING_LIBRARY_VIEW);
139            createQuizSelector();
140            loginFinished();
141            newSetStatus(95, rb.STATUS_CLOSING_SPLASH_SCREEN);
142            closeSplashScreen();
143        }
144    
145    
146        /**
147         * Describe <code>loginFinished</code> method here.
148         *
149         */
150        protected abstract void loginFinished();
151    
152        private void login(final String name, final String pass) {
153            User u = null;
154            if(name != null && pass != null) {
155                try { 
156                    LocalUserFile luf = new LocalUserFile(name);
157                    if(luf.exists()){
158                        u = luf.read(pass);
159                        if(u!=null){
160                            login(u);
161                            return;
162                        }
163                    }
164                } catch (Exception ex) {
165                    warn(rb.LOGIN_ERROR,ex);
166                    // fall through to u==null below
167                }
168            }
169    
170            if(u==null){
171                // FIXED: implement
172                showLoginController(this);
173            }
174    
175        }
176    
177        
178        protected abstract void showLoginController(AbstractPavlovApplication abs);
179        
180        protected void warn(String key,Exception ex){
181            cat.warn(rb.getString(key),ex);    
182        }
183        private void setUser(final User u) {
184            user = u;
185            setUserName(u.getName());
186            //setPassword(u.getPassword());
187        }
188    
189        // for logincontroller's callback
190        /**
191         * The LoginController calls this when the user has finished logging in.
192         *
193         * @param event a <code>LogonEvent</code> value
194         */
195        public void logonAttempt(final LogonEvent event)
196        {
197            login(event.getUser());
198        }
199    
200        /**
201         * Describe <code>getQuiz</code> method here.
202         *
203         * @return a <code>Quiz</code> value
204         */
205        public Quiz getQuiz()
206        {
207            return quiz;
208        }
209    
210        /**
211         * Describe <code>setQuiz</code> method here.
212         *
213         * @param q a <code>Quiz</code> value
214         */
215        public void setQuiz(final Quiz q)
216        {
217            quiz = q;
218            strategyPlugins.addStrategyListener(quiz);
219            quiz.setStrategy(strategyPlugins.getCurrentStrategy());
220        }
221    
222        /**
223         * Returns the library which is supplying questions.
224         *
225         * @return an <code>AbstractLibrary</code> value
226         */
227        public AbstractLibrary getLibrary()
228        {
229            return library;
230        }
231    
232        /**
233         * Asks the user if he's sure he wants to quit.  Delegates to 
234         * getUIBuilder.confirmQuit().
235         *
236         * @return a <code>boolean</code> value
237         */
238        protected abstract boolean confirmQuit();
239    
240        /**
241         * Creates the UI widget that allows the user to select a chapter to
242         * start a quiz.
243         *
244         */
245        public abstract void createQuizSelector();
246        /**
247         * Returns the active user.
248         *
249         * @return an <code>User</code> value
250         */
251        public final User getUser() { return user; }
252    
253    
254    
255    
256    
257        //=============================================================
258        // override these methods for client-server versions
259        /**
260         * Coordinates the users question data with question in the
261         * active library.
262         *
263         * @param u an <code>User</code> value
264         * @param l an <code>AbstractLibrary</code> value
265         */
266        protected void validate(User u, AbstractLibrary l)
267        {
268            assert u != null : rb.getString(rb.USER_NULL);//"User is null!";
269            assert l != null : rb.getString(rb.LIBRARY_NULL);//"Library is null!";
270            u.validate(l);
271        }
272    
273        /**
274         * Reads in the library.
275         *
276         * @return an <code>AbstractLibrary</code> value
277         */
278        protected final AbstractLibrary loadLibrary()
279        {
280            return LibraryLoader.loadLibrary(libraryFile);
281        }
282    
283    
284        /**
285         * Returns the named resource value or the given default, if the
286         * resource value is unavailable.
287         *
288         * @param key a <code>String</code> value
289         * @param def a <code>String</code> value
290         * @return a <code>String</code> value
291         */
292        public String getResourceString(final String key, final String def)
293        {
294            return rb.getString(key,def);
295        }
296    
297        /**
298         * Loads all the feedback, strategy, and tool pluglets.
299         *
300         */
301        public abstract void loadPluglets();
302    
303        //=============================================================
304      
305    
306        /**
307         * Shows the user startup status, delegates to getUIBuilder()'s setStatus.
308         *
309         * @param pos an <code>int</code> value
310         * @param msg a <code>String</code> value
311         */
312        public abstract void setStatus(final int pos, final String msg);
313    
314        public abstract void newSetStatus(final int pos, final String key);
315    
316        
317        /**
318         * Keep the user entertained and informed during startup.
319         *
320         */
321        protected abstract void showSplashScreen();
322    
323    
324        /**
325         * Called when startup is finished, delegates to UIBuilder's 
326         * closeSplashScreen.
327         *
328         */
329        protected abstract void closeSplashScreen();
330    
331    
332        /**
333         * Sets the user name, useful only before login.
334         *
335         * @param na a <code>String</code> value
336         */
337        public final void setUserName(final String na) {
338            userName = na;
339        }
340    
341        /**
342         * Sets the user password, useful only before login.
343         *
344         * @param na a <code>String</code> value
345         */
346        public final void setPassword(final String na) {
347            password = na;
348        }
349    
350        /**
351         * Sets the feedbackpluglets as answerListeners for the quiz.
352         *
353         * @param theQuiz a <code>Quiz</code> value
354         */
355        public void registerFeedbackPlugins(Quiz theQuiz)
356        {
357                if(feedbackPlugins!=null) {
358                    feedbackPlugins.addToAnswerEventProducer(theQuiz);
359                }
360                if(velocityPlugins!=null){
361                    velocityPlugins.addToAnswerEventProducer(theQuiz);
362                }
363        }
364    
365    
366        /**
367         * Process command line arguments.
368         *
369         * @param args a <code>String[]</code> value
370         */
371        public void processArguments(final String[] args)
372        {
373            if(args==null) return;
374            for (String x : args) {
375                if (x.startsWith("-u=") || x.startsWith("--user=")) {
376                    String s = x.substring(x.indexOf('=') + 1);
377    
378                    setUserName(s);
379                } else if (x.startsWith("-p=") || x.startsWith("--password=")) {
380                    String s = x.substring(x.indexOf('=') + 1);
381    
382                    setPassword(s);
383                } else if (x.startsWith("-h") || x.startsWith("--help")) {
384                    String s = "\njava -jar pavlov-1.1.jar";
385    
386                    System.out.println(s);
387                    System.out.println("     -h --help              Show this help info");
388                    System.out.println("     -u=name --user=name    Specify user");
389                    System.out.println("     -p=pass --password=pw  Specify password");
390                }
391            }
392        }
393    
394        /**
395         * Save's the user's progress.
396         *
397         */
398        public final void saveUser()
399        {
400            try { 
401                user.save();
402            } catch (Exception ex) {
403                warn(rb.USER_SAVING_ERROR, ex);
404            }
405        }
406    
407        /**
408         * Ask the user if he really wants to quit.
409         *
410         * @param confirm a <code>boolean</code> value
411         */
412        public final void niceQuit(boolean confirm)
413        {
414                if(confirm){
415                        if( !confirmQuit()) return;
416                        saveUser();
417                }
418            System.exit(0);
419        }
420    
421    
422        /**
423         * Show the user that his answer was incorrect.
424         *
425         * @param msg a <code>String</code> value
426         */
427        public abstract void showIncorrectDialog(String msg);
428    
429    }
430