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