1
2
3
4 package org.telscenter.sailotrunk;
5
6 import java.awt.Dimension;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.WindowAdapter;
10 import java.awt.event.WindowEvent;
11 import java.beans.beancontext.BeanContextServices;
12 import java.io.ByteArrayInputStream;
13 import java.io.ByteArrayOutputStream;
14 import java.io.File;
15 import java.io.StringReader;
16 import java.net.URL;
17 import java.util.TimerTask;
18 import java.util.TooManyListenersException;
19 import java.util.logging.Logger;
20
21 import javax.swing.AbstractAction;
22 import javax.swing.Action;
23 import javax.swing.JFileChooser;
24 import javax.swing.JFrame;
25 import javax.swing.JOptionPane;
26 import javax.swing.JScrollPane;
27 import javax.swing.JTextArea;
28 import java.util.Timer;
29
30 import net.sf.sail.common.beansupport.ITitleAware;
31 import net.sf.sail.common.beansupport.SailBeanContextChildSupport;
32 import net.sf.sail.core.beans.event.SessionEvent;
33 import net.sf.sail.core.beans.event.SessionEventListener;
34 import net.sf.sail.core.beans.service.AgentService;
35 import net.sf.sail.core.beans.service.SessionService;
36 import net.sf.sail.core.entity.IAgent;
37 import net.sf.sail.core.entity.ISock;
38 import net.sf.sail.core.entity.MismatchedAgentSetSizeException;
39 import net.sf.sail.core.entity.Rim;
40 import net.sf.sail.core.entity.Role;
41 import net.sf.sail.core.entity.UnsupportedRimShapeException;
42
43 import org.concord.framework.otrunk.OTObject;
44 import org.concord.framework.otrunk.view.OTViewEntry;
45 import org.concord.framework.otrunk.view.OTViewFactory;
46 import org.concord.otrunk.OTMLToXHTMLConverter;
47 import org.concord.otrunk.datamodel.OTDatabase;
48 import org.concord.otrunk.view.OTConfig;
49 import org.concord.otrunk.view.OTViewChild;
50 import org.concord.otrunk.view.OTViewer;
51 import org.concord.otrunk.view.OTViewerHelper;
52 import org.concord.otrunk.xml.XMLDatabase;
53
54 /***
55 * Bean which should be the root bean of the curnit.
56 * It starts up the OTViewer and saves its data into a rim.
57 *
58 * @author scytacki
59 */
60 public class SailOTViewer extends SailBeanContextChildSupport
61 implements ITitleAware, OTPodAdapter
62 {
63 private static final String EXPORT_HTML_DIALOG_TAG = "_dialog_";
64
65 public static final String SAILOTRUNK_VIEW_LEARNEROTML = "sailotrunk.learnerotml.edit";
66
67 public static final String SAILOTRUNK_OTMLURL = "sailotrunk.otmlurl";
68
69 public static final String SAILOTRUNK_EXPORT_HTML = "sailotrunk.export.html";
70
71 static {
72
73
74 System.setProperty("apple.laf.useScreenMenuBar","true");
75 }
76
77 /***
78 * Logger for this class
79 */
80 private static final Logger logger = Logger.getLogger(SailOTViewer.class
81 .getName());
82
83 private static final long serialVersionUID = 1L;
84
85 private URL authoredDataURL;
86
87 private AgentService agentService;
88 private SessionService sessionService;
89
90 private Rim workRim;
91
92 private ISock workSock;
93
94 private boolean hideTree = false;
95 private int userMode = 0;
96
97 OTViewer viewer = null;
98 OTViewerHelper viewerHelper = new OTViewerHelper();
99
100 private JTextArea xmlTextArea;
101
102 SessionEventListener sessionListener = new SessionEventListener() {
103
104 private Timer timer;
105
106 public void sessionStarted (SessionEvent e) {
107 }
108
109 public void sessionInitiated (SessionEvent e)
110 {
111 String boolStr = sessionService.getProperty(SAILOTRUNK_VIEW_LEARNEROTML, "false");
112 boolean showLearnerOtmlAsText = Boolean.parseBoolean(boolStr);
113 if (showLearnerOtmlAsText){
114 loadDataAsText();
115 return;
116 }
117
118 String exportHtmlFolderStr = sessionService.getProperty(SAILOTRUNK_EXPORT_HTML, null);
119 if (exportHtmlFolderStr != null){
120 exportHtml(exportHtmlFolderStr);
121 return;
122 }
123
124
125 viewer = new OTViewer();
126
127 viewer.addService(OTPodAdapter.class, SailOTViewer.this);
128
129 viewer.setUserMode(getUserMode());
130
131 String authoredDataUrlStr = getAuthoredDataUrlStr();
132
133 viewer.init(authoredDataUrlStr);
134
135 AbstractAction exitAction = new AbstractAction(){
136 /***
137 * Not intended to be serialized, just added remove compile warning
138 */
139 private static final long serialVersionUID = 1L;
140
141 public void actionPerformed(ActionEvent e) {
142 if (timer != null) {
143 timer.cancel();
144 }
145 viewer.getViewContainerPanel().setCurrentObject(null);
146 saveDataInternal();
147
148 getSessionService().userRequestsTermination();
149 }
150 };
151 exitAction.putValue(Action.NAME, "Exit");
152
153 viewer.setExitAction(exitAction);
154
155 viewer.updateMenuBar();
156
157 if(viewer.getUserMode() == OTViewerHelper.NO_USER_MODE){
158
159
160 return;
161 }
162
163 timer = new Timer();
164 long delay = 60*1000;
165 timer.scheduleAtFixedRate(new TimerTask() {
166 @Override
167 public void run() {
168
169 saveDataInternal();
170 }
171 }, delay, delay);
172
173 XMLDatabase sailLearnerDB = getLearnerDatabase();
174 try {
175 if(sailLearnerDB != null){
176 viewer.loadUserDataDb(sailLearnerDB, null);
177 ((XMLDatabase)sailLearnerDB).setDirty(false);
178 } else {
179 viewer.newAnonUserData();
180 }
181 } catch (Exception e1) {
182
183 e1.printStackTrace();
184 }
185 }
186
187 public void sessionStopped(SessionEvent e) {
188 saveDataInternal();
189 }
190
191 };
192
193 private boolean needsSockEntryInit = true;
194
195 /***
196 * This allows us to view the learner data sent from the SDS as a plain-text file,
197 * which we can then edit by hand. Closing the file will then attempt to save the
198 * modified OTML learner data back to the SDS as a new bundle.
199 *
200 * Warning: No attempt is made to verify the XML, so no guarantees are given if
201 * uploading of bad XML is attempted.
202 *
203 * @author sfentress
204 */
205 private void loadDataAsText(){
206 final ISock sock = getWorkSock();
207
208 Object lastEntry = null;
209 if(sock != null && sock.size() > 0){
210 lastEntry = sock.peek();
211 }
212
213 if (lastEntry == null){
214 System.err.println("Error loading data");
215 return;
216 }
217
218 String dataString = null;
219 if (lastEntry instanceof String){
220 dataString = (String)lastEntry;
221 } else if(lastEntry instanceof byte[]){
222 dataString = new String((byte[])lastEntry);
223 }
224
225 xmlTextArea = new JTextArea();
226 xmlTextArea.setLineWrap(true);
227 xmlTextArea.setWrapStyleWord(true);
228
229 xmlTextArea.setText(dataString);
230
231 final JFrame frame = new JFrame();
232
233 frame.addWindowListener(new WindowAdapter() {
234 public void windowClosing(WindowEvent e)
235 {
236 int saveData = JOptionPane.showConfirmDialog(
237 frame, "Upload modified bundle?", "Confirm", JOptionPane.YES_NO_OPTION);
238
239 if (saveData == JOptionPane.YES_OPTION){
240 getSessionService().userRequestsTermination();
241 }
242 }
243 });
244
245 JScrollPane scrollPane = new JScrollPane();
246 scrollPane.setViewportView(xmlTextArea);
247 xmlTextArea.setCaretPosition(0);
248 frame.add(scrollPane);
249 frame.setPreferredSize(new Dimension(400,400));
250 frame.pack();
251 frame.setVisible(true);
252 }
253
254 protected void exportHtml(String exportHtmlFolder) {
255 try{
256 File fileToSave = null;
257
258 if(EXPORT_HTML_DIALOG_TAG.equals(exportHtmlFolder)){
259 JFileChooser fileChooser = new JFileChooser();
260 int result = fileChooser.showSaveDialog(null);
261 switch(result){
262 case JFileChooser.APPROVE_OPTION:
263 fileToSave = fileChooser.getSelectedFile();
264 case JFileChooser.CANCEL_OPTION:
265 case JFileChooser.ERROR_OPTION:
266 break;
267 }
268 }
269
270 viewerHelper.addService(OTPodAdapter.class, SailOTViewer.this);
271
272 viewerHelper.setUserMode(getUserMode());
273
274 String authoredDataUrlStr = getAuthoredDataUrlStr();
275
276 URL authoredContentURL = new URL(authoredDataUrlStr);
277 viewerHelper.loadAuthoredContentURL(authoredContentURL);
278
279 if(viewerHelper.getUserMode() == OTViewerHelper.NO_USER_MODE){
280
281
282 } else {
283 XMLDatabase learnerDatabase = getLearnerDatabase();
284 if(learnerDatabase != null){
285 viewerHelper.loadUserData(learnerDatabase, null);
286 }
287 }
288
289 OTObject rootObject = viewerHelper.getRootObject();
290
291 OTViewEntry rootViewEntry = null;
292 if(rootObject instanceof OTViewChild){
293 rootViewEntry = ((OTViewChild)rootObject).getViewid();
294 rootObject = ((OTViewChild)rootObject).getObject();
295 }
296 OTViewFactory viewFactory = viewerHelper.getViewFactory();
297
298 final OTMLToXHTMLConverter conv = new OTMLToXHTMLConverter(viewFactory, rootObject,
299 rootViewEntry,
300 OTConfig.getSystemPropertyViewMode());
301
302 if(fileToSave == null) {
303 String outputFolderStr = exportHtmlFolder;
304 if(outputFolderStr == null){
305 outputFolderStr = System.getProperty("user.home");
306 }
307 File outputFolder = new File(outputFolderStr);
308 outputFolder.mkdirs();
309 fileToSave = new File(outputFolder, "index.html");
310 }
311
312 conv.setXHTMLParams(fileToSave, 800, 600);
313
314 Thread runner = new Thread(){
315 public void run() {
316 conv.run();
317 System.exit(0);
318 }
319
320 };
321
322 runner.start();
323 }
324 catch (Exception ex) {
325 ex.printStackTrace();
326 }
327 }
328
329
330 protected void registerDesiredServices(BeanContextServices bcs) {
331 }
332
333
334 /***
335 * This method can be called more than once in the authoring runtime, when
336 * the preview is shown more than once.
337 *
338 * @param bcs
339 * @param serviceClass
340 * @param project
341 */
342 @Override
343 protected void consumeService(BeanContextServices bcs, Class serviceClass) {
344 if (serviceClass == SessionService.class) {
345 try {
346 sessionService = (SessionService) bcs.getService(this, this,
347 SessionService.class, this, this);
348
349 sessionService.addSessionEventListener(sessionListener);
350 } catch (TooManyListenersException e1) {
351
352 logger
353 .severe("BeanContextServices, Class - : exception: " + e1);
354 }
355 }
356 if (serviceClass == AgentService.class)
357 {
358 try
359 {
360 final AgentService p = (AgentService) bcs.getService(this,
361 this, AgentService.class, this, this);
362 agentService = p;
363 }
364 catch (TooManyListenersException e)
365 {
366 e.printStackTrace();
367 }
368 }
369 }
370
371 /***
372 * @return the sessionService
373 */
374 public SessionService getSessionService() {
375 return sessionService;
376 }
377
378 /***
379 * @param sessionService the sessionService to set
380 */
381 public void setSessionService(SessionService sessionService) {
382 this.sessionService = sessionService;
383 }
384
385 protected ISock getRimSock(Rim rim)
386 {
387 ISock sock = null;
388 if (rim != null)
389 {
390 try {
391 IAgent agent = agentService.getAgentsInRole(Role.RUN_WORKGROUP).getSingle();
392 sock = agentService.getSock(rim, agent);
393 } catch (MismatchedAgentSetSizeException e) {
394
395 e.printStackTrace();
396 } catch (UnsupportedRimShapeException e) {
397
398 e.printStackTrace();
399 }
400 }
401 return sock;
402 }
403
404 public Rim getWorkRim() {
405 return workRim;
406 }
407
408 public void setWorkRim(Rim workRim) {
409 this.workRim = workRim;
410 }
411
412 public ISock getWorkSock() {
413 if (workSock == null) {
414 workSock = getRimSock(getWorkRim());
415 }
416 return workSock;
417 }
418
419
420 public URL getAuthoredDataURL()
421 {
422 return authoredDataURL;
423 }
424
425 public void setAuthoredDataURL(URL url)
426 {
427 authoredDataURL = url;
428 }
429
430 public String getTitle() {
431 return "SailOTViewer title";
432 }
433
434
435 public void setTitle(String title) {
436 }
437
438
439 public boolean isHideTree() {
440 return hideTree;
441 }
442
443
444 public void setHideTree(boolean hideTree) {
445 this.hideTree = hideTree;
446 }
447
448
449 public int getUserMode() {
450 return userMode;
451 }
452
453
454 public void setUserMode(int userMode) {
455 this.userMode = userMode;
456 }
457
458 private void saveDataInternal() {
459 saveDataInternal(true);
460 }
461
462 private void saveDataInternal(boolean replace)
463 {
464 if (needsSockEntryInit ) {
465
466 replace = false;
467 }
468
469 ISock sock = getWorkSock();
470
471
472
473 String boolStr = sessionService.getProperty(SAILOTRUNK_VIEW_LEARNEROTML, "false");
474 boolean showLearnerOtmlAsText = Boolean.parseBoolean(boolStr);
475 if (showLearnerOtmlAsText){
476 if(getWorkRim().getShape() == byte[].class){
477 sock.add(xmlTextArea.getText().getBytes(), replace);
478 } else {
479 sock.add(xmlTextArea.getText(), replace);
480 }
481 return;
482 }
483
484 OTDatabase userDB = viewer.getUserDataDb();
485
486 if(userDB == null){
487
488 return;
489 }
490
491
492
493 if(userDB instanceof XMLDatabase &&
494 !((XMLDatabase)userDB).isDirty()){
495 return;
496 }
497
498 try {
499 if(sock != null && userDB != null){
500
501
502
503
504
505 if(getWorkRim().getShape() == byte[].class){
506 ByteArrayOutputStream out = new ByteArrayOutputStream();
507 viewerHelper.saveOTDatabase(userDB, out);
508 byte [] bytes = out.toByteArray();
509 sock.add(bytes, replace);
510 if(userDB instanceof XMLDatabase){
511 ((XMLDatabase)userDB).setDirty(false);
512 }
513 } else {
514 String userData = viewerHelper.saveOTDatabase(userDB);
515 sock.add(userData, replace);
516 }
517 needsSockEntryInit = false;
518 } else {
519 System.err.println("No sock in OTrunkStep - cannot save data");
520 }
521
522 } catch (Exception e1) {
523
524 e1.printStackTrace();
525 }
526
527 }
528
529 /***
530 * @see OTPodAdapter.registerBean()
531 */
532 @SuppressWarnings("unchecked")
533 public void registerBean(Object bean) {
534 getBeanContext().add(bean);
535 }
536
537
538 private String getAuthoredDataUrlStr() {
539 String authoredDataUrlStr = getAuthoredDataURL().toExternalForm();
540
541
542 String authoredDataConfigUrlStr =
543 sessionService.getProperty(SAILOTRUNK_OTMLURL, null);
544
545
546
547
548
549 if(authoredDataConfigUrlStr != null) {
550 authoredDataUrlStr = authoredDataConfigUrlStr;
551 }
552 return authoredDataUrlStr;
553 }
554
555 private XMLDatabase getLearnerDatabase() {
556
557 ISock sock = getWorkSock();
558
559 Object lastEntry = null;
560 if(sock != null && sock.size() > 0){
561 lastEntry = sock.peek();
562 }
563
564 if(lastEntry == null){
565 return null;
566 }
567
568 try {
569 if(lastEntry instanceof String) {
570 StringReader reader = new StringReader((String)lastEntry);
571
572
573
574 return (XMLDatabase) viewerHelper.loadOTDatabase(reader, null);
575
576 } else if(lastEntry instanceof byte[]){
577 ByteArrayInputStream inStream = new ByteArrayInputStream((byte[])lastEntry);
578
579 return (XMLDatabase) viewerHelper.loadOTDatabase(inStream, null);
580 }
581
582 } catch (Exception exp) {
583 exp.printStackTrace();
584 }
585
586 return null;
587 }
588
589 }