source: gli/trunk/src/org/greenstone/gatherer/collection/CollectionManager.java@ 16132

Last change on this file since 16132 was 16132, checked in by osborn, 16 years ago

Additions for Scheduling Component

  • Property svn:keywords set to Author Date Id Revision
File size: 81.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.cdm.CollectionDesignManager;
50import org.greenstone.gatherer.cdm.CollectionMeta;
51import org.greenstone.gatherer.cdm.CollectionMetaManager;
52import org.greenstone.gatherer.cdm.CommandTokenizer;
53import org.greenstone.gatherer.greenstone.Classifiers;
54import org.greenstone.gatherer.greenstone.LocalGreenstone;
55import org.greenstone.gatherer.greenstone.LocalLibraryServer;
56import org.greenstone.gatherer.greenstone.Plugins;
57import org.greenstone.gatherer.greenstone3.ServletConfiguration;
58import org.greenstone.gatherer.gui.LockFileDialog;
59import org.greenstone.gatherer.gui.ModalProgressPopup;
60import org.greenstone.gatherer.gui.WarningDialog;
61import org.greenstone.gatherer.metadata.DocXMLFileManager;
62import org.greenstone.gatherer.metadata.MetadataChangedListener;
63import org.greenstone.gatherer.metadata.MetadataSet;
64import org.greenstone.gatherer.metadata.MetadataSetManager;
65import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
66import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
67import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
68import org.greenstone.gatherer.shell.GShell;
69import org.greenstone.gatherer.shell.GShellEvent;
70import org.greenstone.gatherer.shell.GShellListener;
71import org.greenstone.gatherer.shell.GShellProgressMonitor;
72import org.greenstone.gatherer.util.Codec;
73import org.greenstone.gatherer.util.StaticStrings;
74import org.greenstone.gatherer.util.Utility;
75import org.greenstone.gatherer.util.XMLTools;
76import org.w3c.dom.*;
77
78/** This class manages many aspects of the collection, from its creation via scripts, data access via methods and its importing and building into the final collection. It is also responsible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
79 * @author John Thompson
80 * @version 2.3
81 */
82public class CollectionManager
83 implements GShellListener, MetadataChangedListener
84{
85 /** Are we currently in the process of building? */
86 static private boolean building = false;
87 /** Are we currently in the process of importing? */
88 static private boolean importing = false;
89 /** Are we currently in the process of scheduling? */
90 static private boolean scheduling = false;
91 /** The objects listening for CollectionContentsChanged events. */
92 static private ArrayList collection_contents_changed_listeners = new ArrayList();
93 /** The collection this manager is managing! */
94 static private Collection collection = null;
95 /** The collection tree (used in both Gather and Enrich panes). */
96 static private CollectionTree collection_tree = null;
97 /** The collection tree model. */
98 static private CollectionTreeModel collection_tree_model = null;
99 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
100 static private FMTreeModelListener fm_tree_model_listener = null;
101 /** The monitor responsible for parsing the build process. */
102 static private GShellProgressMonitor build_monitor = null;
103 /** The monitor responsible for parsing the import process. */
104 static private GShellProgressMonitor import_monitor = null;
105 /** The monitor responsible for parsing the scheduler process. */
106 static private GShellProgressMonitor schedule_monitor = null;
107
108 /** The name of the standard lock file. */
109 static final public String LOCK_FILE = "gli.lck";
110
111 /** Used to indicate the source of the message is the file collection methods. */
112 static final public int COLLECT = 3;
113 /** Used to indicate the source of the message is the building methods. */
114 static final public int BUILDING = 5;
115 /** Used to indicate the source of the message is in the scheduling methods...? */
116 static final public int SCHEDULING = 7;
117
118
119 /** Constructor. */
120 public CollectionManager() {
121 // Initialisation.
122 this.building = false;
123 this.importing = false;
124 this.scheduling = false;
125 this.collection = null;
126
127 MetadataXMLFileManager.addMetadataChangedListener(this);
128
129 // If using a remote Greenstone server, delete the local collect directory because it will be out of date
130 if (Gatherer.isGsdlRemote) {
131 System.err.println("Deleting user's local collect directory...");
132 Utility.delete(new File(Gatherer.getCollectDirectoryPath()));
133 System.err.println("Done.");
134 new File(Gatherer.getCollectDirectoryPath()).mkdirs();
135 }
136 }
137
138
139 static public void addCollectionContentsChangedListener(CollectionContentsChangedListener listener)
140 {
141 collection_contents_changed_listeners.add(listener);
142 }
143
144
145 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
146 * @see org.greenstone.gatherer.Configuration
147 * @see org.greenstone.gatherer.Gatherer
148 * @see org.greenstone.gatherer.collection.Collection
149 * @see org.greenstone.gatherer.gui.BuildOptions
150 * @see org.greenstone.gatherer.shell.GShell
151 * @see org.greenstone.gatherer.shell.GShellListener
152 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
153 * @see org.greenstone.gatherer.util.Utility
154 */
155 public void buildCollection(boolean incremental_build)
156 {
157
158 DebugStream.println("In CollectionManager.buildCollection(), incremental_build: " + incremental_build);
159 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
160 building = true;
161
162 // Generate the buildcol.pl command
163 ArrayList command_parts_list = new ArrayList();
164 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
165 command_parts_list.add(Configuration.perl_path);
166 command_parts_list.add("-S");
167 }
168
169 if (Configuration.fedora_info.isActive()) {
170 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-buildcol.pl");
171
172 command_parts_list.add("-hostname");
173 command_parts_list.add(Configuration.fedora_info.getHostname());
174
175 command_parts_list.add("-port");
176 command_parts_list.add(Configuration.fedora_info.getPort());
177
178 command_parts_list.add("-username");
179 command_parts_list.add(Configuration.fedora_info.getUsername());
180
181 command_parts_list.add("-password");
182 command_parts_list.add(Configuration.fedora_info.getPassword());
183
184 command_parts_list.add("-protocol");
185 command_parts_list.add(Configuration.fedora_info.getProtocol());
186
187 }
188 else {
189 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "buildcol.pl");
190 }
191 command_parts_list.add("-gli");
192 command_parts_list.add("-language");
193 command_parts_list.add(Configuration.getLanguage());
194 command_parts_list.add("-collectdir");
195 command_parts_list.add(getCollectDirectory());
196
197 // If the user hasn't manually specified "-keepold" or "-removeold" then pick one based on incremental_build
198 if (!collection.build_options.getValueEnabled("keepold") && !collection.build_options.getValueEnabled("removeold")) {
199 command_parts_list.add(incremental_build ? "-keepold" : "-removeold");
200 }
201
202 String[] build_options = collection.build_options.getValues();
203 for (int i = 0; i < build_options.length; i++) {
204 command_parts_list.add(build_options[i]);
205 }
206
207 command_parts_list.add(collection.getName());
208
209 // Run the buildcol.pl command
210 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
211 GShell shell = new GShell(command_parts, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
212 shell.addGShellListener(Gatherer.g_man.create_pane);
213 shell.addGShellListener(Gatherer.g_man.format_pane);
214 shell.start();
215
216 }
217
218 /*probably repeating alot of work, but I want to keep this separate... wendy*/
219 public void scheduleBuild(boolean incremental_build)
220 {
221
222 DebugStream.println("In CollectionManager.scheduleBuild(), incremental_build: " + incremental_build);
223 DebugStream.println("Is event dispatch threa: " + SwingUtilities.isEventDispatchThread());
224
225 ArrayList sched_list = new ArrayList();
226 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
227 sched_list.add(Configuration.perl_path);
228 sched_list.add("-S");
229 }
230 sched_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "schedule.pl");
231 sched_list.add("-colname");
232 sched_list.add(collection.getName());
233 sched_list.add("-gli");
234
235 // First, generate the import.pl command, also converting to a string
236 // Generate the import.pl command
237 ArrayList import_list = new ArrayList();
238 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
239 import_list.add(Configuration.perl_path);
240 import_list.add("-S");
241 }
242 import_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
243 import_list.add("-language");
244 import_list.add(Configuration.getLanguage());
245 import_list.add("-collectdir");
246 import_list.add(getCollectDirectory());
247
248 String[] import_options = collection.import_options.getValues();
249 int i = 0;
250 for (i = 0; i < import_options.length; i++) {
251 import_list.add(import_options[i]);
252 }
253
254 import_list.add(collection.getName());
255
256 String[] import_parts = (String[]) import_list.toArray(new String[0]);
257 String command = "";
258 i = 0;
259 for (i = 0; i < import_parts.length-1; i++) {
260 command = command + import_parts[i] + " ";
261 }
262 command = command + import_parts[i];
263
264 sched_list.add("-import");
265 sched_list.add("\"" + command + "\"");
266
267 // Generate the buildcol.pl command, also converting to a string
268 ArrayList build_list = new ArrayList();
269
270 // i'm not doing this in schedule.pl right now - should i be?
271 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
272 build_list.add(Configuration.perl_path);
273 build_list.add("-S");
274 }
275 build_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "buildcol.pl");
276 build_list.add("-language");
277 build_list.add(Configuration.getLanguage());
278 build_list.add("-collectdir");
279 build_list.add(getCollectDirectory());
280
281 // If the user hasn't manually specified "-keepold" or "-removeold" then pick one based on incremental_build
282 if (!collection.build_options.getValueEnabled("keepold") && !collection.build_options.getValueEnabled("removeold")) {
283 build_list.add(incremental_build ? "-keepold" : "-removeold");
284 }
285
286 String[] build_options = collection.build_options.getValues();
287 for (i = 0; i < build_options.length; i++) {
288 build_list.add(build_options[i]);
289 }
290
291 build_list.add(collection.getName());
292
293 //build actual string
294 String[] build_parts = (String[]) build_list.toArray(new String[0]);
295 String command2 = "";
296 for(i = 0; i < build_parts.length-1; i++) {
297 command2 = command2 + build_parts[i] + " ";
298 }
299 command2 = command2 + build_parts[i];
300
301 sched_list.add("-build");
302 sched_list.add("\"" + command2 + "\"");
303
304 //next, the scheduling frequency goes here
305 String[] schedule_options = collection.schedule_options.getValues();
306 for(i = 0; i < schedule_options.length; i++) {
307 sched_list.add(schedule_options[i]);
308 }
309
310 //now, hope it will run. ;)
311 String[] sched_parts = (String[]) sched_list.toArray(new String[0]);
312
313 GShell shell = new GShell(sched_parts, GShell.SCHEDULE, SCHEDULING, this, schedule_monitor, GShell.GSHELL_SCHEDULE);
314 shell.addGShellListener(Gatherer.g_man.create_pane);
315 shell.addGShellListener(Gatherer.g_man.format_pane);
316 shell.start();
317 }
318
319 /** Used to determine whether the currently active collection has been built.
320 * @return A boolean indicating the built status of the collection.
321 */
322 public boolean built() {
323 if(collection != null) {
324 // Determine if the collection has been built by looking for the build.cfg (gs2)
325 // buildConfig.xml (gs3) or export.inf (fedora) file
326 String file_name = "";
327
328 if (Configuration.fedora_info.isActive()) { // FLI case
329 // Fedora build
330 //file_name = getLoadedCollectionArchivesDirectoryPath() + "import.inf";
331 file_name = getLoadedCollectionExportDirectoryPath() + "export.inf";
332 } else {
333 // GLI is running, check if it's greenstone 3 or greenstone 2
334 if (Gatherer.GS3) { // GS3 GLI
335 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CONFIG_XML;
336 }
337 else { // greenstone 2 GLI
338 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CFG;
339 }
340 }
341 File test_file = new File(file_name);
342 return test_file.exists();
343 }
344 return false;
345 }
346
347
348 /** a test method to see if we can delete a directory/file - returns false is the file or any of the contents of a directory cannot be deleted */
349 static private boolean canDelete(File file)
350 {
351 if (!file.isDirectory()) {
352 return file.canWrite();
353 }
354 File [] file_list = file.listFiles();
355 for (int i=0; i<file_list.length; i++) {
356 if (!canDelete(file_list[i])) {
357 return false;
358 }
359 }
360 return true;
361 }
362
363
364 /** Called to close the current collection and remove its lock file.
365 * @see org.greenstone.gatherer.Gatherer
366 * @see org.greenstone.gatherer.collection.Collection
367 * @see org.greenstone.gatherer.util.Utility
368 */
369 public void closeCollection() {
370 DebugStream.println("Close collection: " + collection.getName());
371
372 // Remove the lock on this file, then remove the collection.
373 File lock_file = new File(getLoadedCollectionDirectoryPath() + LOCK_FILE);
374 lock_file.delete();
375 if (lock_file.exists()) {
376 System.err.println("Warning: Lockfile was not successfully deleted.");
377 }
378
379 // Remove the lock file on the server
380 if (Gatherer.isGsdlRemote) {
381 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), lock_file);
382 }
383
384 MetadataSetManager.clearMetadataSets();
385 MetadataXMLFileManager.clearMetadataXMLFiles();
386 DocXMLFileManager.clearDocXMLFiles();
387 ProfileXMLFileManager.clearProfileXMLFile();
388
389 collection.destroy();
390 collection = null;
391 collection_tree_model = null;
392 //Configuration.setCollectionConfiguration(null);
393 Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
394 if (Gatherer.g_man != null) {
395 Gatherer.g_man.updateUI(); // !!! Necessary?
396 }
397 }
398
399//This method is no longer used in gs3 since the modification of CollectionConfiguration.java
400// public void convertToGS3Collection() {
401// // Generate the convert_coll_from_gs2.pl command
402// ArrayList command_parts_list = new ArrayList();
403// if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
404// command_parts_list.add(Configuration.perl_path);
405// command_parts_list.add("-S");
406// }
407// command_parts_list.add(Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl");
408// command_parts_list.add("-collectdir");
409// command_parts_list.add(getCollectDirectory());
410// command_parts_list.add(collection.getName());
411//
412// // Run the convert_coll_from_gs2.pl command
413// String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
414// GShell process = new GShell(command_parts, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
415// process.addGShellListener(this);
416// process.run(); // Don't bother threading this... yet
417//
418// }
419
420 /** When basing a new collection on an existing one, we need to copy
421 * over some extra directories: images and macros
422 */
423 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
424 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
425 return false;
426 }
427 DebugStream.println("Copying images and macros dirs from the base collection");
428 try {
429 // do the images dir
430 File base_coll_images = new File(base_coll_dir, "images");
431 if (base_coll_images.isDirectory()) {
432 // copy all the images over
433 File new_coll_images = new File(new_coll_dir, "images");
434 new_coll_images.mkdirs();
435
436 // copy the contents over
437 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_images, new_coll_images);
438 }
439 }
440 catch (Exception e) {
441 DebugStream.println("Couldn't copy over the images dir from the base collection: "+e.toString());
442 }
443 try {
444 // do the macros dir
445 File base_coll_macros = new File(base_coll_dir, "macros");
446 if (base_coll_macros.isDirectory()) {
447 // copy all the macros over
448 File new_coll_macros = new File(new_coll_dir, "macros");
449 new_coll_macros.mkdirs();
450
451 // copy the contents over
452 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_macros, new_coll_macros);
453 }
454 }
455 catch (Exception e) {
456 DebugStream.println("Couldn't copy over the macros dir from the base collection: "+e.toString());
457 }
458 return true;
459 }
460
461 /** Used to set the current collection to the given collection. Note that this call should -always- be proceeded by a ready call, and if the collection is ready and the saved flag is unset then the user should be prompted to save. Also note that this method creates yet another GShell to run buildcol.pl.
462 * @param description a description of the collection as a String
463 * @param email the email address of the author/maintainer as a String
464 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
465 * @param title the longer title of the collection as a String
466 * @param base_collection_directory if the user has chosen to base their new collection on an existing one, this is the directory where this base collection can be found, as a File, otherwise its null
467 * @param metadata_sets if the user has decided to select several metadata sets with which to initially populate the GLI then this is an ArrayList of metadata set file names, otherwise its null
468 */
469 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
470 {
471 // Display a modal progress popup to indicate that the collection is being loaded
472 ModalProgressPopup create_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Creating_Collection"), Dictionary.get("CollectionManager.Creating_Collection_Please_Wait"));
473 create_collection_progress_popup.display();
474
475 // Create the collection on a separate thread so the progress bar updates correctly
476 (new CreateCollectionTask(description, email, name, title, base_collection_directory, metadata_sets, create_collection_progress_popup)).start();
477 }
478
479
480 private class CreateCollectionTask
481 extends Thread
482 {
483 private String description = null;
484 private String email = null;
485 private String name = null;
486 private String title = null;
487 private File base_collection_directory = null;
488 private ArrayList metadata_sets = null;
489 private ModalProgressPopup create_collection_progress_popup = null;
490
491 public CreateCollectionTask(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets, ModalProgressPopup create_collection_progress_popup)
492 {
493 this.description = description;
494 this.email = email;
495 this.name = name;
496 this.title = title;
497 this.base_collection_directory = base_collection_directory;
498 this.metadata_sets = metadata_sets;
499 this.create_collection_progress_popup = create_collection_progress_popup;
500 }
501
502 public void run()
503 {
504 createCollectionInternal(description, email, name, title, base_collection_directory, metadata_sets);
505 create_collection_progress_popup.close();
506 }
507 }
508
509
510 private void createCollectionInternal(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
511 {
512 try {
513 // first make sure that the collect directory exists
514 File collect_dir = new File(getCollectDirectory());
515 if (!collect_dir.exists()) {
516 collect_dir.mkdirs();
517 }
518
519 // Create the new collection
520 makeCollection(name, email);
521
522 // Check that the collection has been created successfully
523 String collection_directory_path = getCollectionDirectoryPath(name);
524 if (!new File(collection_directory_path).exists()) {
525 // If there is no collection directory then the creation was unsuccessful, or cancelled
526
527 return;
528 }
529
530 // Check for the existence of the collection configuration file
531 String file_name = ((Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG);
532 File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + file_name);
533
534 if (!collect_cfg_file.exists()) {
535 System.err.println("Error: no " + file_name + " file has been created!");
536 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", Dictionary.get("CollectionManager.No_Config_File")), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
537 return;
538 }
539
540 // ACTIVE_DIR/log/
541 File log_dir = new File(collection_directory_path + "log");
542 log_dir.mkdirs();
543
544 // Make sure an import folder exists
545 File collection_import_directory = new File(collection_directory_path + "import");
546 if (!collection_import_directory.exists()) {
547 collection_import_directory.mkdirs();
548 if (Gatherer.isGsdlRemote) {
549 RemoteGreenstoneServer.newCollectionDirectory(name, collection_import_directory);
550 }
551 }
552
553 // Now create the collection object around the directory.
554 collection = new Collection(new File(collection_directory_path, name + ".col"));
555
556 // "-removeold" is on by default for import.pl
557 collection.import_options.setValue("removeold", true, null);
558
559 //try to obtain email address of collection owner if it exists...
560 String stmp = Configuration.getEmail();
561 if(stmp != null) {
562 collection.schedule_options.setValue("toaddr", false, Configuration.getEmail());
563 }
564
565 //try to obtain email address of Greenstone installation webmaster for - used to indicate "sender".
566 File mcfg = new File(LocalGreenstone.getDirectoryPath()+"etc" + File.separator + "main.cfg");
567 BufferedReader maincfg = new BufferedReader(new FileReader(mcfg));
568 stmp = "";
569 String fromaddr = "";
570 while((stmp = maincfg.readLine()) != null) {
571 if(stmp.startsWith("maintainer")) {
572 fromaddr = stmp.substring(10); //length of MailServer
573 fromaddr = fromaddr.trim();
574 break;
575 }
576 }
577 maincfg.close();
578 if(!fromaddr.equals("NULL") && !fromaddr.equals("null")) {
579 collection.schedule_options.setValue("fromaddr", false, fromaddr);
580 }
581
582 //try to obtain an smtp server address from main.cfg. If that fails,
583 //try mail.server if an email address exists. If that fails,
584 //maybe a message to set attribute in main.cfg?
585 //i'm pretty sure there exists functionality to do this, but
586 //i'll finish this faster if I just wrote it
587
588
589 maincfg = new BufferedReader(new FileReader(mcfg));
590 String smtptmp = "NULL";
591 while((stmp = maincfg.readLine()) != null) {
592 if(stmp.startsWith("MailServer")) {
593 smtptmp = stmp.substring(10); //length of MailServer
594 smtptmp = smtptmp.trim();
595 break;
596 }
597 }
598 maincfg.close();
599
600 //try if lookup failes
601 if(smtptmp.equals("NULL") || smtptmp.equals("null")) {
602 String email2=fromaddr;
603 if(!email2.equals("NULL") && !email2.equals("null")) {
604 int loc = email2.indexOf('@');
605 email2 = email2.substring(loc+1);
606 smtptmp = "mail."+email2;
607 }
608 }
609 if(!smtptmp.equals("NULL") && !smtptmp.equals("null")) {
610 collection.schedule_options.setValue("smtp", false, smtptmp);
611 }
612
613 MetadataSetManager.clearMetadataSets();
614 MetadataXMLFileManager.clearMetadataXMLFiles();
615 DocXMLFileManager.clearDocXMLFiles();
616
617 // Import default metadata sets, if any
618 // for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
619 // importMetadataSet((MetadataSet) metadata_sets.get(i));
620 // }
621
622 ProfileXMLFileManager.loadProfileXMLFile(new File(collection_directory_path + "metadata"));
623
624 // Before creating the CollectionDesignManager check if we are basing it upon some other collection
625 if (base_collection_directory != null) {
626 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
627
628 // If we're using a remote Greenstone server, download the collection shell to get the files needed
629 if (Gatherer.isGsdlRemote) {
630 String base_collection_name = base_collection_directory.getName();
631 RemoteGreenstoneServer.downloadCollection(base_collection_name);
632 }
633
634 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
635 // copy over other needed directories
636 copyExtraBaseCollStuff(new File(collection_directory_path), base_collection_directory);
637
638 // Try to import any existing metadata sets for this collection
639 // Look in base_collection_directory/metadata and import any metadata sets found.
640 File base_metadata_directory = new File(base_collection_directory, "metadata");
641 ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
642 if (base_metadata_sets != null) {
643 for (int i = 0; i < base_metadata_sets.size(); i++) {
644 importMetadataSet((MetadataSet) base_metadata_sets.get(i));
645 }
646 }
647 else {
648 DebugStream.println("This base collection has no metadata directory.");
649 }
650
651 // Now we update our collect.cfg
652 DebugStream.println("Copy and update " + file_name + " from base collection.");
653
654 if (Gatherer.GS3 == true) {
655 updateCollectionConfigXML(new File(base_collection_directory, Utility.CONFIG_GS3_FILE),
656 new File(collection_directory_path, Utility.CONFIG_GS3_FILE));
657 } else {
658 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE),
659 new File(collection_directory_path, Utility.CONFIG_FILE),
660 description, email, title);
661 }
662 }
663
664 // Load the default metadata sets
665 addDefaultMetadataSets();
666
667 // Make sure we always have the extracted metadata set
668 addRequiredMetadataSets();
669
670 collection.cdm = new CollectionDesignManager(new File(getLoadedCollectionCfgFilePath()));
671
672 // We always set title and description here rather than calling mkcol.pl with Unicode arguments
673 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
674 collection_name_collectionmeta.setValue(title);
675 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
676 collection_extra_collectionmeta.setValue(description);
677
678 // Now that we have a CDM, update several settings, such as if we created this collection by basing it on another, set it as public automatically. This update is done to the internal xml structure which may be saved into collect.cfg or collectionConfig.xml accordingly.
679 if (base_collection_directory != null) {
680 // Update the creator and maintainer
681 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
682 creator_collectionmeta.setValue(email);
683 creator_collectionmeta = null;
684 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
685 maintainer_collectionmeta.setValue(email);
686 maintainer_collectionmeta = null;
687
688 // All collections based on others are automatically public
689 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
690 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
691 public_collectionmeta = null;
692
693 // Finally reset the icons
694 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
695 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
696 icon_collection_collectionmeta = null;
697 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
698 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
699 icon_collection_small_collectionmeta = null;
700 }
701
702 saveCollection();
703
704 // Create a lock file
705 createLockFile(new File(collection_directory_path, LOCK_FILE));
706
707 // We're done. Let everyone know.
708 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
709 }
710 catch (Exception error) {
711 DebugStream.printStackTrace(error);
712 }
713 }
714
715
716 private void createLockFile(File lock_file)
717 {
718 try {
719 Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
720 String user_name = System.getProperty("user.name");
721 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
722 person_element.appendChild(default_lockfile.createTextNode(user_name));
723 person_element = null;
724 user_name = null;
725 String machine_name = Utility.getMachineName();
726 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
727 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
728 machine_element = null;
729 machine_name = null;
730 String date_time = Utility.getDateString();
731 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
732 date_element.appendChild(default_lockfile.createTextNode(date_time));
733 date_element = null;
734 date_time = null;
735 XMLTools.writeXMLFile(lock_file, default_lockfile);
736 }
737 catch (Exception exception) {
738 DebugStream.printStackTrace(exception);
739 }
740 }
741
742
743 public boolean deleteCollection(String collection_name)
744 {
745 // First we must release the collection from the local library, if it's running
746 if (LocalLibraryServer.isRunning() == true) {
747 LocalLibraryServer.releaseCollection(collection_name);
748 }
749
750 // Delete the collection on the server if we're using a remote Greenstone
751 if (Gatherer.isGsdlRemote) {
752 RemoteGreenstoneServer.deleteCollection(collection_name);
753 }
754
755 // Now delete the collection directory
756 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
757 }
758
759
760 public void fireFileAddedToCollection(File file)
761 {
762 // Send the event off to all the CollectionContentsChangedListeners
763 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
764 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
765 }
766 }
767
768
769 /** Retrieve the current collection.
770 * @return The <strong>Collection</strong> itself.
771 */
772 public Collection getCollection() {
773 return collection;
774 }
775
776
777 /** Returns the absolute filename of the specified collection's directory.
778 */
779 static public String getCollectionDirectoryPath(String collection_name)
780 {
781 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
782 }
783
784
785 /** Returns the absolute filename of the loaded collection's archives directory.
786 */
787 static public String getLoadedCollectionArchivesDirectoryPath()
788 {
789 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
790 }
791
792 /** Returns the absolute filename of the loaded collection's export directory.
793 */
794 static public String getLoadedCollectionExportDirectoryPath()
795 {
796 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
797 }
798
799
800
801 /** Returns the absolute filename of the loaded collection's building directory.
802 */
803 static public String getLoadedCollectionBuildingDirectoryPath()
804 {
805 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
806 }
807
808
809 /** Returns the absolute filename of the loaded collection's collect.cfg file.
810 */
811 static public String getLoadedCollectionCfgFilePath()
812 {
813 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
814 return getLoadedCollectionEtcDirectoryPath() + path;
815 }
816
817
818 /** Returns the absolute filename of the loaded collection's directory.
819 */
820 static public String getLoadedCollectionDirectoryPath()
821 {
822 return Gatherer.getCollectDirectoryPath() + collection.getName() + File.separator;
823 }
824
825
826 /** Returns the absolute filename of the loaded collection's etc directory.
827 */
828 static public String getLoadedCollectionEtcDirectoryPath()
829 {
830 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
831 }
832
833
834 /** Returns the absolute filename of the loaded collection's .col file.
835 */
836 static public String getLoadedCollectionColFilePath()
837 {
838 return getLoadedCollectionDirectoryPath() + collection.getName() + ".col";
839 }
840
841
842 /** Returns the absolute filename of the loaded collection's images directory.
843 */
844 static public String getLoadedCollectionImagesDirectoryPath()
845 {
846 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
847 }
848
849
850 /** Returns the absolute filename of the loaded collection's import directory.
851 */
852 static public String getLoadedCollectionImportDirectoryPath()
853 {
854 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
855 }
856
857
858 /** Returns the absolute filename of the loaded collection's index directory.
859 */
860 static public String getLoadedCollectionIndexDirectoryPath()
861 {
862 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
863 }
864
865
866 /** Returns the absolute filename of the loaded collection's log directory.
867 */
868 static public String getLoadedCollectionLogDirectoryPath()
869 {
870 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
871 }
872
873
874 /** Returns the absolute filename of the loaded collection's macros directory.
875 */
876 static public String getLoadedCollectionMacrosDirectoryPath()
877 {
878 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
879 }
880
881
882 /** Returns the absolute filename of the loaded collection's metadata directory.
883 */
884 static public String getLoadedCollectionMetadataDirectoryPath()
885 {
886 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
887 }
888
889
890 /** Returns the name of the loaded collection.
891 */
892 static public String getLoadedCollectionName()
893 {
894 if (collection != null) {
895 return collection.getName();
896 }
897
898 return null;
899 }
900
901
902 public CollectionTree getCollectionTree()
903 {
904 if (collection_tree == null) {
905 collection_tree = new CollectionTree(collection_tree_model, true);
906 }
907
908 return collection_tree;
909 }
910
911
912 /** Retrieve the tree model associated with the current collection. */
913 public CollectionTreeModel getCollectionTreeModel()
914 {
915 if (collection_tree_model == null && collection != null) {
916 // Use the import directory to generate a new CollectionTreeModel
917 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
918 // Ensure that the manager is a change listener for the tree.
919 if (fm_tree_model_listener == null) {
920 fm_tree_model_listener = new FMTreeModelListener();
921 }
922 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
923 }
924 return collection_tree_model;
925 }
926
927
928 /** This method when called, creates a new GShell in order to run the import.pl script.
929 * @see org.greenstone.gatherer.Configuration
930 * @see org.greenstone.gatherer.Gatherer
931 * @see org.greenstone.gatherer.gui.BuildOptions
932 * @see org.greenstone.gatherer.shell.GShell
933 * @see org.greenstone.gatherer.shell.GShellListener
934 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
935 * @see org.greenstone.gatherer.util.Utility
936 */
937 public void importCollection() {
938 importing = true;
939
940 if (!saved()) {
941 DebugStream.println("CollectionManager.importCollection().forcesave");
942 import_monitor.saving();
943 saveCollection();
944 }
945
946 DebugStream.println("CollectionManager.importCollection()");
947 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
948 //check that we can remove the old index before starting import
949 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
950 if (index_dir.exists()) {
951 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
952 if (!canDelete(index_dir)) {
953 // tell the user
954 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
955 // tell the gui manager
956 // a message for the building log
957 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
958 Gatherer.g_man.create_pane.message(event);
959 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
960 Gatherer.g_man.create_pane.processComplete(event);
961 importing = false;
962 return;
963 }
964 }
965
966 // Generate the import.pl command
967 ArrayList command_parts_list = new ArrayList();
968 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
969 command_parts_list.add(Configuration.perl_path);
970 command_parts_list.add("-S");
971 }
972
973 if (Configuration.fedora_info.isActive()) {
974 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-import.pl");
975
976 command_parts_list.add("-hostname");
977 command_parts_list.add(Configuration.fedora_info.getHostname());
978
979 command_parts_list.add("-port");
980 command_parts_list.add(Configuration.fedora_info.getPort());
981
982 command_parts_list.add("-username");
983 command_parts_list.add(Configuration.fedora_info.getUsername());
984
985 command_parts_list.add("-password");
986 command_parts_list.add(Configuration.fedora_info.getPassword());
987
988 command_parts_list.add("-protocol");
989 command_parts_list.add(Configuration.fedora_info.getProtocol());
990 }
991 else {
992 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
993 }
994
995 command_parts_list.add("-gli");
996 command_parts_list.add("-language");
997 command_parts_list.add(Configuration.getLanguage());
998 command_parts_list.add("-collectdir");
999 command_parts_list.add(getCollectDirectory());
1000
1001 String[] import_options = collection.import_options.getValues();
1002 for (int i = 0; i < import_options.length; i++) {
1003 command_parts_list.add(import_options[i]);
1004 }
1005
1006 command_parts_list.add(collection.getName());
1007
1008 // Run the import.pl command
1009 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1010 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1011 shell.addGShellListener(Gatherer.g_man.create_pane);
1012 shell.addGShellListener(Gatherer.g_man.format_pane);
1013 shell.start();
1014 DebugStream.println("CollectionManager.importCollection().return");
1015
1016 importing = false;
1017 }
1018
1019
1020 public void importMetadataSet(MetadataSet external_metadata_set)
1021 {
1022 // Copy the .mds file into the collection's "metadata" folder...
1023 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1024
1025 // ...but not if it is the redundant "hidden.mds" file
1026 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1027 return;
1028 }
1029
1030 // ...and only if it doesn't already exist
1031 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1032 if (!metadata_set_file.exists()) {
1033 try {
1034 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1035
1036 // If we're using a remote Greenstone server, upload the metadata file
1037 if (Gatherer.isGsdlRemote) {
1038 RemoteGreenstoneServer.uploadCollectionFile(collection.getName(), metadata_set_file);
1039 }
1040 }
1041 catch (Exception exception) {
1042 DebugStream.printStackTrace(exception);
1043 }
1044
1045 // Load it into the MetadataSetManager
1046 MetadataSetManager.loadMetadataSet(metadata_set_file);
1047 }
1048 }
1049
1050
1051 /** Determine if we are currently in the middle of importing (and thus, in this case, we can't allow the log writer to exit). Boy was this a mission to track down. The cascade of crap rolls out something like this: Joe Schmo clicks 'Build Collection', which calls the importCollection() method above, which in turn saves the collection with a saveTask, which fires a collectionChanged message once its finished, which drives the list of logs shown on the create pane to update, which fires a itemChanged() event to the OptionsPane who dutifully tells the current log writer thread to finish up writing (all zero lines its been asked to write) and then die. Wereapon Joe Schmo gets a pretty log to look at, but it isn't actually being written to file so the next time he tries to view it faeces hits the air motion cooling device. Joy.
1052 * @return true if the gli is currently importing
1053 */
1054 public boolean isImporting() {
1055 return importing;
1056 }
1057
1058
1059 public void loadCollection(String collection_file_path)
1060 {
1061 // Display a modal progress popup to indicate that the collection is being loaded
1062 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1063 load_collection_progress_popup.display();
1064
1065 // Load the collection on a separate thread so the progress bar updates correctly
1066 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1067 }
1068
1069
1070 private class LoadCollectionTask
1071 extends Thread
1072 {
1073 private String collection_file_path = null;
1074 private ModalProgressPopup load_collection_progress_popup = null;
1075
1076 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1077 {
1078 this.collection_file_path = collection_file_path;
1079 this.load_collection_progress_popup = load_collection_progress_popup;
1080 }
1081
1082 public void run()
1083 {
1084 loadCollectionInternal(collection_file_path);
1085 load_collection_progress_popup.close();
1086 Gatherer.setMenuBarEnabled(true);
1087 }
1088 }
1089
1090
1091 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1092 * @param location The path to the collection as a <strong>String</strong>.
1093 * @see org.greenstone.gatherer.Configuration
1094 * @see org.greenstone.gatherer.Gatherer
1095 * @see org.greenstone.gatherer.collection.Collection
1096 * @see org.greenstone.gatherer.util.Utility
1097 */
1098 private void loadCollectionInternal(String location)
1099 {
1100 DebugStream.println("Loading collection " + location + "...");
1101
1102 if (Gatherer.isGsdlRemote) {
1103 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
1104 if (RemoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1105 return;
1106 }
1107 }
1108
1109 // Check we have actually been given a .col file.
1110 if (!location.endsWith(".col")) {
1111 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1112 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1113 return;
1114 }
1115
1116 // Check that the collection configuration file is available
1117 File collection_file = new File(location);
1118
1119 // Ensure that the directory exists
1120 File collection_directory = collection_file.getParentFile();
1121
1122 if (collection_directory == null || !collection_directory.exists()) {
1123 // We can't open this
1124 System.err.println("CollectionManager.loadCollection: No collection directory.");
1125 return;
1126 }
1127
1128 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1129 File collection_config_file = new File(collection_directory, file_str);
1130 if (!collection_config_file.exists()) {
1131 System.err.println("CollectionManager.loadCollection: No config file.");
1132 collection_directory = null;
1133 collection_config_file = null;
1134 return;
1135 }
1136
1137 // Ensure that an import directory exists for this collection
1138 File collection_import_directory = new File(collection_directory, "import");
1139 if (!collection_import_directory.exists()) {
1140 collection_import_directory.mkdir();
1141 }
1142
1143 // Special case of a user trying to open an old greenstone collection.
1144 boolean non_gli_collection = false;
1145 File collection_metadata_directory = new File(collection_directory, "metadata");
1146 if (!collection_metadata_directory.exists()) {
1147 DebugStream.println("Loading non-gatherer collection...");
1148 // Show a warning message in case user wants to quit now
1149 non_gli_collection = true;
1150 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1151 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1152 legacy_dialog.dispose();
1153 collection_directory = null;
1154 collection_config_file = null;
1155 return;
1156 }
1157 legacy_dialog.dispose();
1158
1159 }
1160
1161 // Now determine if a lock already exists on this collection.
1162 String collection_name = collection_directory.getName();
1163 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1164 if (lock_file.exists()) {
1165 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1166 int choice = dialog.getChoice();
1167 dialog.dispose();
1168 dialog = null;
1169
1170 if (choice != LockFileDialog.YES_OPTION) {
1171 // user has cancelled
1172 lock_file = null;
1173 collection_directory = null;
1174 collection_config_file = null;
1175 return;
1176 }
1177
1178 lock_file.delete();
1179 }
1180
1181 try {
1182 // Create a lock file.
1183 createLockFile(lock_file);
1184 // This lock file may not have been created so check
1185 if(!lock_file.canWrite()) {
1186 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1187 System.err.println("Cannot write lock file!");
1188 String args[] = new String[2];
1189 args[0] = location;
1190 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1191 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1192 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1193 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1194 //}
1195 }
1196 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1197 args = null;
1198 return;
1199 }
1200
1201 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1202
1203 //First, see if "Schedule" exists in the XMl File...
1204 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1205 boolean flag = false;
1206 try {
1207 String stmp = new String();
1208
1209 while((stmp = bir.readLine()) != null) {
1210 stmp = stmp.trim();
1211 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1212 flag = true;
1213 break;
1214 }
1215 }
1216 bir.close();
1217
1218 } catch (IOException ioe) {
1219 //do something here
1220 }
1221
1222 //modify if old .col (i.e. no Schedule exists in XML file)
1223 if(!flag) {
1224 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1225
1226
1227 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1228 bir = new BufferedReader(new FileReader(collection_file));
1229
1230 try {
1231 String stmp = new String();
1232 while((stmp = bir.readLine()) != null) {
1233 String stmp2 = stmp.trim();
1234 if(stmp2.startsWith("<!ELEMENT Argument")) {
1235 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1236 }
1237 else if(stmp2.equals("</BuildConfig>")) {
1238 bor.write(" <Schedule/>\n");
1239 }
1240
1241 bor.write(stmp + "\n");
1242
1243 }
1244 bir.close();
1245 bor.close();
1246 } catch (IOException ioe) {
1247 //do something here
1248 }
1249
1250 //copy over tmp.col to replace
1251 try {
1252 collection_file.delete();
1253 new_collection_file.renameTo(collection_file);
1254 } catch (Exception e) {
1255 //do something here
1256 }
1257 }
1258
1259 // Open the collection file
1260 this.collection = new Collection(collection_file);
1261 if (collection.error) {
1262 collection = null;
1263 // Remove lock file
1264 if (lock_file.exists()) {
1265 lock_file.delete();
1266 }
1267 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1268 }
1269
1270
1271 //try to obtain email address of collection owner if it exists...
1272 String stmp = Configuration.getEmail();
1273 if(stmp != null) {
1274 collection.schedule_options.setValue("toaddr", false, Configuration.getEmail());
1275 }
1276
1277
1278
1279 //The next few items deal with updating the SMTP server, and the to: and from: addresses
1280 //from main.cfg and the collection configuration. if no changes are made, or the
1281 //values are result to NULL, any existing values are kept.
1282
1283 //try to obtain email address of Greenstone installation webmaster for - used to indicate "sender".
1284 File mcfg = new File(LocalGreenstone.getDirectoryPath()+"etc" + File.separator + "main.cfg");
1285 BufferedReader maincfg = new BufferedReader(new FileReader(mcfg));
1286 stmp = "";
1287 String fromaddr = "";
1288 while((stmp = maincfg.readLine()) != null) {
1289 if(stmp.startsWith("maintainer")) {
1290 fromaddr = stmp.substring(10); //length of MailServer
1291 fromaddr = fromaddr.trim();
1292 break;
1293 }
1294 }
1295 maincfg.close();
1296 if(!fromaddr.equals("NULL") && !fromaddr.equals("null")) {
1297 collection.schedule_options.setValue("fromaddr", false, fromaddr);
1298 }
1299
1300 //try to obtain an smtp server address from main.cfg. If that fails,
1301 //try mail.server if an email address exists. If that fails,
1302 //maybe a message to set attribute in main.cfg?
1303 //i'm pretty sure there exists functionality to do this, but
1304 //i'll finish this faster if I just wrote it
1305
1306
1307 maincfg = new BufferedReader(new FileReader(mcfg));
1308 String smtptmp = "NULL";
1309 while((stmp = maincfg.readLine()) != null) {
1310 if(stmp.startsWith("MailServer")) {
1311 smtptmp = stmp.substring(10); //length of MailServer
1312 smtptmp = smtptmp.trim();
1313 break;
1314 }
1315 }
1316 maincfg.close();
1317
1318 //try if lookup failes
1319 if(smtptmp.equals("NULL") || smtptmp.equals("null")) {
1320 String email2=fromaddr;
1321 if(!email2.equals("NULL") && !email2.equals("null")) {
1322 int loc = email2.indexOf('@');
1323 email2 = email2.substring(loc+1);
1324 smtptmp = "mail."+email2;
1325 }
1326 }
1327 if(!smtptmp.equals("NULL") && !smtptmp.equals("null")) {
1328 collection.schedule_options.setValue("smtp", false, smtptmp);
1329 }
1330
1331
1332 MetadataSetManager.clearMetadataSets();
1333 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1334
1335 // Make sure we always have the extracted metadata set
1336 addRequiredMetadataSets();
1337
1338 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1339
1340 // If this is a non-GLI (legacy) collection, load the default metadata sets
1341 if (non_gli_collection) {
1342 addDefaultMetadataSets();
1343
1344 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1345 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1346 }
1347
1348 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1349 MetadataXMLFileManager.clearMetadataXMLFiles();
1350 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1351
1352 // Read through the doc.xml files in the archives directory
1353 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1354 DocXMLFileManager.clearDocXMLFiles();
1355 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
1356
1357 // Get a list of the collection specific classifiers and plugins
1358 Classifiers.loadClassifiersList(collection_name);
1359 Plugins.loadPluginsList(collection_name);
1360
1361 collection.cdm = new CollectionDesignManager(collection_config_file);
1362 if (non_gli_collection) {
1363 // Change the classifiers to use the namespaced element names
1364 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1365 }
1366
1367 // We're done. Let everyone know.
1368 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1369 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1370 }
1371 catch (Exception error) {
1372 // There is obviously no existing collection present.
1373 DebugStream.printStackTrace(error);
1374 error.printStackTrace();
1375 if(error.getMessage() != null) {
1376 String[] args = new String[2];
1377 args[0] = location;
1378 //args[1] = error.getMessage();
1379 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1380 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1381 }
1382 else {
1383 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1384 }
1385 }
1386
1387 lock_file = null;
1388 collection_directory = null;
1389 collection_config_file = null;
1390 }
1391
1392
1393 private void makeCollection(String name, String email)
1394 {
1395 // Generate the mkcol.pl command
1396 ArrayList command_parts_list = new ArrayList();
1397 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1398 command_parts_list.add(Configuration.perl_path);
1399 command_parts_list.add("-S");
1400 }
1401 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1402 if(Gatherer.GS3) {
1403 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1404 }
1405
1406 command_parts_list.add("-collectdir");
1407 command_parts_list.add(getCollectDirectory());
1408
1409 command_parts_list.add("-win31compat");
1410 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1411
1412 if (email != null && !email.equals("")) {
1413 command_parts_list.add("-creator");
1414 command_parts_list.add(email);
1415 }
1416
1417 command_parts_list.add(name);
1418
1419 // Run the mkcol.pl command
1420 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1421 //for(int i = 0; i < command_parts.length; i++) {
1422 ///ystem.err.println("\""+command_parts[i]+"\"");
1423 //}
1424
1425 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1426 process.run(); // Don't bother threading this... yet
1427 }
1428
1429
1430 /** Any implementation of GShellListener must include this method to allow the GShell to send messages to listeners. However in this case the CollectionManager is in no way interested in what the messages are, just the import events which have a specific type and are handled elsewhere. Thus we can safely ignore this event.
1431 * @param event A <strong>GShellEvent</strong> which contains a the message.
1432 */
1433 public synchronized void message(GShellEvent event) {
1434
1435 }
1436
1437
1438 public void metadataChanged(CollectionTreeNode[] file_nodes)
1439 {
1440 if (collection != null) {
1441 collection.setMetadataChanged(true);
1442 }
1443 }
1444
1445
1446 public void openCollectionFromLastTime() {
1447 // If there was an open collection last session, reopen it
1448 if (Gatherer.open_collection_file_path != null) {
1449 // Load the collection now
1450 loadCollection(Gatherer.open_collection_file_path);
1451 }
1452
1453 }
1454
1455
1456 /** This call is fired whenever a process within a GShell created by this class begins.
1457 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1458 * @see org.greenstone.gatherer.Gatherer
1459 * @see org.greenstone.gatherer.gui.GUIManager
1460 * @see org.greenstone.gatherer.shell.GShell
1461 */
1462 public synchronized void processBegun(GShellEvent event) {
1463 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1464 ///ystem.err.println("ProcessBegun " + event.getType());
1465 // If this is one of the types where we wish to lock user control
1466 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1467 }
1468 /** This call is fired whenever a process within a GShell created by this class ends.
1469 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1470 * @see org.greenstone.gatherer.Gatherer
1471 * @see org.greenstone.gatherer.gui.GUIManager
1472 * @see org.greenstone.gatherer.shell.GShell
1473 */
1474 public synchronized void processComplete(GShellEvent event) {
1475 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1476 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1477 ///ystem.err.println("Recieved process complete event - " + event);
1478 // If we were running an import, now run a build.
1479 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1480 // Finish import.
1481 collection.setImported(true);
1482 collection.setFilesChanged(false);
1483 collection.setMetadataChanged(false);
1484 buildCollection(false);
1485 }
1486 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1487
1488 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1489 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1490 collection_built_warning_dialog.display();
1491 collection_built_warning_dialog.dispose();
1492 collection_built_warning_dialog = null;
1493 }
1494 // If we were running a build, now is when we move files across.
1495 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1496
1497 if(installCollection()) {
1498 // If we have a local library running then ask it to add our newly create collection
1499 if (LocalLibraryServer.isRunning() == true) {
1500 LocalLibraryServer.addCollection(collection.getName());
1501 }
1502 else if (Gatherer.GS3) {
1503 //xiao comment out this: convertToGS3Collection();
1504 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1505 }
1506
1507 // Fire a collection changed first to update the preview etc buttons
1508 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1509
1510 // Now display a message dialog saying its all built
1511 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1512 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1513 collection_built_warning_dialog.display();
1514 collection_built_warning_dialog.dispose();
1515 collection_built_warning_dialog = null;
1516
1517 //Set nothing as needing rebuilding, as a build has just finished :-)
1518 CollectionDesignManager.resetRebuildTypeRequired();
1519 }
1520 else {
1521 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1522 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1523 DebugStream.println("Status is ok but !installCollection()");
1524 }
1525 }
1526 else if (event.getStatus() == GShell.CANCELLED) {
1527 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1528 Gatherer.g_man.repaint();
1529 }
1530 else if (event.getStatus() == GShell.ERROR) {
1531 if (event.getType() == GShell.NEW) {
1532 String name = event.getMessage();
1533 String collectDir = getCollectionDirectoryPath(name);
1534 String errMsg = "";
1535 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1536 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1537 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1538 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1539 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1540 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1541 //}
1542 }
1543 } else {
1544 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1545 }
1546 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1547 }
1548 else if(event.getType() == GShell.SCHEDULE) {
1549 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1550 }
1551 else {
1552 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1553 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1554 }
1555
1556 Gatherer.g_man.repaint(); // It appears Java's own dialogs have the same not always painting correct area bug that I suffer from. Well I don't suffer from it personally, but my ModalDialog components do.
1557 }
1558 }
1559
1560
1561 /** Determine if the manager is ready for actions apon its collection.
1562 * @return A <i>boolean</i> which is <i>true</i> to indicate a collection has been loaded and thus the collection is ready for editing, <i>false</i> otherwise.
1563 */
1564 static public synchronized boolean ready() {
1565 if(collection != null) {
1566 return true;
1567 }
1568 else {
1569 return false;
1570 }
1571 }
1572
1573
1574 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1575 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1576 */
1577 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1578 build_monitor = monitor;
1579 }
1580 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1581 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1582 */
1583 public void registerImportMonitor(GShellProgressMonitor monitor) {
1584 import_monitor = monitor;
1585 }
1586
1587 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1588 schedule_monitor = monitor;
1589 }
1590
1591
1592 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1593 {
1594 collection_contents_changed_listeners.remove(listener);
1595 }
1596
1597
1598 public void removeMetadataSet(MetadataSet metadata_set)
1599 {
1600 DebugStream.println("Removing metadata set...");
1601
1602 // Delete the .mds file from the collection's "metadata" folder...
1603 File metadata_set_file = metadata_set.getMetadataSetFile();
1604
1605 // ...but not if it is the "ex.mds" file
1606 if (metadata_set_file.getName().equals("ex.mds")) {
1607 return;
1608 }
1609
1610 // ...and only if it exists
1611 if (metadata_set_file.exists()) {
1612 metadata_set_file.delete();
1613
1614 // Unload it from the MetadataSetManager
1615 MetadataSetManager.unloadMetadataSet(metadata_set);
1616
1617 // If we're using a remote Greenstone server, delete the metadata file on the server
1618 if (Gatherer.isGsdlRemote) {
1619 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), metadata_set_file);
1620 }
1621 }
1622 }
1623
1624
1625 /** Used to check whether all open collections have a 'saved' state.
1626 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1627 * @see org.greenstone.gatherer.collection.Collection
1628 */
1629 public boolean saved() {
1630 boolean result = true;
1631 if(collection != null) {
1632 result = collection.getSaved();
1633 }
1634 return result;
1635 }
1636
1637
1638 /** Saves the currently loaded collection. */
1639 public void saveCollection()
1640 {
1641
1642 if (collection == null) return;
1643
1644 DebugStream.println("Saving collection " + collection.getName() + "...");
1645
1646 // Change cursor to hourglass
1647 Gatherer.g_man.wait(true);
1648
1649 // Create a backup of the collection file, just in case anything goes wrong
1650 File collection_file = new File(getLoadedCollectionColFilePath());
1651 if (collection_file.exists()) {
1652 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1653 if (!collection_file.renameTo(collection_file_backup)) {
1654 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1655 }
1656 collection_file_backup.deleteOnExit();
1657 }
1658
1659 // Write out the collection file
1660 collection.save();
1661
1662 // Write out the collection configuration file
1663 collection.cdm.save();
1664
1665 // Change cursor back to normal
1666 Gatherer.g_man.wait(false);
1667 }
1668
1669
1670 /** I started giving the user the choice of using an existing meta set or creating a new one. The second option being so that they didn't have to add/merge/ignore each element, they could all be added automatically. However, I am not sure where the merge prompt gets called from, and it is not essential, so I am leaving it for now - it should be added back in and finished. [kjdon] */
1671 private void addDefaultMetadataSets()
1672 {
1673 // Add dublin core which is the default metadata set. The user
1674 // can change this later
1675 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1676 if (dc_file.exists()) {
1677 importMetadataSet(new MetadataSet(dc_file));
1678 }
1679 }
1680
1681
1682 private void addRequiredMetadataSets()
1683 {
1684 // Always import the extracted metadata set
1685 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1686 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1687 }
1688
1689
1690 // used as arg in the perl scripts
1691 private String getCollectDirectory() {
1692 String collect_dir = Gatherer.getCollectDirectoryPath();
1693
1694 // Remove erroneous file windows file separator as it causes problems when running import.pl
1695 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1696 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1697 }
1698
1699 return collect_dir;
1700 }
1701
1702
1703 /** Install collection by moving its files from building to index after a successful build.
1704 * @see org.greenstone.gatherer.Gatherer
1705 * @see org.greenstone.gatherer.util.Utility
1706 */
1707 private boolean installCollection()
1708 {
1709 if (Configuration.fedora_info.isActive()) {
1710 DebugStream.println("Fedora build complete. No need to move files.");
1711 return true;
1712 }
1713
1714
1715 DebugStream.println("Build complete. Moving files.");
1716
1717 try {
1718 // Ensure that the local library has released this collection so we can delete the index directory
1719 if (LocalLibraryServer.isRunning() == true) {
1720 LocalLibraryServer.releaseCollection(collection.getName());
1721 }
1722 // deactivate it in tomcat so that windows will release the index files
1723 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1724 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1725 }
1726 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1727 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1728
1729 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1730 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1731
1732 // Get the build mode from the build options
1733 String build_mode = collection.build_options.getValue("mode");
1734
1735 // Special case for build mode "all": replace index dir with building dir
1736 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1737 // Remove the old index directory
1738 if (index_dir.exists()) {
1739 Utility.delete(index_dir);
1740
1741 // Wait for a couple of seconds, just for luck
1742 wait(2000);
1743
1744 // Check the delete worked
1745 if (index_dir.exists()) {
1746 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1747 }
1748 }
1749
1750 if (Gatherer.isGsdlRemote) {
1751 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), new File(getLoadedCollectionIndexDirectoryPath()));
1752 RemoteGreenstoneServer.moveCollectionFile(collection.getName(), new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1753 }
1754
1755 // Move the building directory to become the new index directory
1756 if (building_dir.renameTo(index_dir) == false) {
1757 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1758 }
1759 }
1760
1761 // Otherwise copy everything in the building dir into the index dir
1762 else {
1763 moveContentsInto(building_dir, index_dir);
1764 }
1765 }
1766 catch (Exception exception) {
1767 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1768 return false;
1769 }
1770 return true;
1771 }
1772
1773
1774 /** Moves all the files in one directory into another, overwriting existing files */
1775 private void moveContentsInto(File source_directory, File target_directory)
1776 {
1777 File[] source_files = source_directory.listFiles();
1778 for (int i = 0; i < source_files.length; i++) {
1779 File source_file = source_files[i];
1780 File target_file = new File(target_directory, source_file.getName());
1781
1782 if (source_file.isDirectory()) {
1783 moveContentsInto(source_file, target_file);
1784 source_file.delete();
1785 }
1786 else {
1787 if (target_file.exists()) {
1788 target_file.delete();
1789 }
1790
1791 source_file.renameTo(target_file);
1792 }
1793 }
1794 }
1795
1796 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1797 //In this method, the files base_cfg and new_cfg are all xml files.
1798
1799 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1800 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1801 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1802 Element collection_config = new_cfg_doc.getDocumentElement();
1803
1804 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1805 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1806 int num_nodes = classifier_children.getLength();
1807
1808 if (num_nodes < 1) {
1809 return;
1810 }
1811
1812 // Read in the classifier command watching for hfile, metadata and sort arguments.
1813 String buttonname = null;
1814 String hfile = null;
1815 String metadata = null;
1816 String sort = null;
1817
1818 for (int i=0; i<num_nodes; i++) {
1819 Element classifier_element = (Element)classifier_children.item(i);
1820 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1821 for (int j=0; j<option_children.getLength(); j++) {
1822 Element option_element = (Element)option_children.item(j);
1823 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1824 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1825
1826 if (name_str == null || name_str.equals("")) {
1827 continue;
1828 }
1829 if (name_str != null && value_str == null ) {
1830 value_str = "";
1831 }
1832 if (name_str.equals("hfile")) {
1833 hfile = value_str;
1834 }
1835 else if (name_str.equals("metadata") && value_str != null) {
1836 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1837 if (replacement != null && !replacement.equals("")) {
1838 metadata = replacement;
1839 }
1840 }
1841 else if (name_str.equals("sort") && value_str != null) {
1842 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1843 if (replacement != null && !replacement.equals("")) {
1844 sort = replacement;
1845 }
1846 }
1847 else if(name_str.equals("buttonname") && value_str != null) {
1848 buttonname = value_str;
1849 }
1850 }
1851 }
1852 for (int i=0; i<num_nodes; i++) {
1853 Element classifier_element = (Element)classifier_children.item(i);
1854 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1855 for (int j=0; j<option_children.getLength(); j++) {
1856 Element option_element = (Element)option_children.item(j);
1857 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1858
1859 if (name_str.equals("metadata") && metadata != null) {
1860 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1861 }
1862 else if (name_str.equals("hfile") && hfile != null) {
1863 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1864 }
1865 else if (name_str.equals("sort") && sort != null) {
1866 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1867 }
1868 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1869 // No buttonname has been specified. Lets create one using the metadata as its value
1870 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1871 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1872 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1873 classifier_element.appendChild(option);
1874 }
1875 }
1876 }
1877 }
1878
1879 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1880 {
1881 boolean first_name = true;
1882 boolean first_extra = true;
1883
1884 // Now read in base_cfg line by line, parsing important onces and/or replacing them with information pertinent to our collection. Each line is then written back out to the new collect.cfg file.
1885 try {
1886 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1887 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1888 String command = null;
1889 while((command = in.readLine()) != null) {
1890 if (command.length()==0) {
1891 // output a new line
1892 out.newLine();
1893 continue;
1894 }
1895 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1896 while(command.trim().endsWith("\\")) {
1897 command = command.substring(0, command.lastIndexOf("\\"));
1898 String next_line = in.readLine();
1899 if(next_line != null) {
1900 command = command + next_line;
1901 }
1902 }
1903 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1904 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1905 String command_type_str = tokenizer.nextToken().toLowerCase();
1906
1907 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1908 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1909 StringBuffer new_command = new StringBuffer(command_type_str);
1910 String meta_name = tokenizer.nextToken();
1911 new_command.append(' ');
1912 new_command.append(meta_name);
1913 while (tokenizer.hasMoreTokens()) {
1914 new_command.append(' ');
1915 new_command.append(tokenizer.nextToken());
1916 }
1917 if (meta_name.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR)) {
1918 // dont save
1919 } else {
1920 write(out, new_command.toString());
1921 }
1922 new_command = null;
1923 continue;
1924 } // if collectionmeta
1925
1926 if (command_type_str.equals("classify")) {
1927 StringBuffer text = new StringBuffer(command_type_str);
1928 // Read in the classifier command watching for hfile, metadata and sort arguments.
1929 String buttonname = null;
1930 String hfile = null;
1931 String new_metadata = null;
1932 String old_metadata = null;
1933
1934 while(tokenizer.hasMoreTokens()) {
1935 String token = tokenizer.nextToken();
1936 if (token.equals("-hfile")) {
1937 if(tokenizer.hasMoreTokens()) {
1938 text.append(" ");
1939 text.append(token);
1940 token = tokenizer.nextToken();
1941 hfile = token;
1942 }
1943 }
1944 else if (token.equals("-metadata")) {
1945 if(tokenizer.hasMoreTokens()) {
1946 text.append(" ");
1947 text.append(token);
1948 String temp_metadata = tokenizer.nextToken();
1949 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1950 if (replacement != null && !replacement.equals("")) {
1951 token = replacement;
1952 old_metadata = temp_metadata;
1953 new_metadata = replacement;
1954 }
1955 else {
1956 token = temp_metadata;
1957 }
1958 temp_metadata = null;
1959 replacement = null;
1960 }
1961 }
1962 else if (token.equals("-sort")) {
1963 if(tokenizer.hasMoreTokens()) {
1964 text.append(" ");
1965 text.append(token);
1966 String temp_metadata = tokenizer.nextToken();
1967 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1968 if (replacement != null && !replacement.equals("")) {
1969 token = replacement;
1970 }
1971 else {
1972 token = temp_metadata;
1973 }
1974 temp_metadata = null;
1975 replacement = null;
1976 }
1977 }
1978 else if(token.equals("-buttonname")) {
1979 buttonname = token;
1980 }
1981 text.append(' ');
1982 text.append(token);
1983 token = null;
1984 }
1985
1986 // If we replaced the metadata argument and didn't encounter a buttonname, then add one now pointing back to the old metadata name in order to accomodate macro files which required such names (buttonname is metadata name by default)!
1987 if(old_metadata != null && new_metadata != null && buttonname == null) {
1988 text.append(' ');
1989 text.append("-buttonname");
1990 text.append(' ');
1991 text.append(old_metadata);
1992 }
1993 command = text.toString();
1994 // Replace the hfile if we found it
1995 if(hfile != null && new_metadata != null) {
1996 command = command.replaceAll(hfile, new_metadata + ".txt");
1997 }
1998
1999 buttonname = null;
2000 hfile = null;
2001 new_metadata = null;
2002 old_metadata = null;
2003 write(out, command);
2004 } else {
2005 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2006 StringBuffer new_command = new StringBuffer(command_type_str);
2007 while (tokenizer.hasMoreTokens()) {
2008 new_command.append(' ');
2009 new_command.append(tokenizer.nextToken());
2010 }
2011
2012 command = new_command.toString();
2013
2014 // There is still one special case, that of the format command. In such a command we have to search for [<target>] to ensure we don't change parts of the format which have nothing to do with the metadata elements.
2015 // we really want to build up the whole command here
2016 boolean format_command = command_type_str.equals("format");
2017 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2018 if (metadata_mapping != null) {
2019 Iterator keys = metadata_mapping.keySet().iterator();
2020 while (keys.hasNext()) {
2021 String target = (String) keys.next();
2022 String replacement = (String) metadata_mapping.get(target);
2023 if (replacement != null && !replacement.equals("")) {
2024 if (format_command) {
2025 target = "\\[" + target + "\\]";
2026 replacement = "{Or}{[" + replacement + "]," + target + "}";
2027 }
2028 command = command.replaceAll(target, replacement);
2029 }
2030 }
2031 }
2032
2033 write(out, command);
2034 }
2035 tokenizer = null;
2036 }
2037 in.close();
2038 in = null;
2039 out.flush();
2040 out.close();
2041 out = null;
2042 }
2043 catch(Exception error) {
2044 DebugStream.printStackTrace(error);
2045 }
2046 // All done, I hope.
2047 }
2048
2049 private void write(BufferedWriter out, String message)
2050 throws Exception {
2051 out.write(message, 0, message.length());
2052 out.newLine();
2053 }
2054
2055
2056 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2057 private class FMTreeModelListener
2058 implements TreeModelListener {
2059 /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
2060 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2061 */
2062 public void treeNodesChanged(TreeModelEvent event) {
2063 if(collection != null) {
2064 collection.setSaved(false);
2065 collection.setFilesChanged(true);
2066 }
2067 }
2068 /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
2069 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2070 */
2071 public void treeNodesInserted(TreeModelEvent event) {
2072 if(collection != null) {
2073 collection.setSaved(false);
2074 collection.setFilesChanged(true);
2075 }
2076 }
2077 /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
2078 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2079 */
2080 public void treeNodesRemoved(TreeModelEvent event) {
2081 if(collection != null) {
2082 collection.setSaved(false);
2083 collection.setFilesChanged(true);
2084
2085 }
2086 }
2087 /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
2088 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2089 */
2090 public void treeStructureChanged(TreeModelEvent event) {
2091 if(collection != null) {
2092 collection.setSaved(false);
2093 }
2094 }
2095 }
2096}
Note: See TracBrowser for help on using the repository browser.