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

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

The PreviewButton's response had not been updated to load the page of a collection if this was nested in a collectiongroup. Adjusted relevant classes to make the PreviewButton work in the collection group case as well.

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