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

Last change on this file since 24636 was 24636, checked in by ak19, 13 years ago

FileQueue.copyDirectoryContents is now overloaded to take an overwrite parameter. This is necessary for when CollectionManager.copyExtraBaseCollStuff() has to copy the macros folder across. At this point a new collection contains a macros folder already and it used to be unable to overwite it before. Now, with the new overwrite flag to FileQueue.copyDirContents(), setting overwrite to true when basing a new collection on an existing one allows all the necessary folders to be copied across.

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