Source code: org/mitre/cvw/DSIController.java
1 /*
2 * Copyright (c) 1996-2000. The MITRE Corporation (http://www.mitre.org/).
3 * All rights reserved.
4 * CVW comes with ABSOLUTELY NO WARRANTY. See license for details.
5 */
6
7 package org.mitre.cvw;
8
9 import java.io.*;
10 import java.net.*;
11 import java.util.Date;
12 import java.util.Vector;
13
14 import org.mitre.cvw.docserv.DocServException;
15
16 import org.mitre.cvw.docserv.AttributeSignature;
17 import org.mitre.cvw.docclnt.DocFactory;
18
19 /**
20 * A shell class to handle launching of DocServer threads.
21 * Other classes wishing to control the Document Server and get
22 * information should funnel all calls through this shell.
23 *
24 * This class also deals with user-interface issues and error
25 * reporting. The calling routine can call into here and never worry
26 * again about what happens. This allows DSIController to run multiple
27 * document server threads and control the results.
28 *
29 * In beginning, the document server availability was also tied to the
30 * availability of the Netscape plugin (NPDocServer), since this client
31 * was an applet. Now that it is an application, the availability of the
32 * plugin is not relevant but the code dependency has not been removed.
33 *
34 * 8/23/00 SRJ MAJOR REWRITE!!!
35 * Added a level above this class (DocumentServerList) to incorporate federation
36 * Did a lot of cleanup and changing. Basically, made this class more of a
37 * container for each document server encountered. The main entry point will
38 * now be DocumentServerList
39 * @version 1.0
40 * @author Marc N. Cannava
41 * @author S.R.Jones
42 */
43 public class DSIController extends Object implements ObjectValues {
44
45 protected String DSHost; // The base DocServer host
46 protected String DSUrl; // The docservlet url
47 protected int DSPort; // The base DocServer port
48 private static String CheckDir; // The base checkout directory
49 // private static String UserName = "unknown"; // The current user name using the client
50 private static String PROTOCOL = "http"; // define the protocol to connect to DS
51
52 static CVWCoordinator jcvw = CVWCoordinator.getInstance(); // Pointer to CVW Coordinator object
53 static NPDocServer plugin = NPDocServer.getInstance();
54 DocFactory factory = null; // the default factory constructor
55
56 static Vector runTable = new Vector(); // List of running DSI's
57 static Vector runThreads = new Vector(); // List of running DSI threads
58 static Vector docIDTable = new Vector(); // List of docID's w/ops-in-progress
59
60 DSIParms resultParms; // Holds result for sync() calls
61 // static Object blockObject; // Indicator for thread completion
62 //Thread runThread; // The thread this object is running on
63
64 private boolean available = true;
65 private static boolean firstTime = true;
66
67 /* **********************************
68 * 4/6/98 dage -- static/class methods
69 */
70
71 /**
72 * Returns whether connectivity to the document server is available.
73 * @return whether connectivity to the document server is available
74 */
75 public boolean isAvailable() {
76 return available;
77 }
78
79 /**
80 * Returns teh current instance of this class, instantiates it if first time thru.
81 * @return the current instance
82 *
83 public static DSIController getInstance(){
84 if (currentDSI == null && available)
85 initDocServerCheck();
86 return currentDSI;
87 }
88 */
89
90 /**
91 * Checks to see if document server connectivity is available.
92 * @return <code>true</code> if document server connectivity is available
93 */
94 private boolean initDocServerCheck(URL location) {
95 boolean result = false;
96 if(firstTime) {
97 if(CVWCoordinator.DEBUG) System.err.println("DSI: First time thru, initting dsi...");
98 try {
99 initDocServerInterface(location);
100 result = true;
101 } catch (CheckoutDirectoryException e) {
102 checkoutDirNotAvailable();
103 //return;
104 } catch (Throwable e) {
105 System.err.println(e);
106 docGenericError();
107 //return;
108 }
109 }
110 available = result;
111 return result;
112 }
113
114 /**
115 * Initializes the single instance of this class, checks to make sure
116 * connectivity to the document server is available, the user checkout dir
117 * exists and tries to start its own thread.
118 * @exception CheckoutDirectoryException
119 * @exception Throwable
120 */
121 private void initDocServerInterface(URL location) throws CheckoutDirectoryException, Throwable {
122
123 if(CVWCoordinator.DEBUG) System.err.println("IDSI: Plugin is initted to: "+plugin);
124 if (location == null) throw new ConnectException("Cannot connect to null docserver");
125
126 DSHost = location.getHost();
127 DSUrl = location.getFile();
128 DSPort = location.getPort();
129
130 if (DSHost == null)
131 jcvw.displayError("There was no CVW document server specified in your CVW server configuration file. Document features are unavailable.",
132 "CVW Document Server Problem", false);
133
134 /* 8/7/98 dage - added the following block to see if dshost and dsport are
135 * even valid
136 */
137 try {
138 Socket s = new Socket(DSHost, DSPort);
139 } catch (Exception v) {
140 if (v instanceof UnknownHostException) {
141 String host = v.getMessage();
142 jcvw.displayError("You are trying to connect to a document server with name: "
143 + host + ". Document features are unavailable. Please check your configurtion file.",
144 "Unknown CVW Document Server", false);
145 } else if (v instanceof ConnectException) {
146 jcvw.displayError("There is a problem connecting to CVW document server: " +
147 DSHost + ":" + DSPort + ". Document features are unavailable.",
148 v.getMessage(), false);
149 } else {
150 if (DSHost == null)
151 jcvw.displayError("There was no CVW document server specified in your CVW server configuration file. Document features are unavailable.",
152 "CVW Document Server Problem", false);
153 else
154 jcvw.displayError("There is a problem connecting to CVW document server: " +
155 DSHost + ":" + DSPort + ". Document features are unavailable.",
156 "CVW Document Server Problem", false);
157 v.printStackTrace();
158 }
159 throw v;
160 }
161
162 try {
163 if(CVWCoordinator.DEBUG) System.err.println("Calling the dsi constructor..");
164 String name = new String();
165 //if (currentUser != null)
166 //name = currentUser.name;
167 //currentDSI=new DSIController(0); //dont use the null parm constructor
168 //Thread dsiThread = new Thread(currentDSI);
169 //dsiThread.start();
170 // } catch (CheckoutDirectoryException exc) {
171 // if(CVWCoordinator.DEBUG) System.err.println("INIT DSI EXCEPTION: "+exc);
172 // throw exc;
173 } catch (Throwable exc) {
174 if(CVWCoordinator.DEBUG) System.err.println("INIT DSI GENERAL EXCEPTION: "+exc);
175 throw exc;
176 }
177
178 }
179
180 /**
181 * Checks to see if user is currently editing documents, if so warns them,
182 * and user can cancel logout.
183 * @return <code>true</code> if the logout process should be continued
184 * @exception CheckoutDirectoryException
185 * @exception Throwable
186 */
187 public boolean docServerLogout() {
188
189 OkCancelDialog okc;
190 DSIParms dsp=null;
191 DocServerInterface tdsi = new DocServerInterface(this);
192 String docNames = new String();
193 String name = new String();
194 int x;
195 String msg = null;
196
197 syncWithDocServer(); //clean up cache directory
198
199 try {
200 dsp=startDSSyncOp(USERSTAT, null);
201 Vector cd = dsp.vectorResult;
202
203 // Get the names. Since we've sync'ed w/ the docserver, use the DSDB file for this info
204 // we just did this with syncWithDocServer above, but don't know a better way right now
205 DSDB localDB = new DSDB(CheckDir, plugin);
206
207 int coCount = cd.size();
208 for (int i=0; i<localDB.getCount(); i++) {
209 try {
210 DSDBEntry entry = localDB.getNextEntry();
211 if (entry.ReadWrite() &&
212 (entry.getServer().equals(CVWCoordinator.getInstance().getServerName()))) {
213 // true, so doc is checked out
214 docNames = docNames + "\"" + entry.Name() + "\" ";
215 } else
216 coCount--;
217 } catch (DBEntryNotFoundException enfe) {} // error reading DSDB file
218 }
219
220
221 docNames = "(" + docNames.trim() + ")";
222 //if (jcvw.DEBUG) System.err.println(docNames);
223
224 if(coCount > 0) {
225 msg = "You are currently working on "+coCount+" document(s) "+docNames+". In order to continue working with those documents, your next login must be on the same machine. If you login from another machine, your changes to those documents will be discarded.";
226 }
227 } catch (DocInUseException e) {
228 msg = "If you are currently working on any documents, in order to continue working with those documents, your next login must be on the same machine. If you login from another machine, your changes to those documents will be discareded.";
229 }
230
231 if (msg == null) return true;
232
233 okc=new OkCancelDialog(jcvw, msg, true, "Documents Opened for Editing", OkCancelDialog.WARNING, OkCancelDialog.OKCANCEL);
234 okc.pack(); okc.setVisible(true);
235 if(okc.cancel) return false;
236 return true;
237 }
238
239 /**
240 * Synchronize the user's local database file with the information on the
241 * document server.
242 * @exception CheckoutDirectoryException
243 * @exception Throwable
244 * @see #verifyCache
245 */
246 public void syncWithDocServer() {
247 try {
248 verifyCache();
249 } catch (DocServException d) {
250 displayError("Couldn't complete verification because the document server did not respond.");
251 }
252 }
253
254 /**
255 * Preforms the right mouse menu functions on the specified document.
256 * @param document the document to perform the function on
257 * @param function the right mouse menu function
258 * @return <code>true</code> if the function was performed successfully
259 * @exception CheckoutDirectoryException
260 * @exception Throwable
261 *
262 * @see #startDSOp
263 */
264 public boolean doDocMenu(CVWDocument document, String function) {
265
266 Integer docID;
267 docID = new Integer(document.docID);
268 DSIParms indsip= new DSIParms();
269 DSIParms outdsip;
270 indsip.name = document.name;
271 indsip.docID = docID;
272
273 if(CVWCoordinator.DEBUG) System.err.print("DocID is: "+docID + " ");
274
275 if(function.startsWith("Open")) {
276 indsip.doOpen=false;
277 indsip.context = null; // this happened when we changed to application
278 try {
279 if(document.isShortcut())
280 indsip.shortcut=true;
281 else
282 indsip.shortcut=false;
283 int indx = startDSOp(DOCOPEN, indsip);
284 } catch (DocInUseException e) {
285 e.printStackTrace();
286 displayDocServInUseError();
287 return false;
288 }
289 return true;
290 }
291
292 if(function.startsWith("Export")) {
293 String path = plugin.fileBrowse("Export File", "Save", document.name);
294 if (path == null)
295 return false;
296
297 if (plugin.fileExists(path)) {
298 plugin.removeFile(path); // if not removed then over write doesnt quite work.
299 }
300
301 indsip.path = path;
302 try {
303 startDSOp(DOCEXPORT, indsip);
304 jcvw.displayPrvSysMsg("\"" + document.name + "\" is now stored locally on your workstation as " + path + ".");
305 return true;
306 } catch (DocInUseException e) {
307 displayDocServInUseError();
308 return false;
309 }
310 }
311
312 if(function.startsWith("Check Out")) {
313 try {
314 startDSSyncOp(CHECKOUT, indsip);
315 // track locally that it's checked out
316 document.setCheckOut(true);
317 return true;
318 } catch (DocInUseException e) {
319 e.printStackTrace();
320 displayDocServInUseError();
321 return false;
322 }
323 }
324
325 indsip.objNum = document.objNum.strValue();
326 if(function.startsWith("Save Changes")) {
327 try {
328 startDSOp(DOCCHECKIN, indsip);
329 // track that's the doc's checked in
330 //9/13/98 dage - not here ... document.setCheckOut(false);
331 return true;
332 } catch (DocInUseException e) {
333 displayDocServInUseError();
334 return false;
335 }
336
337 }
338
339 if(function.startsWith("Discard Changes")) {
340 try {
341 startDSOp(REVERT, indsip);
342 //9/13/98 dage - not here ... document.setCheckOut(false);
343 return true;
344 } catch (DocInUseException e) {
345 displayDocServInUseError();
346 return false;
347 }
348 }
349
350 if(function.startsWith("Delete")) {
351 System.err.println("in doDocMenu funct=Delete");
352 return doDocDelete(document.objNum.strValue(), docID, false);
353 }
354
355 return false;
356 }
357
358 /**
359 * Deletes the specified document from the document server.
360 * @param objNum the object number of the document
361 * @param docID the document id of the document
362 * @param finalTime whether this is the final time that the document has
363 * been requested to delete, not final time means the user just requested
364 * the deletion and some initial checks have to be made
365 * @return whether the delete was successfull
366 * @exception CheckoutDirectoryException
367 * @exception Throwable
368 */
369 public boolean doDocDelete(String objNum, int docID, boolean finalTime) {
370 System.err.println("in doDocDelete: String, int, boolean, DocToken");
371 return doDocDelete(objNum, new Integer(docID), finalTime);
372 }
373
374
375 /**
376 * Deletes the specified document from the document server.
377 * @param objNum the object number of the document
378 * @param docID the document id of the document
379 * @param finalTime whether this is the final time that the document has
380 * been requested to delete, not final time means the user just requested
381 * the deletion and some initial checks have to be made
382 * @return whether the delete was successfull
383 * @exception CheckoutDirectoryException
384 * @exception Throwable
385 */
386 public boolean doDocDelete(String objNum, Integer docID, boolean finalTime) {
387 String error_msg = "none";
388 DSIParms indsip=new DSIParms();
389 indsip.docID = docID;
390 DSIParms outdsip;
391
392 System.err.println("doDocDelete: finalTime is " + finalTime);
393
394 if (finalTime) {
395 try {
396 outdsip=startDSSyncOp(DOCDELETE,indsip);
397 if(outdsip.exc != null) throw outdsip.exc;
398 } catch (DocServException d) {
399 displayError(d.toString());
400 return false;
401 } catch (DocInUseException d) {
402 displayDocServInUseError();
403 return false;
404 }
405 return true;
406 } else {
407 String status = "None";
408 try {
409 outdsip=startDSSyncOp(DOCSTATUS,indsip);
410 if(outdsip.exc != null) throw outdsip.exc;
411 status = outdsip.stringResult;
412 } catch (DocServException d) {
413 if(CVWCoordinator.DEBUG) System.err.println("DocServException (delete)");
414 error_msg = d.toString();
415 } catch (DocInUseException d) {
416 if(CVWCoordinator.DEBUG) System.err.println("INUSEEXCEPTION (delete)");
417 error_msg = "Document services are in process. Please wait for the last action to complete and try again.";
418 }
419 if (error_msg.equals("none"))
420 if (status.startsWith("None"))
421 return true;
422 else {
423 if(CVWCoordinator.DEBUG) System.err.println("status is "+status);
424 displayError(" You are currently working on that document, so it could not be deleted. Either save or discard your changes before deleting.");
425 }
426 else
427 displayError(error_msg);
428 return false;
429 }
430 }
431
432 /**
433 * Returns a new document id needed when copying an existing document.
434 * @param docid the document id of the document to be copied
435 * @return the new document id
436 * @exception CheckoutDirectoryException
437 * @exception Throwable
438 */
439 public int getNewDocID(String docid) {
440
441 Integer newDocId = new Integer("0");;
442 DSIParms inparm = new DSIParms();
443 DSIParms outparm;
444 String name = "Item";
445
446 int newID = 0;
447
448 try {
449 inparm.docID = new Integer(docid);
450 outparm=startDSSyncOp(DOCCOPY, inparm);
451 if(outparm.exc != null) throw outparm.exc;
452 newDocId = outparm.integerResult;
453 newID = newDocId.intValue();
454 } catch (DocServException d) {
455 displayError(d.toString());
456 //newID = 0;
457 } catch (DocInUseException e) {
458 displayDocServInUseError();
459 //newID = 0;
460 }
461 return newID;
462 }
463
464
465 /**
466 * Checks to see if the document specified can be accessed and is not busy.
467 * @param docID the document to be checked
468 * @return <code>true</code> if the document can be accessed
469 * @exception CheckoutDirectoryException
470 * @exception Throwable
471 */
472 public boolean documentIsBusy(String docID) {
473 DSIParms inparm,outparm;
474 inparm = new DSIParms();
475 try {
476 inparm.docID = new Integer(docID);
477 outparm=startDSSyncOp(DOCBUSY, inparm);
478 if(outparm.exc != null) throw outparm.exc;
479 } catch (DocServException d) {
480 displayError(d.toString());
481 return true;
482 } catch (DocInUseException e) {
483 e.printStackTrace();
484 displayDocServInUseError();
485 return true;
486 }
487 return false;
488 }
489
490
491 /**
492 * Displays the standard error that the document server is currently busy.
493 * @exception CheckoutDirectoryException
494 * @exception Throwable
495 */
496 public static void displayDocServInUseError() {
497 displayError("Document services here are in process. Please wait for the last action to complete and try again.");
498 }
499
500 /**
501 * Displays the standard error that the document server is not installed.
502 * Note: this was pertinent when the doc server availability was tied to the
503 * Netscape plugin.
504 * @exception CheckoutDirectoryException
505 * @exception Throwable
506 */
507 public static void displayDocServNotInstalled() {
508 if (!firstTime) return;
509 //displayError("The CVW Plugin is either not installed or not available. If you have installed the Plugin, then call your Administrator.");
510 displayError("The CVW Document server is not available.");
511 firstTime = false;
512 }
513
514 /**
515 * Displays the specified error message.
516 * @param msg the error message to display
517 * @exception CheckoutDirectoryException
518 * @exception Throwable
519 */
520 public static void displayError(String msg) {
521 if (msg.equals("Invalid document ID")) return;
522 jcvw.displayError(msg, false);
523 }
524
525 /**
526 * Display error for debugging purposes.
527 * @exception CheckoutDirectoryException
528 * @exception Throwable
529 */
530 public static void docGenericError() {
531 if (CVWCoordinator.DEBUG) System.err.println("ERROR: Generic error, Document features unavailable.");
532 }
533 /**
534 * Display error for debugging purposes.
535 * @exception CheckoutDirectoryException
536 * @exception Throwable
537 */
538 public static void checkoutDirNotAvailable() {
539 if (CVWCoordinator.DEBUG) System.err.println("ERROR: Checkout directory not avaiable, Document features unavailable.");
540 }
541
542 /*
543 * 4/6/98 dage - end of class/static methods
544 * **********************************/
545 //
546 // The constructors live here.
547 //
548 /**
549 * Constructor
550 * @return
551 */
552 public DSIController() {
553 if(CVWCoordinator.DEBUG) System.err.println("**** CONSTRUCTED: New DSIController");
554 // runThread = null;
555 // if(blockObject == null) {
556 // blockObject = new Object();
557 // }
558 }
559
560 /**
561 * Runs the current thread.
562 */
563 public void run() {
564 int x;
565 boolean handled;
566
567 // runThread = Thread.currentThread();
568 if(CVWCoordinator.DEBUG) System.err.println("DSIC: INITIALIZED ");
569
570 // synchronized(blockObject) {
571 // while(true) {
572
573 // try {
574 // if(CVWCoordinator.DEBUG) System.err.println("[DSIC/RUN] WAITING FOR A THREAD");
575 // blockObject.wait();
576 // if(CVWCoordinator.DEBUG) System.err.println("[DSIC/RUN] NOTIFIED ABOUT THREAD");
577 // } catch (InterruptedException e) {
578 // if(CVWCoordinator.DEBUG) System.err.println("[DSIC/RUN] INTERRUPTED... WHAT?");
579 // }
580
581 // if(CVWCoordinator.DEBUG) System.err.println("DSIC Thread Int: "+Thread.currentThread());
582 // handled = false;
583
584 // while (!handled) { // Make sure we handle a thread now
585 // for(x=0;x<runThreads.size();x++) {
586 // if(CVWCoordinator.DEBUG) System.err.println("Checking thread id: ["+x+"]");
587 // if(isFinished(x)) {
588 // if(CVWCoordinator.DEBUG) System.err.println("Thread ID: ["+x+"] is ready.");
589 // handled = true;
590 // handleThreadReturn(x);
591 // }
592 // }
593 // }
594
595 // }
596 // }
597 }
598
599 /* 1/23/98 dage - added this because when dsi is inited, the current user name
600 is not known
601 * 2/6/98 dage - verify cache at this point
602 */
603 /**
604 * Sets the current user name once the user has connected.
605 * @param name the name of the current user
606 */
607 public void setupUser() throws CheckoutDirectoryException {
608 if(CVWCoordinator.DEBUG) System.err.println("Setting up user");
609
610 String sysDir = plugin.getUserCheckoutDir();
611 if (sysDir == null) {
612 // Memory allocation didn't happen, so NULL was returned..
613 //currentDSI = null;
614 throw new CheckoutDirectoryException();
615 }
616
617 CheckDir = sysDir;
618
619 if (!plugin.setupCheckoutDir()) {
620 String msg = "Cache directory could not be created/accessed: " + CheckDir;
621 System.err.println(msg);
622 CVWCoordinator.getInstance().displayError(msg, "Cache Access Problem", false);
623 }
624
625 if (!isAvailable()) {
626 if(CVWCoordinator.DEBUG) System.err.println("cant verify cache");
627 return;
628 }
629
630 // now set up the DocFactory for this user
631 AttributeSignature as = new AttributeSignature();
632 as.put("Content-Type", new Integer(2)); // just a default int type. meaningless right now
633 factory = new DocFactory(DSHost, DSPort, DSUrl, getUserName(), as);
634
635 // Verify the cache
636 try {
637 verifyCache();
638 } catch (DocServException e) {
639 // Couldn't verify cache for now
640 System.err.println("Couldn't validate server integrity, continuing.");
641 }
642
643 }
644
645 /* 4/10/98 dage - no longer pass in all the parameters, can directly ask
646 * CVWCoordinator or SysUtils.
647 *
648 *
649 * 4/8/98 dage - need to have some parameter list because subclass
650 * DocServerInterface needs a constructor with an empty parm list
651 */
652 /**
653 * Constructor
654 * @param dummy
655 * @return
656 * @exception CheckoutDirectoryException
657 */
658 public DSIController(URL location) {
659 int rc=0;
660
661 // runThread = null; // Filled in in the "run" method
662
663 jcvw.displayPrvSysMsg("Please wait a moment. Performing one-time document initialization ...");
664 if(CVWCoordinator.DEBUG) System.err.println("Init DSIController, Thread: "+Thread.currentThread());
665
666 //initMimeVector();
667
668 /*
669 * for some reason had to add init the blockObject var.
670 */
671 // if(blockObject == null) {
672 // blockObject = new Object();
673 // }
674
675 initDocServerCheck(location);
676
677 if(CVWCoordinator.DEBUG) System.err.println("DSI: Done with init, plugin is "+plugin);
678 }
679
680 /**
681 * Methods to start a DS request, query a current request's status,
682 * and retrieve the results of a request
683 *
684 * Start a request. In general, the philosophy is that we can
685 * perform *one* operation at a time on a given docID, so we check
686 * to see which docID's are currently having operations performed
687 * on them. If the docID does not appear, we can continue to start
688 * the operation. Returns a transaction index.
689 *
690 * @param opcode the operation to perform
691 * @param params the parameters the document server needs
692 * @return the index of this document server transaction
693 * @exception DocInUseException
694 */
695 public int startDSOp(int opcode, DSIParms params) throws DocInUseException {
696
697 System.err.println("starting DSOp, code " + opcode);
698 // REMOVE THESE LINES
699 // if(inUse(params.docID)) throw new DocInUseException();
700 // REMOVE THESE LINES
701
702 // Add these lines and remove the above ones when a reentrant
703 // plugin is available.
704 if(params.docID.intValue() != 0 && inUse(params.docID))
705 throw new DocInUseException();
706
707 // if(this.runThread == null) {
708 // This means that the run() method hasn't gotten around
709 // to initializing the runThread variable yet. Hang around
710 // and wait until this is the case.
711 // int count=0;
712 // boolean ready = false;
713 // while(!ready && count < 10000) {
714 // if(this.runThread != null) ready=true;
715 // count++;
716 // }
717 // if(!ready) throw new DocInUseException();
718 // }
719
720 if(CVWCoordinator.DEBUG) System.err.println("Constructing dsi");
721 // DocServerInterface dsi = new DocServerInterface(this, opcode, params,
722 // blockObject,
723 // runTable.size()+1);
724
725 DocServerInterface dsi = new DocServerInterface(this, opcode, params,
726 runTable.size()+1);
727
728 if(CVWCoordinator.DEBUG) System.err.println("Done DSI");
729
730 Thread pThread = new Thread(dsi);
731
732 runTable.addElement(dsi); // Enter this DSI into the runtable
733 runThreads.addElement(pThread); // Enter this thread into the runtable
734 docIDTable.addElement(params.docID); // Enter this docID into exclusivity
735
736 pThread.start();
737
738 if (CVWCoordinator.DEBUG) System.err.println("returning from startDSOp");
739 return(runTable.size()-1);
740 }
741
742
743 /**
744 * Returns true if the docID is currently active/in use.
745 *
746 * NOTE NOTE NOTE
747 * Until the plugin is made re-entrant (i.e., it can support
748 * more than one file open at a time), this routine will always return
749 * TRUE if there is ANY document operation in progress.
750 * CHANGE THIS ROUTINE for multiple operations on multiple documents,
751 * after the plugin is rewritten.
752 * @param docID the document id to be checked
753 * @return whether the document is in use
754 * @exception DocInUseException
755 */
756 public boolean inUse(Integer docID) {
757 int x;
758 Integer id;
759
760 //// REMOVE THESE LINES
761 // if(docIDTable.size() > 0) return(true);
762 // else return(false);
763 //// REMOVE THESE LINES
764
765 // Add these lines and remove the above ones for multiple
766 // document operations.
767 //
768 for(x=0;x<docIDTable.size();x++) {
769 id=(Integer)docIDTable.elementAt(x);
770 if(id.intValue() == docID.intValue()) return true;
771 }
772 return false;
773 }
774
775 /**
776 * Start a request, and wait for it to finish. Return the process'
777 * DSI result block.
778 * @param opcode the function to perform
779 * @param params the parameters the document server needs
780 * @return the result parameters from the document server
781 * @exception DocInUseException
782 */
783 public DSIParms startDSSyncOp(int opcode, DSIParms params) throws DocInUseException {
784 int idx;
785 DSIParms parms;
786 System.err.println("starting dssyncOp, code " + opcode);
787
788 if(params == null) parms = new DSIParms();
789 else parms = params;
790
791 // REMOVE THESE LINES
792 // if(inUse(parms.docID)) throw new DocInUseException();
793 // REMOVE THESE LINES
794
795 // No op, just wanted to check if the doc was in use.
796 // Returns the parms passed in.
797 if(opcode == DOCBUSY) return(parms);
798
799 // Add these lines and remove the above ones for multiple
800 // doc operations
801 if(parms.docID.intValue() != 0 && inUse(parms.docID))
802 throw new DocInUseException();
803
804 idx=this.startDSOp(opcode, parms);
805 Thread myThread = (Thread)runThreads.elementAt(idx);
806
807 while(myThread.isAlive()) {
808 try {
809 if (CVWCoordinator.DEBUG)
810 System.err.println("[DSIC/SDSSO] WAITING FOR A THREAD");
811 // synchronized(this) {
812 // this.wait();
813 // } // Wait for thread completion
814 if (CVWCoordinator.DEBUG)
815 System.err.println("[DSIC/SDSSO] WAITING FOR A THREAD");
816 } catch (Exception e) {
817 // No big deal
818 }
819 }
820 DSIParms returnParms = handleThreadReturn(idx);
821
822 return(returnParms);
823 }
824
825 /**
826 * Check status of request/transaction.
827 * @param transIdx the index of the transaction being checked
828 * @return <code>true</code> if the transaction is finished
829 */
830 private boolean isFinished(int transIdx) {
831 Thread thr;
832
833 thr = (Thread)runThreads.elementAt(transIdx);
834 return(!thr.isAlive());
835 }
836
837 /**
838 * Retrieve results of request.
839 * @param transIdx the index of the transaction being checked
840 * @return the result parameters from the document server
841 * @exception DSNotFinishedException
842 *
843 public DSIParms getResult(int transIdx) throws DSNotFinishedException {
844 DocServerInterface dsi;
845
846 if(!isFinished(transIdx)) throw new DSNotFinishedException();
847 dsi = (DocServerInterface)runTable.elementAt(transIdx);
848 return(dsi.result);
849 }
850 */
851
852 /**
853 * Remove this transaction from the indexes, it's no longer
854 * needed. Removes the object from the runtable,
855 * removes the thread from the thread table, and releases the
856 * op lock on the docID
857 * @param transIdx the index of the transaction being checked
858 */
859 private synchronized void releaseDSOp(int transIdx) {
860
861 if(CVWCoordinator.DEBUG) System.err.println("[RDSO] Cleaning up from tables..");
862 runTable.removeElementAt(transIdx);
863 runThreads.removeElementAt(transIdx);
864 docIDTable.removeElementAt(transIdx);
865 if(CVWCoordinator.DEBUG) System.err.println("[RDSO] Cleaning up complete.");
866 }
867
868 /**
869 * Cleans up thread information
870 *
871 * @param thread The thread who's finished processing
872 */
873 public void releaseThreadInfo(Thread thread) {
874 int i;
875
876 String name = thread.getName();
877 System.err.println("Trying to release thread " + name);
878 for (i = 0; i < runThreads.size(); i++) {
879 Thread t = (Thread)runThreads.elementAt(0);
880 System.err.println("Found thread: " + t.getName());
881 if (t.getName().equals(name)) {
882 System.err.println("Release thread at index: " + i);
883 // see if we need to handle this return first
884 DSIParms dsip = handleThreadReturn(i);
885 // releaseDSOp(i);
886 return;
887 }
888 }
889 }
890
891 /**
892 * Handles the return of a particular thread.
893 * @param threadID the thread which has finished
894 */
895 private DSIParms handleThreadReturn(int threadID) {
896
897 DocServerInterface dsi = (DocServerInterface)runTable.elementAt(threadID);
898 DSIParms dsip=dsi.result;
899 DSIParms indsip=dsi.parms;
900
901 boolean exc = false;
902 String excMessage = null;
903
904 if(CVWCoordinator.DEBUG) System.err.println("THREAD RETURNED: ["+threadID+"]; "+Thread.currentThread());
905
906 try {
907 // Catch any thrown exceptions
908 if(dsip.exc!= null) {
909 if(CVWCoordinator.DEBUG) System.err.println("THREAD EXCEPTION: "+dsip.exc);
910 throw dsip.exc;
911 }
912
913 if(CVWCoordinator.DEBUG) System.err.println("NO EXCEPTION, post-process..");
914
915 // Post-processing
916 if(dsi.operation == DOCCREATE) {
917 // call to moo server
918 Integer docID = dsip.integerResult;
919 String mimeType = dsip.stringResult;
920 CVWDocument cvwDoc = new CVWDocument();
921 cvwDoc.objectCreate(indsip.name, mimeType, indsip.sessile, indsip.desc,
922 indsip.path, docID);
923 }
924
925 } catch (DocServException e) {
926 // RJT calling displayError() here with modality true results in the
927 // OkCancelDialog object unable to receive/process events. Make call
928 // after we releaseDSOp() and synchronize().
929 exc = true;
930 excMessage = e.toString();
931 }
932
933 // this.resultParms = dsip;
934 if(CVWCoordinator.DEBUG) System.err.println("Releasing thread..");
935 releaseDSOp(threadID);
936 // synchronized(this) {this.notify();}
937
938 if (exc)
939 displayError(excMessage);
940
941 return dsip;
942 }
943
944 //
945 // Local public methods
946 //
947 /**
948 * Verifies the cache integrity, database integrity, and
949 * synchronization with the document server.
950 * @exception DocServException
951 */
952 private void verifyCache() throws DocServException {
953 DSDBEntry entry;
954 Integer doc;
955 String resultMsg=null;
956 int x;
957 DocServerInterface dsi=new DocServerInterface(this);
958
959 if(runTable.size() > 0) {
960 displayError("Can't perform integrity check during document operation.");
961 displayError("Please wait for the previous operation to complete.");
962 return;
963 }
964
965 jcvw.displayPrvSysMsg("Synchronizing your local document database with the document server's data.");
966
967 // Local DB is okay if we can create it
968 DSDB localDB = new DSDB(this.CheckDir,plugin);
969
970 // First, check to see if the database agrees
971 // with the document server
972 Vector cdocs = dsi.DocUserStatus();
973
974 for(x=0;x<cdocs.size();x++) {
975 doc=(Integer)cdocs.elementAt(x);
976 System.err.println("[DS->DB]: Checking doc: "+doc);
977 try {
978 entry=localDB.getEntry(doc.intValue());
979 if(!entry.ReadWrite()) {
980 displayError("You had previously opened \""+entry.Name()+"\" for editing but the system encountered a locking error. Any changes you made will be discarded. Report this to your administrator.");
981 try {dsi.ClearDocLock(doc.intValue());}
982 catch (DocNotCheckedOutException e) {}
983 catch (DocIDException e) {}
984 }
985 } catch (DBEntryNotFoundException e) {
986 // This is bad; the DocServer has it checked out to us,
987 // but our database doesn't even have it at all.
988 String name;
989 try {
990 name=dsi.GetDocName(doc.intValue());
991 } catch (Exception z) {
992 name="Unknown (#"+doc.intValue()+")";
993 }
994 displayError("You had previously opened \""+name+"\" for editing but it is not on your local computer, perhaps because you were working on another computer. Any changes you made will be discarded.");
995 try {dsi.ClearDocLock(doc.intValue());}
996 catch (DocNotCheckedOutException f) {}
997 catch (DocIDException f) {}
998 }
999 }
1000
1001 // Now, the other way around: Check if the local DB agrees w/ the
1002 // DocServer
1003 localDB.resetCurrentEntry();
1004 Vector ddocs = new Vector();
1005 boolean found=false;
1006
1007 try {
1008 for(entry=localDB.getNextEntry(); true; entry=localDB.getNextEntry()) {
1009 System.err.print("[DB->DS]: Checking doc: "+entry.getID());
1010 if (!entry.getServer().equals(CVWCoordinator.getInstance().getServerName())) {
1011 //System.err.println(" different doc server.");
1012 } else {
1013 if(entry.ReadWrite()) {
1014 found=false;
1015 for(x=0;x<cdocs.size();x++) {
1016 doc=(Integer)cdocs.elementAt(x);
1017 if(doc.intValue() == entry.getID()) found=true;
1018 }
1019 if(!found) {
1020// dage -- couldnt we make sure that the current user is the user in the
1021// db file before deleting
1022 System.err.println(" -- not valid, deleting");
1023 displayError("You had previously opened \""+entry.Name()+"\" for editing but the system encountered a synchronizaton problem. Any changes you made will be discarded. Report this to your administrator.");
1024 ddocs.addElement(entry);
1025 } else { System.err.println("-- Okay.");}
1026 }
1027 }
1028 } //end for
1029 } catch (DBEntryNotFoundException e) {} // Terminates loop
1030
1031 System.err.println();
1032
1033 // Go through and delete from the database
1034 for(x=0;x<ddocs.size();x++) {
1035 try {
1036 entry=(DSDBEntry)ddocs.elementAt(x);
1037 System.err.println("[MAINT]: Deleting "+entry.getID());
1038 if(plugin.fileExists(entry.Path())) {
1039 plugin.setFileLock(entry.Path(),(short)0);
1040 plugin.removeFile(entry.Path());
1041 }
1042 localDB.removeEntry(entry);
1043 } catch (DBEntryNotFoundException e) {}
1044 }
1045
1046 // Last, check to see if the database agrees
1047 // with the file cache. Also, clear out any R/O entries.
1048 localDB.resetCurrentEntry();
1049 ddocs = new Vector();
1050
1051 try {
1052 for(entry=localDB.getNextEntry(); true; entry=localDB.getNextEntry()) {
1053 System.err.println("[DB->FS]: Checking doc: "+entry.getID());
1054 if(!plugin.fileExists(entry.Path()) && entry.ReadWrite()) {
1055 displayError("You had previously opened \""+entry.Name()+"\" for editing but it is not on your local computer, perhaps because someone deleted it manually. Any changes you made will be discarded.");
1056 ddocs.addElement(entry);
1057 } else if(!plugin.fileExists(entry.Path())) {
1058 ddocs.addElement(entry);
1059 } else if(!entry.ReadWrite()) {
1060 System.err.println("\""+entry.Name()+"\" is R/O, clearing ("+entry.getID()+")");
1061 ddocs.addElement(entry);
1062 }
1063 }
1064 } catch (DBEntryNotFoundException e) {} // Terminates loop
1065
1066 // Go through and delete from the database
1067 for(x=0;x<ddocs.size();x++) {
1068 try {
1069 entry=(DSDBEntry)ddocs.elementAt(x);
1070 System.err.println("[MAINT]: Deleting "+entry.getID());
1071 if(plugin.fileExists(entry.Path())) {
1072 plugin.setFileLock(entry.Path(),(short)0);
1073 plugin.removeFile(entry.Path());
1074 }
1075 localDB.removeEntry(entry);
1076 } catch (DBEntryNotFoundException e) {}
1077 }
1078
1079 jcvw.displayPrvSysMsg("Synchronization with the document server is complete.");
1080 }
1081
1082 //
1083 // Private internal utility methods
1084 //
1085
1086 public DocFactory getDocFactory() {
1087 return factory;
1088 }
1089
1090 public URL getDSUrl() throws MalformedURLException {
1091 return (new URL(PROTOCOL, DSHost, DSPort, DSUrl));
1092 }
1093
1094 public String getUserName() {
1095 return CVWUser.getFedUserName();
1096 }
1097
1098}
1099
1100
1101
1102