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

Last change on this file since 19197 was 19197, checked in by ak19, 15 years ago

Tentative changes for getting the collectiongroup construct to work with the RemoteGreenstoneServer

  • Property svn:keywords set to Author Date Id Revision
File size: 83.0 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 and
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 != null && 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 Gatherer.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: all except import, archives, building, index
422 * really we just want images, macros, perllib, but there may also be eg style, or other dirs.
423 */
424 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
425 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
426 return false;
427 }
428 DebugStream.println("Copying extra dirs from the base collection");
429
430
431 File subdirs[] = base_coll_dir.listFiles();
432 for (int i = 0; subdirs != null && i < subdirs.length; i++) {
433 File subdir = subdirs[i];
434 if (subdir.isDirectory()) {
435 String dir_name = subdir.getName();
436 // ignore those we don't need, (archives, buildng, index) and
437 // those we are handling in another place (import, etc, metadata)
438 if (dir_name.startsWith ("import") || dir_name.startsWith("archives") || dir_name.startsWith("building") || dir_name.startsWith("index") || dir_name.startsWith("etc") || dir_name.startsWith("metadata") || dir_name.startsWith("log") || dir_name.startsWith("tmp")) {
439 continue;
440 }
441 try {
442 // copy the directory
443 File new_coll_subdir = new File(new_coll_dir, dir_name);
444 new_coll_subdir.mkdirs();
445 Gatherer.f_man.getQueue().copyDirectoryContents(subdir, new_coll_subdir);
446 }
447 catch (Exception e) {
448 DebugStream.println("Couldn't copy over the" + subdir+" dir from the base collection: "+e.toString());
449 }
450 }
451 }
452
453 return true;
454 }
455
456 /** 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.
457 * @param description a description of the collection as a String
458 * @param email the email address of the author/maintainer as a String
459 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
460 * @param title the longer title of the collection as a String
461 * @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
462 * @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
463 */
464 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
465 {
466 // Display a modal progress popup to indicate that the collection is being loaded
467 ModalProgressPopup create_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Creating_Collection"), Dictionary.get("CollectionManager.Creating_Collection_Please_Wait"));
468 create_collection_progress_popup.display();
469
470 // Create the collection on a separate thread so the progress bar updates correctly
471 (new CreateCollectionTask(description, email, name, title, base_collection_directory, metadata_sets, create_collection_progress_popup)).start();
472 }
473
474
475 private class CreateCollectionTask
476 extends Thread
477 {
478 private String description = null;
479 private String email = null;
480 private String name = null;
481 private String title = null;
482 private File base_collection_directory = null;
483 private ArrayList metadata_sets = null;
484 private ModalProgressPopup create_collection_progress_popup = null;
485
486 public CreateCollectionTask(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets, ModalProgressPopup create_collection_progress_popup)
487 {
488 this.description = description;
489 this.email = email;
490 this.name = name;
491 this.title = title;
492 this.base_collection_directory = base_collection_directory;
493 this.metadata_sets = metadata_sets;
494 this.create_collection_progress_popup = create_collection_progress_popup;
495 }
496
497 public void run()
498 {
499 createCollectionInternal(description, email, name, title, base_collection_directory, metadata_sets);
500 create_collection_progress_popup.close();
501 }
502 }
503
504
505 private void createCollectionInternal(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
506 {
507 try {
508 // first make sure that the collect directory exists
509 File collect_dir = new File(getDefaultCollectDirectory());
510 if (!collect_dir.exists()) {
511 collect_dir.mkdirs();
512 }
513
514 // Create the new collection
515 makeCollection(name, email);
516
517 // Check that the collection has been created successfully
518 String collection_directory_path = getCollectionDirectoryPath(name);
519 if (!new File(collection_directory_path).exists()) {
520 // If there is no collection directory then the creation was unsuccessful, or cancelled
521
522 return;
523 }
524
525 // Check for the existence of the collection configuration file
526 String file_name = ((Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG);
527 File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + file_name);
528
529 if (!collect_cfg_file.exists()) {
530 System.err.println("Error: no " + file_name + " file has been created!");
531 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);
532 return;
533 }
534
535 // ACTIVE_DIR/log/
536 File log_dir = new File(collection_directory_path + "log");
537 log_dir.mkdirs();
538
539 // Make sure an import folder exists
540 File collection_import_directory = new File(collection_directory_path + "import");
541 if (!collection_import_directory.exists()) {
542 collection_import_directory.mkdirs();
543 if (Gatherer.isGsdlRemote) {
544 Gatherer.remoteGreenstoneServer.newCollectionDirectory(name, collection_import_directory);
545 }
546 }
547
548 // Now create the collection object around the directory.
549 collection = new Collection(new File(collection_directory_path, name + ".col"));
550
551 // "-removeold" is on by default for import.pl
552 collection.import_options.setValue("removeold", true, null);
553
554 // for remote case, scheduling causes an Exception on creating a new collection that
555 // can't be recovered from. For GS3, it doesn't work since it it trying to access etc/main.cfg
556 if (canDoScheduling()) {
557 scheduling();
558 }
559
560 MetadataSetManager.clearMetadataSets();
561 MetadataXMLFileManager.clearMetadataXMLFiles();
562 DocXMLFileManager.clearDocXMLFiles();
563
564 // Import default metadata sets, if any
565 // for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
566 // importMetadataSet((MetadataSet) metadata_sets.get(i));
567 // }
568
569 ProfileXMLFileManager.loadProfileXMLFile(new File(collection_directory_path + "metadata"));
570
571 // Before creating the CollectionDesignManager check if we are basing it upon some other collection
572 if (base_collection_directory != null) {
573 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
574
575 // If we're using a remote Greenstone server, download the collection shell to get the files needed
576 if (Gatherer.isGsdlRemote) {
577 String base_collection_name = base_collection_directory.getName();
578 Gatherer.remoteGreenstoneServer.downloadCollection(base_collection_name);
579 }
580
581 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
582 // copy over other needed directories
583 copyExtraBaseCollStuff(new File(collection_directory_path), base_collection_directory);
584
585 // Try to import any existing metadata sets for this collection
586 // Look in base_collection_directory/metadata and import any metadata sets found.
587 File base_metadata_directory = new File(base_collection_directory, "metadata");
588 ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
589 if (base_metadata_sets != null) {
590 for (int i = 0; i < base_metadata_sets.size(); i++) {
591 importMetadataSet((MetadataSet) base_metadata_sets.get(i));
592 }
593 }
594 else {
595 DebugStream.println("This base collection has no metadata directory.");
596 }
597
598 // Now we update our collect.cfg
599 DebugStream.println("Copy and update " + file_name + " from base collection.");
600
601 if (Gatherer.GS3 == true) {
602 updateCollectionConfigXML(new File(base_collection_directory, Utility.CONFIG_GS3_FILE),
603 new File(collection_directory_path, Utility.CONFIG_GS3_FILE));
604 } else {
605 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE),
606 new File(collection_directory_path, Utility.CONFIG_FILE),
607 description, email, title);
608 }
609 }
610 else {
611 // only load metadata sets here if we have not based the collection on any other.
612 // Load the default metadata sets
613 addDefaultMetadataSets();
614
615 // Make sure we always have the extracted metadata set
616 addRequiredMetadataSets();
617 }
618
619 collection.cdm = new CollectionDesignManager(new File(getLoadedCollectionCfgFilePath()));
620
621 // We always set title and description here rather than calling mkcol.pl with Unicode arguments
622 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
623 collection_name_collectionmeta.setValue(title);
624 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
625 collection_extra_collectionmeta.setValue(description);
626
627 // 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.
628 if (base_collection_directory != null) {
629 // Update the creator and maintainer
630 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
631 creator_collectionmeta.setValue(email);
632 creator_collectionmeta = null;
633 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
634 maintainer_collectionmeta.setValue(email);
635 maintainer_collectionmeta = null;
636
637 // All collections based on others are automatically public
638 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
639 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
640 public_collectionmeta = null;
641
642 // Finally reset the icons
643 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
644 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
645 icon_collection_collectionmeta = null;
646 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
647 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
648 icon_collection_small_collectionmeta = null;
649 }
650
651 saveCollection();
652
653 // Create a lock file
654 createLockFile(new File(collection_directory_path, LOCK_FILE));
655
656 // We're done. Let everyone know.
657 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
658 }
659 catch (Exception error) {
660 DebugStream.printStackTrace(error);
661 }
662 }
663
664 private void scheduling()
665 throws Exception
666 {
667 //try to obtain email address of collection owner if it exists...
668 String stmp = Configuration.getEmail();
669 if(stmp != null) {
670 collection.schedule_options.setValue("toaddr", false, Configuration.getEmail());
671 }
672
673 //The next few items deal with updating the SMTP server, and the to: and from: addresses
674 //from main.cfg and the collection configuration. if no changes are made, or the
675 //values are result to NULL, any existing values are kept.
676
677 //try to obtain email address of Greenstone installation webmaster for - used to indicate "sender".
678 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
679 BufferedReader maincfg = new BufferedReader(new FileReader(mcfg));
680 stmp = "";
681 String fromaddr = "";
682 while((stmp = maincfg.readLine()) != null) {
683 if(stmp.startsWith("maintainer")) {
684 fromaddr = stmp.substring(10); //length of MailServer
685 fromaddr = fromaddr.trim();
686 break;
687 }
688 }
689 maincfg.close();
690 if(!fromaddr.equals("NULL") && !fromaddr.equals("null")) {
691 collection.schedule_options.setValue("fromaddr", false, fromaddr);
692 }
693
694 //try to obtain an smtp server address from main.cfg. If that fails,
695 //try mail.server if an email address exists. If that fails,
696 //maybe a message to set attribute in main.cfg?
697 //i'm pretty sure there exists functionality to do this, but
698 //i'll finish this faster if I just wrote it
699
700
701 maincfg = new BufferedReader(new FileReader(mcfg));
702 String smtptmp = "NULL";
703 while((stmp = maincfg.readLine()) != null) {
704 if(stmp.startsWith("MailServer")) {
705 smtptmp = stmp.substring(10); //length of MailServer
706 smtptmp = smtptmp.trim();
707 break;
708 }
709 }
710 maincfg.close();
711
712 //try if lookup fails
713 if(smtptmp.equals("NULL") || smtptmp.equals("null")) {
714 String email2=fromaddr;
715 if(!email2.equals("NULL") && !email2.equals("null")) {
716 int loc = email2.indexOf('@');
717 email2 = email2.substring(loc+1);
718 smtptmp = "mail."+email2;
719 }
720 }
721 if(!smtptmp.equals("NULL") && !smtptmp.equals("null")) {
722 collection.schedule_options.setValue("smtp", false, smtptmp);
723 }
724
725 }
726
727
728 private void createLockFile(File lock_file)
729 {
730 try {
731 Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
732 String user_name = System.getProperty("user.name");
733 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
734 person_element.appendChild(default_lockfile.createTextNode(user_name));
735 person_element = null;
736 user_name = null;
737 String machine_name = Utility.getMachineName();
738 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
739 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
740 machine_element = null;
741 machine_name = null;
742 String date_time = Utility.getDateString();
743 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
744 date_element.appendChild(default_lockfile.createTextNode(date_time));
745 date_element = null;
746 date_time = null;
747 XMLTools.writeXMLFile(lock_file, default_lockfile);
748 }
749 catch (Exception exception) {
750 DebugStream.printStackTrace(exception);
751 }
752 }
753
754
755 public boolean deleteCollection(String collection_name)
756 {
757 // First we must release the collection from the local library, if it's running
758 if (LocalLibraryServer.isRunning() == true) {
759 LocalLibraryServer.releaseCollection(collection_name);
760 }
761
762 // Delete the collection on the server if we're using a remote Greenstone
763 if (Gatherer.isGsdlRemote) {
764 Gatherer.remoteGreenstoneServer.deleteCollection(collection_name);
765 }
766
767 // if Greenstone3, need to deactivate the collection on the server
768 if (Gatherer.GS3) {
769 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection_name);
770 }
771
772 // Now delete the collection directory
773 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
774 }
775
776
777 public void fireFileAddedToCollection(File file)
778 {
779 // Send the event off to all the CollectionContentsChangedListeners
780 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
781 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
782 }
783 }
784
785
786 /** Retrieve the current collection.
787 * @return The <strong>Collection</strong> itself.
788 */
789 public Collection getCollection() {
790 return collection;
791 }
792
793
794 /** Returns the absolute filename of the specified collection's directory.
795 */
796 static public String getCollectionDirectoryPath(String collection_name)
797 {
798 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
799 }
800
801
802 /** Returns the absolute filename of the loaded collection's archives directory.
803 */
804 static public String getLoadedCollectionArchivesDirectoryPath()
805 {
806 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
807 }
808
809 /** Returns the absolute filename of the loaded collection's export directory.
810 */
811 static public String getLoadedCollectionExportDirectoryPath()
812 {
813 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
814 }
815
816
817
818 /** Returns the absolute filename of the loaded collection's building directory.
819 */
820 static public String getLoadedCollectionBuildingDirectoryPath()
821 {
822 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
823 }
824
825
826 /** Returns the absolute filename of the loaded collection's collect.cfg file.
827 */
828 static public String getLoadedCollectionCfgFilePath()
829 {
830 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
831 return getLoadedCollectionEtcDirectoryPath() + path;
832 }
833
834
835 /** Returns the absolute filename of the loaded collection's directory.
836 */
837 static public String getLoadedCollectionDirectoryPath()
838 {
839 return collection.getCollectionDirectory().getPath() + File.separator;
840 }
841
842
843 /** Returns the absolute filename of the loaded collection's etc directory.
844 */
845 static public String getLoadedCollectionEtcDirectoryPath()
846 {
847 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
848 }
849
850
851 /** Returns the absolute filename of the loaded collection's .col file.
852 */
853 static public String getLoadedCollectionColFilePath()
854 {
855 return getLoadedCollectionDirectoryPath() + collection.getName() + ".col";
856 }
857
858
859 /** Returns the absolute filename of the loaded collection's images directory.
860 */
861 static public String getLoadedCollectionImagesDirectoryPath()
862 {
863 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
864 }
865
866
867 /** Returns the absolute filename of the loaded collection's import directory.
868 */
869 static public String getLoadedCollectionImportDirectoryPath()
870 {
871 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
872 }
873
874
875 /** Returns the absolute filename of the loaded collection's index directory.
876 */
877 static public String getLoadedCollectionIndexDirectoryPath()
878 {
879 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
880 }
881
882
883 /** Returns the absolute filename of the loaded collection's log directory.
884 */
885 static public String getLoadedCollectionLogDirectoryPath()
886 {
887 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
888 }
889
890
891 /** Returns the absolute filename of the loaded collection's macros directory.
892 */
893 static public String getLoadedCollectionMacrosDirectoryPath()
894 {
895 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
896 }
897
898
899 /** Returns the absolute filename of the loaded collection's metadata directory.
900 */
901 static public String getLoadedCollectionMetadataDirectoryPath()
902 {
903 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
904 }
905
906
907 /** Returns the name of the loaded collection.
908 * Returns the "collectionGroupName/collectionName" or just the collectionName
909 * depending on whether the collection is part of a collection group or not.
910 */
911 static public String getLoadedCollectionName()
912 {
913 if (collection != null) {
914 return collection.getName();
915 }
916
917 return null;
918 }
919
920 /** @return the subname of any collection (stripped of any collection-group). */
921 static public String getLoadedCollectionSubName()
922 {
923 if (collection != null) {
924 return collection.getCollectionSubName();
925 }
926
927 return null;
928 }
929
930 /** Returns the "collectionGroupName/collectionName" or just the collectionName
931 * depending on whether the collection is part of a collection group or not.
932 * If url = true, then returns the sub-path as a URL (containing / only),
933 * and if url = false, then the sub-path is returned in filepath form
934 * (\ or /, depending on the OS).
935 */
936 static public String getLoadedGroupQualifiedCollectionName(boolean url)
937 {
938 if (collection != null) {
939 return collection.getGroupQualifiedName(url);
940 }
941
942 return null;
943 }
944
945 public CollectionTree getCollectionTree()
946 {
947 if (collection_tree == null) {
948 collection_tree = new CollectionTree(collection_tree_model, true);
949 }
950
951 return collection_tree;
952 }
953
954
955 /** Retrieve the tree model associated with the current collection. */
956 public CollectionTreeModel getCollectionTreeModel()
957 {
958 if (collection_tree_model == null && collection != null) {
959 // Use the import directory to generate a new CollectionTreeModel
960 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
961 // Ensure that the manager is a change listener for the tree.
962 if (fm_tree_model_listener == null) {
963 fm_tree_model_listener = new FMTreeModelListener();
964 }
965 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
966 }
967 return collection_tree_model;
968 }
969
970
971 /** This method when called, creates a new GShell in order to run the import.pl script.
972 * @see org.greenstone.gatherer.Configuration
973 * @see org.greenstone.gatherer.Gatherer
974 * @see org.greenstone.gatherer.gui.BuildOptions
975 * @see org.greenstone.gatherer.shell.GShell
976 * @see org.greenstone.gatherer.shell.GShellListener
977 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
978 * @see org.greenstone.gatherer.util.Utility
979 */
980 public void importCollection() {
981 importing = true;
982
983 if (!saved()) {
984 DebugStream.println("CollectionManager.importCollection().forcesave");
985 import_monitor.saving();
986 saveCollection();
987 }
988
989 DebugStream.println("CollectionManager.importCollection()");
990 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
991 //check that we can remove the old index before starting import
992 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
993 if (index_dir.exists()) {
994 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
995 if (!canDelete(index_dir)) {
996 // tell the user
997 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
998 // tell the gui manager
999 // a message for the building log
1000 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
1001 Gatherer.g_man.create_pane.message(event);
1002 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
1003 Gatherer.g_man.create_pane.processComplete(event);
1004 importing = false;
1005 return;
1006 }
1007 }
1008
1009 // Generate the import.pl command
1010 ArrayList command_parts_list = new ArrayList();
1011 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
1012 command_parts_list.add(Configuration.perl_path);
1013 command_parts_list.add("-S");
1014 }
1015
1016 if (Configuration.fedora_info.isActive()) {
1017 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-import.pl");
1018
1019 command_parts_list.add("-hostname");
1020 command_parts_list.add(Configuration.fedora_info.getHostname());
1021
1022 command_parts_list.add("-port");
1023 command_parts_list.add(Configuration.fedora_info.getPort());
1024
1025 command_parts_list.add("-username");
1026 command_parts_list.add(Configuration.fedora_info.getUsername());
1027
1028 command_parts_list.add("-password");
1029 command_parts_list.add(Configuration.fedora_info.getPassword());
1030
1031 command_parts_list.add("-protocol");
1032 command_parts_list.add(Configuration.fedora_info.getProtocol());
1033 }
1034 else {
1035 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
1036 }
1037
1038 command_parts_list.add("-gli");
1039 command_parts_list.add("-language");
1040 command_parts_list.add(Configuration.getLanguage());
1041 command_parts_list.add("-collectdir");
1042 command_parts_list.add(getCollectDirectory());
1043
1044 String[] import_options = collection.import_options.getValues();
1045 for (int i = 0; i < import_options.length; i++) {
1046 command_parts_list.add(import_options[i]);
1047 }
1048
1049 command_parts_list.add(collection.getName());
1050
1051 // Run the import.pl command
1052 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1053 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1054 shell.addGShellListener(Gatherer.g_man.create_pane);
1055 shell.addGShellListener(Gatherer.g_man.format_pane);
1056 shell.start();
1057 DebugStream.println("CollectionManager.importCollection().return");
1058
1059 importing = false;
1060 }
1061
1062
1063 public void importMetadataSet(MetadataSet external_metadata_set)
1064 {
1065 // Copy the .mds file into the collection's "metadata" folder...
1066 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1067
1068 // ...but not if it is the redundant "hidden.mds" file
1069 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1070 return;
1071 }
1072
1073 // ...and only if it doesn't already exist
1074 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1075 if (!metadata_set_file.exists()) {
1076 try {
1077 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1078
1079 // If we're using a remote Greenstone server, upload the metadata file
1080 if (Gatherer.isGsdlRemote) {
1081 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection.getName(), metadata_set_file);
1082 }
1083 }
1084 catch (Exception exception) {
1085 DebugStream.printStackTrace(exception);
1086 }
1087
1088 // Load it into the MetadataSetManager
1089 MetadataSetManager.loadMetadataSet(metadata_set_file);
1090 }
1091 }
1092
1093
1094 /** 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.
1095 * @return true if the gli is currently importing
1096 */
1097 public boolean isImporting() {
1098 return importing;
1099 }
1100
1101
1102 public void loadCollection(String collection_file_path)
1103 {
1104 // Display a modal progress popup to indicate that the collection is being loaded
1105 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1106 load_collection_progress_popup.display();
1107
1108 // Load the collection on a separate thread so the progress bar updates correctly
1109 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1110 }
1111
1112
1113 private class LoadCollectionTask
1114 extends Thread
1115 {
1116 private String collection_file_path = null;
1117 private ModalProgressPopup load_collection_progress_popup = null;
1118
1119 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1120 {
1121 this.collection_file_path = collection_file_path;
1122 this.load_collection_progress_popup = load_collection_progress_popup;
1123 }
1124
1125 public void run()
1126 {
1127 loadCollectionInternal(collection_file_path);
1128 load_collection_progress_popup.close();
1129 Gatherer.setMenuBarEnabled(true);
1130 }
1131 }
1132
1133
1134 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1135 * @param location The path to the collection as a <strong>String</strong>.
1136 * @see org.greenstone.gatherer.Configuration
1137 * @see org.greenstone.gatherer.Gatherer
1138 * @see org.greenstone.gatherer.collection.Collection
1139 * @see org.greenstone.gatherer.util.Utility
1140 */
1141 private void loadCollectionInternal(String location)
1142 {
1143 DebugStream.println("Loading collection " + location + "...");
1144
1145 if (Gatherer.isGsdlRemote) {
1146 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
1147 if (Gatherer.remoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1148 return;
1149 }
1150 }
1151
1152 // Check we have actually been given a .col file.
1153 if (!location.endsWith(".col")) {
1154 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1155 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1156 return;
1157 }
1158
1159 // Check that the collection configuration file is available
1160 File collection_file = new File(location);
1161
1162 // Ensure that the directory exists
1163 File collection_directory = collection_file.getParentFile();
1164
1165 if (collection_directory == null || !collection_directory.exists()) {
1166 // We can't open this
1167 System.err.println("CollectionManager.loadCollection: No collection directory.");
1168 return;
1169 }
1170
1171 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1172 File collection_config_file = new File(collection_directory, file_str);
1173 if (!collection_config_file.exists()) {
1174 System.err.println("CollectionManager.loadCollection: No config file.");
1175 collection_directory = null;
1176 collection_config_file = null;
1177 return;
1178 }
1179
1180 // Ensure that an import directory exists for this collection
1181 File collection_import_directory = new File(collection_directory, "import");
1182 if (!collection_import_directory.exists()) {
1183 collection_import_directory.mkdir();
1184 }
1185
1186 // Special case of a user trying to open an old greenstone collection.
1187 boolean non_gli_collection = false;
1188 File collection_metadata_directory = new File(collection_directory, "metadata");
1189 if (!collection_metadata_directory.exists()) {
1190 DebugStream.println("Loading non-gatherer collection...");
1191 // Show a warning message in case user wants to quit now
1192 non_gli_collection = true;
1193 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1194 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1195 legacy_dialog.dispose();
1196 collection_directory = null;
1197 collection_config_file = null;
1198 return;
1199 }
1200 legacy_dialog.dispose();
1201
1202 }
1203
1204 // Now determine if a lock already exists on this collection.
1205 String collection_name = collection_directory.getName();
1206 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1207 if (lock_file.exists()) {
1208 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1209 int choice = dialog.getChoice();
1210 dialog.dispose();
1211 dialog = null;
1212
1213 if (choice != LockFileDialog.YES_OPTION) {
1214 // user has cancelled
1215 lock_file = null;
1216 collection_directory = null;
1217 collection_config_file = null;
1218 return;
1219 }
1220
1221 lock_file.delete();
1222 }
1223
1224 try {
1225 // Create a lock file.
1226 createLockFile(lock_file);
1227 // This lock file may not have been created so check
1228 if(!lock_file.canWrite()) {
1229 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1230 System.err.println("Cannot write lock file!");
1231 String args[] = new String[2];
1232 args[0] = location;
1233 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1234 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1235 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1236 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1237 //}
1238 }
1239 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1240 args = null;
1241 return;
1242 }
1243
1244 if (canDoScheduling()) {
1245 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1246
1247 //First, see if "Schedule" exists in the XMl File...
1248 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1249 boolean flag = false;
1250 try {
1251 String stmp = new String();
1252
1253 while((stmp = bir.readLine()) != null) {
1254 stmp = stmp.trim();
1255 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1256 flag = true;
1257 break;
1258 }
1259 }
1260 bir.close();
1261
1262 } catch (IOException ioe) {
1263 DebugStream.printStackTrace(ioe);
1264 }
1265
1266 //modify if old .col (i.e. no Schedule exists in XML file)
1267 if(!flag) {
1268 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1269
1270
1271 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1272 bir = new BufferedReader(new FileReader(collection_file));
1273
1274 try {
1275 String stmp = new String();
1276 while((stmp = bir.readLine()) != null) {
1277 String stmp2 = stmp.trim();
1278 if(stmp2.startsWith("<!ELEMENT Argument")) {
1279 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1280 }
1281 else if(stmp2.equals("</BuildConfig>")) {
1282 bor.write(" <Schedule/>\n");
1283 }
1284
1285 bor.write(stmp + "\n");
1286
1287 }
1288 bir.close();
1289 bor.close();
1290 } catch (IOException ioe) {
1291 DebugStream.printStackTrace(ioe);
1292 }
1293
1294 //copy over tmp.col to replace
1295 try {
1296 collection_file.delete();
1297 new_collection_file.renameTo(collection_file);
1298 } catch (Exception e) {
1299 DebugStream.printStackTrace(e);
1300 }
1301 }
1302 }
1303
1304 // Open the collection file
1305 this.collection = new Collection(collection_file);
1306 if (collection.error) {
1307 collection = null;
1308 // Remove lock file
1309 if (lock_file.exists()) {
1310 lock_file.delete();
1311 }
1312 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1313 }
1314
1315 if (canDoScheduling()) {
1316 scheduling();
1317 }
1318
1319 MetadataSetManager.clearMetadataSets();
1320 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1321
1322 // Make sure we always have the extracted metadata set
1323 addRequiredMetadataSets();
1324
1325 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1326
1327 // If this is a non-GLI (legacy) collection, load the default metadata sets
1328 if (non_gli_collection) {
1329 addDefaultMetadataSets();
1330
1331 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1332 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1333 }
1334
1335 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1336 MetadataXMLFileManager.clearMetadataXMLFiles();
1337 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1338
1339
1340 // get rid of the previous scan through docxml files
1341 DocXMLFileManager.clearDocXMLFiles();
1342
1343 if (Configuration.fedora_info.isActive()) { // FLI case
1344 // Read through the docmets.xml files in the export directory
1345 File collection_export_directory = new File(getLoadedCollectionExportDirectoryPath());
1346 DocXMLFileManager.loadDocXMLFiles(collection_export_directory,"docmets.xml");
1347 }
1348 else {
1349 // Read through the doc.xml files in the archives directory
1350 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1351 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory,"doc.xml");
1352 }
1353
1354
1355 // Get a list of the collection specific classifiers and plugins
1356 Classifiers.loadClassifiersList(collection_name);
1357 Plugins.loadPluginsList(collection_name);
1358
1359 collection.cdm = new CollectionDesignManager(collection_config_file);
1360 if (non_gli_collection) {
1361 // Change the classifiers to use the namespaced element names
1362 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1363 }
1364
1365 // We're done. Let everyone know.
1366 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1367 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1368 }
1369 catch (Exception error) {
1370 // There is obviously no existing collection present.
1371 DebugStream.printStackTrace(error);
1372 error.printStackTrace();
1373 if(error.getMessage() != null) {
1374 String[] args = new String[2];
1375 args[0] = location;
1376 //args[1] = error.getMessage();
1377 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1378 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1379 }
1380 else {
1381 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1382 }
1383 }
1384
1385 lock_file = null;
1386 collection_directory = null;
1387 collection_config_file = null;
1388 }
1389
1390 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1391 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1392 * more situations. */
1393 public static boolean canDoScheduling() {
1394 // Would be nice to support more of these, rather than returning false
1395 if(Gatherer.isGsdlRemote) {
1396 return false;
1397 }
1398 if(Gatherer.GS3) {
1399 return false;
1400 }
1401 if (Configuration.fedora_info.isActive()) {
1402 return false;
1403 }
1404
1405 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1406 // it assumes GLI is inside a GS2 installation
1407 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1408 if(!mcfg.exists()) {
1409 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1410 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1411 return false;
1412 }
1413
1414 return true;
1415 }
1416
1417 private void makeCollection(String name, String email)
1418 {
1419 // Generate the mkcol.pl command
1420 ArrayList command_parts_list = new ArrayList();
1421 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1422 command_parts_list.add(Configuration.perl_path);
1423 command_parts_list.add("-S");
1424 }
1425 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1426 if(Gatherer.GS3) {
1427 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1428 }
1429
1430 command_parts_list.add("-collectdir");
1431 command_parts_list.add(getDefaultCollectDirectory());
1432
1433 command_parts_list.add("-win31compat");
1434 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1435
1436 if (email != null && !email.equals("")) {
1437 command_parts_list.add("-creator");
1438 command_parts_list.add(email);
1439 }
1440
1441 command_parts_list.add(name);
1442
1443 // Run the mkcol.pl command
1444 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1445 //for(int i = 0; i < command_parts.length; i++) {
1446 ///ystem.err.println("\""+command_parts[i]+"\"");
1447 //}
1448
1449 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1450 process.run(); // Don't bother threading this... yet
1451 }
1452
1453
1454 /** 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.
1455 * @param event A <strong>GShellEvent</strong> which contains a the message.
1456 */
1457 public synchronized void message(GShellEvent event) {
1458
1459 }
1460
1461
1462 public void metadataChanged(CollectionTreeNode[] file_nodes)
1463 {
1464 if (collection != null) {
1465 collection.setMetadataChanged(true);
1466 }
1467 }
1468
1469
1470 public void openCollectionFromLastTime() {
1471 // If there was an open collection last session, reopen it
1472 if (Gatherer.open_collection_file_path != null) {
1473 // Load the collection now
1474 loadCollection(Gatherer.open_collection_file_path);
1475 }
1476
1477 }
1478
1479
1480 /** This call is fired whenever a process within a GShell created by this class begins.
1481 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1482 * @see org.greenstone.gatherer.Gatherer
1483 * @see org.greenstone.gatherer.gui.GUIManager
1484 * @see org.greenstone.gatherer.shell.GShell
1485 */
1486 public synchronized void processBegun(GShellEvent event) {
1487 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1488 ///ystem.err.println("ProcessBegun " + event.getType());
1489 // If this is one of the types where we wish to lock user control
1490 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1491 }
1492 /** This call is fired whenever a process within a GShell created by this class ends.
1493 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1494 * @see org.greenstone.gatherer.Gatherer
1495 * @see org.greenstone.gatherer.gui.GUIManager
1496 * @see org.greenstone.gatherer.shell.GShell
1497 */
1498 public synchronized void processComplete(GShellEvent event) {
1499 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1500 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1501 ///ystem.err.println("Recieved process complete event - " + event);
1502 // If we were running an import, now run a build.
1503 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1504 // Finish import.
1505 collection.setImported(true);
1506 collection.setFilesChanged(false);
1507 collection.setMetadataChanged(false);
1508 buildCollection(false);
1509 }
1510 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1511
1512 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1513 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1514 collection_built_warning_dialog.display();
1515 collection_built_warning_dialog.dispose();
1516 collection_built_warning_dialog = null;
1517 }
1518 // If we were running a build, now is when we move files across.
1519 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1520
1521 if(installCollection()) {
1522 // If we have a local library running then ask it to add our newly create collection
1523 if (LocalLibraryServer.isRunning() == true) {
1524 LocalLibraryServer.addCollection(collection.getName());
1525 }
1526 else if (Gatherer.GS3) {
1527 //xiao comment out this: convertToGS3Collection();
1528 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1529 }
1530
1531 // Fire a collection changed first to update the preview etc buttons
1532 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1533
1534 // Now display a message dialog saying its all built
1535 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1536 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1537 collection_built_warning_dialog.display();
1538 collection_built_warning_dialog.dispose();
1539 collection_built_warning_dialog = null;
1540
1541 //Set nothing as needing rebuilding, as a build has just finished :-)
1542 CollectionDesignManager.resetRebuildTypeRequired();
1543 }
1544 else {
1545 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1546 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1547 DebugStream.println("Status is ok but !installCollection()");
1548 }
1549 }
1550 else if (event.getStatus() == GShell.CANCELLED) {
1551 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1552 Gatherer.g_man.repaint();
1553 }
1554 else if (event.getStatus() == GShell.ERROR) {
1555 if (event.getType() == GShell.NEW) {
1556 String name = event.getMessage();
1557 String collectDir = getCollectionDirectoryPath(name);
1558 String errMsg = "";
1559 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1560 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1561 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1562 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1563 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1564 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1565 //}
1566 }
1567 } else {
1568 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1569 }
1570 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1571 }
1572 else if(event.getType() == GShell.SCHEDULE) {
1573 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1574 }
1575 else {
1576 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1577 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1578 }
1579
1580 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.
1581 }
1582 }
1583
1584
1585 /** Determine if the manager is ready for actions apon its collection.
1586 * @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.
1587 */
1588 static public synchronized boolean ready() {
1589 if(collection != null) {
1590 return true;
1591 }
1592 else {
1593 return false;
1594 }
1595 }
1596
1597
1598 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1599 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1600 */
1601 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1602 build_monitor = monitor;
1603 }
1604 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1605 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1606 */
1607 public void registerImportMonitor(GShellProgressMonitor monitor) {
1608 import_monitor = monitor;
1609 }
1610
1611 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1612 schedule_monitor = monitor;
1613 }
1614
1615
1616 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1617 {
1618 collection_contents_changed_listeners.remove(listener);
1619 }
1620
1621
1622 public void removeMetadataSet(MetadataSet metadata_set)
1623 {
1624 DebugStream.println("Removing metadata set...");
1625
1626 // Delete the .mds file from the collection's "metadata" folder...
1627 File metadata_set_file = metadata_set.getMetadataSetFile();
1628
1629 // ...but not if it is the "ex.mds" file
1630 if (metadata_set_file.getName().equals("ex.mds")) {
1631 return;
1632 }
1633
1634 // ...and only if it exists
1635 if (metadata_set_file.exists()) {
1636 metadata_set_file.delete();
1637
1638 // Unload it from the MetadataSetManager
1639 MetadataSetManager.unloadMetadataSet(metadata_set);
1640
1641 // If we're using a remote Greenstone server, delete the metadata file on the server
1642 if (Gatherer.isGsdlRemote) {
1643 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getName(), metadata_set_file);
1644 }
1645 }
1646 }
1647
1648
1649 /** Used to check whether all open collections have a 'saved' state.
1650 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1651 * @see org.greenstone.gatherer.collection.Collection
1652 */
1653 public boolean saved() {
1654 boolean result = true;
1655 if(collection != null) {
1656 result = collection.getSaved();
1657 }
1658 return result;
1659 }
1660
1661
1662 /** Saves the currently loaded collection. */
1663 public void saveCollection()
1664 {
1665
1666 if (collection == null) return;
1667
1668 DebugStream.println("Saving collection " + collection.getName() + "...");
1669
1670 // Change cursor to hourglass
1671 Gatherer.g_man.wait(true);
1672
1673 // Create a backup of the collection file, just in case anything goes wrong
1674 File collection_file = new File(getLoadedCollectionColFilePath());
1675 if (collection_file.exists()) {
1676 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1677 if (!collection_file.renameTo(collection_file_backup)) {
1678 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1679 }
1680 collection_file_backup.deleteOnExit();
1681 }
1682
1683 // Write out the collection file
1684 collection.save();
1685
1686 // Write out the collection configuration file
1687 collection.cdm.save();
1688
1689 // Change cursor back to normal
1690 Gatherer.g_man.wait(false);
1691 }
1692
1693
1694 /** 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] */
1695 private void addDefaultMetadataSets()
1696 {
1697 // Add dublin core which is the default metadata set. The user
1698 // can change this later
1699 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1700 if (dc_file.exists()) {
1701 importMetadataSet(new MetadataSet(dc_file));
1702 }
1703 }
1704
1705
1706 private void addRequiredMetadataSets()
1707 {
1708 // Always import the extracted metadata set
1709 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1710 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1711 }
1712
1713 private String getDefaultCollectDirectory() {
1714 String collect_dir = Gatherer.getCollectDirectoryPath();
1715 // Remove erroneous file windows file separator as it causes problems when running import.pl
1716 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1717 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1718 }
1719 return collect_dir;
1720 }
1721
1722 // used as arg in the perl scripts
1723 private String getCollectDirectory() {
1724
1725 String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
1726 return collect_dir;
1727 }
1728
1729
1730 /** Install collection by moving its files from building to index after a successful build.
1731 * @see org.greenstone.gatherer.Gatherer
1732 * @see org.greenstone.gatherer.util.Utility
1733 */
1734 private boolean installCollection()
1735 {
1736 if (Configuration.fedora_info.isActive()) {
1737 DebugStream.println("Fedora build complete. No need to move files.");
1738 return true;
1739 }
1740
1741
1742 DebugStream.println("Build complete. Moving files.");
1743
1744 try {
1745 // Ensure that the local library has released this collection so we can delete the index directory
1746 if (LocalLibraryServer.isRunning() == true) {
1747 LocalLibraryServer.releaseCollection(collection.getName());
1748 }
1749 // deactivate it in tomcat so that windows will release the index files
1750 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1751 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1752 }
1753 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1754 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1755
1756 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1757 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1758
1759 // Get the build mode from the build options
1760 String build_mode = collection.build_options.getValue("mode");
1761
1762 // Special case for build mode "all": replace index dir with building dir
1763 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1764 // Remove the old index directory
1765 if (index_dir.exists()) {
1766 Utility.delete(index_dir);
1767
1768 // Wait for a couple of seconds, just for luck
1769 wait(2000);
1770
1771 // Check the delete worked
1772 if (index_dir.exists()) {
1773 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1774 }
1775 }
1776
1777 if (Gatherer.isGsdlRemote) {
1778 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
1779 collection.getName(), new File(getLoadedCollectionIndexDirectoryPath()));
1780 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getName(),
1781 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1782 }
1783
1784 // Move the building directory to become the new index directory
1785 if (building_dir.renameTo(index_dir) == false) {
1786 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1787 }
1788 }
1789
1790 // Otherwise copy everything in the building dir into the index dir
1791 else {
1792 moveContentsInto(building_dir, index_dir);
1793 }
1794 }
1795 catch (Exception exception) {
1796 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1797 return false;
1798 }
1799 return true;
1800 }
1801
1802
1803 /** Moves all the files in one directory into another, overwriting existing files */
1804 private void moveContentsInto(File source_directory, File target_directory)
1805 {
1806 File[] source_files = source_directory.listFiles();
1807 for (int i = 0; i < source_files.length; i++) {
1808 File source_file = source_files[i];
1809 File target_file = new File(target_directory, source_file.getName());
1810
1811 if (source_file.isDirectory()) {
1812 moveContentsInto(source_file, target_file);
1813 source_file.delete();
1814 }
1815 else {
1816 if (target_file.exists()) {
1817 target_file.delete();
1818 }
1819
1820 source_file.renameTo(target_file);
1821 }
1822 }
1823 }
1824
1825 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1826 //In this method, the files base_cfg and new_cfg are all xml files.
1827
1828 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1829 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1830 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1831 Element collection_config = new_cfg_doc.getDocumentElement();
1832
1833 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1834 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1835 int num_nodes = classifier_children.getLength();
1836
1837 if (num_nodes < 1) {
1838 return;
1839 }
1840
1841 // Read in the classifier command watching for hfile, metadata and sort arguments.
1842 String buttonname = null;
1843 String hfile = null;
1844 String metadata = null;
1845 String sort = null;
1846
1847 for (int i=0; i<num_nodes; i++) {
1848 Element classifier_element = (Element)classifier_children.item(i);
1849 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1850 for (int j=0; j<option_children.getLength(); j++) {
1851 Element option_element = (Element)option_children.item(j);
1852 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1853 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1854
1855 if (name_str == null || name_str.equals("")) {
1856 continue;
1857 }
1858 if (name_str != null && value_str == null ) {
1859 value_str = "";
1860 }
1861 if (name_str.equals("hfile")) {
1862 hfile = value_str;
1863 }
1864 else if (name_str.equals("metadata") && value_str != null) {
1865 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1866 if (replacement != null && !replacement.equals("")) {
1867 metadata = replacement;
1868 }
1869 }
1870 else if (name_str.equals("sort") && value_str != null) {
1871 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1872 if (replacement != null && !replacement.equals("")) {
1873 sort = replacement;
1874 }
1875 }
1876 else if(name_str.equals("buttonname") && value_str != null) {
1877 buttonname = value_str;
1878 }
1879 }
1880 }
1881 for (int i=0; i<num_nodes; i++) {
1882 Element classifier_element = (Element)classifier_children.item(i);
1883 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1884 for (int j=0; j<option_children.getLength(); j++) {
1885 Element option_element = (Element)option_children.item(j);
1886 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1887
1888 if (name_str.equals("metadata") && metadata != null) {
1889 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1890 }
1891 else if (name_str.equals("hfile") && hfile != null) {
1892 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1893 }
1894 else if (name_str.equals("sort") && sort != null) {
1895 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1896 }
1897 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1898 // No buttonname has been specified. Lets create one using the metadata as its value
1899 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1900 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1901 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1902 classifier_element.appendChild(option);
1903 }
1904 }
1905 }
1906 }
1907
1908 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1909 {
1910 boolean first_name = true;
1911 boolean first_extra = true;
1912
1913 // 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.
1914 try {
1915 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1916 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1917 String command = null;
1918 while((command = in.readLine()) != null) {
1919 if (command.length()==0) {
1920 // output a new line
1921 out.newLine();
1922 continue;
1923 }
1924 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1925 while(command.trim().endsWith("\\")) {
1926 command = command.substring(0, command.lastIndexOf("\\"));
1927 String next_line = in.readLine();
1928 if(next_line != null) {
1929 command = command + next_line;
1930 }
1931 }
1932 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1933 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1934 String command_type_str = tokenizer.nextToken().toLowerCase();
1935
1936 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1937 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1938 StringBuffer new_command = new StringBuffer(command_type_str);
1939 String meta_name = tokenizer.nextToken();
1940 new_command.append(' ');
1941 new_command.append(meta_name);
1942 while (tokenizer.hasMoreTokens()) {
1943 new_command.append(' ');
1944 new_command.append(tokenizer.nextToken());
1945 }
1946 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)) {
1947 // dont save
1948 } else {
1949 write(out, new_command.toString());
1950 }
1951 new_command = null;
1952 continue;
1953 } // if collectionmeta
1954
1955 if (command_type_str.equals("classify")) {
1956 StringBuffer text = new StringBuffer(command_type_str);
1957 // Read in the classifier command watching for hfile, metadata and sort arguments.
1958 String buttonname = null;
1959 String hfile = null;
1960 String new_metadata = null;
1961 String old_metadata = null;
1962
1963 while(tokenizer.hasMoreTokens()) {
1964 String token = tokenizer.nextToken();
1965 if (token.equals("-hfile")) {
1966 if(tokenizer.hasMoreTokens()) {
1967 text.append(" ");
1968 text.append(token);
1969 token = tokenizer.nextToken();
1970 hfile = token;
1971 }
1972 }
1973 else if (token.equals("-metadata")) {
1974 if(tokenizer.hasMoreTokens()) {
1975 text.append(" ");
1976 text.append(token);
1977 String temp_metadata = tokenizer.nextToken();
1978 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1979 if (replacement != null && !replacement.equals("")) {
1980 token = replacement;
1981 old_metadata = temp_metadata;
1982 new_metadata = replacement;
1983 }
1984 else {
1985 token = temp_metadata;
1986 }
1987 temp_metadata = null;
1988 replacement = null;
1989 }
1990 }
1991 else if (token.equals("-sort")) {
1992 if(tokenizer.hasMoreTokens()) {
1993 text.append(" ");
1994 text.append(token);
1995 String temp_metadata = tokenizer.nextToken();
1996 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1997 if (replacement != null && !replacement.equals("")) {
1998 token = replacement;
1999 }
2000 else {
2001 token = temp_metadata;
2002 }
2003 temp_metadata = null;
2004 replacement = null;
2005 }
2006 }
2007 else if(token.equals("-buttonname")) {
2008 buttonname = token;
2009 }
2010 text.append(' ');
2011 text.append(token);
2012 token = null;
2013 }
2014
2015 // 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)!
2016 if(old_metadata != null && new_metadata != null && buttonname == null) {
2017 text.append(' ');
2018 text.append("-buttonname");
2019 text.append(' ');
2020 text.append(old_metadata);
2021 }
2022 command = text.toString();
2023 // Replace the hfile if we found it
2024 if(hfile != null && new_metadata != null) {
2025 command = command.replaceAll(hfile, new_metadata + ".txt");
2026 }
2027
2028 buttonname = null;
2029 hfile = null;
2030 new_metadata = null;
2031 old_metadata = null;
2032 write(out, command);
2033 } else {
2034 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2035 StringBuffer new_command = new StringBuffer(command_type_str);
2036 while (tokenizer.hasMoreTokens()) {
2037 new_command.append(' ');
2038 new_command.append(tokenizer.nextToken());
2039 }
2040
2041 command = new_command.toString();
2042
2043 // 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.
2044 // we really want to build up the whole command here
2045 boolean format_command = command_type_str.equals("format");
2046 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2047 if (metadata_mapping != null) {
2048 Iterator keys = metadata_mapping.keySet().iterator();
2049 while (keys.hasNext()) {
2050 String target = (String) keys.next();
2051 String replacement = (String) metadata_mapping.get(target);
2052 if (replacement != null && !replacement.equals("")) {
2053 if (format_command) {
2054 target = "\\[" + target + "\\]";
2055 replacement = "{Or}{[" + replacement + "]," + target + "}";
2056 }
2057 command = command.replaceAll(target, replacement);
2058 }
2059 }
2060 }
2061
2062 write(out, command);
2063 }
2064 tokenizer = null;
2065 }
2066 in.close();
2067 in = null;
2068 out.flush();
2069 out.close();
2070 out = null;
2071 }
2072 catch(Exception error) {
2073 DebugStream.printStackTrace(error);
2074 }
2075 // All done, I hope.
2076 }
2077
2078 private void write(BufferedWriter out, String message)
2079 throws Exception {
2080 out.write(message, 0, message.length());
2081 out.newLine();
2082 }
2083
2084
2085 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2086 private class FMTreeModelListener
2087 implements TreeModelListener {
2088 /** 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.
2089 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2090 */
2091 public void treeNodesChanged(TreeModelEvent event) {
2092 if(collection != null) {
2093 collection.setSaved(false);
2094 collection.setFilesChanged(true);
2095 }
2096 }
2097 /** 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.
2098 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2099 */
2100 public void treeNodesInserted(TreeModelEvent event) {
2101 if(collection != null) {
2102 collection.setSaved(false);
2103 collection.setFilesChanged(true);
2104 }
2105 }
2106 /** 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.
2107 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2108 */
2109 public void treeNodesRemoved(TreeModelEvent event) {
2110 if(collection != null) {
2111 collection.setSaved(false);
2112 collection.setFilesChanged(true);
2113
2114 }
2115 }
2116 /** 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.
2117 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2118 */
2119 public void treeStructureChanged(TreeModelEvent event) {
2120 if(collection != null) {
2121 collection.setSaved(false);
2122 }
2123 }
2124 }
2125}
Note: See TracBrowser for help on using the repository browser.