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

Last change on this file since 25773 was 25773, checked in by ak19, 12 years ago

Fixed the bug where basing a GS3 collection on another one that had collection descriptions and collection names in multiple languages would copy all those additional names and descriptions across to the new collection.

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