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

Last change on this file since 9017 was 9017, checked in by mdewsnip, 19 years ago

Moved some GUI stuff out of CollectionManager and into GUIManager.

  • Property svn:keywords set to Author Date Id Revision
File size: 63.7 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.LocalLibraryServer;
50import org.greenstone.gatherer.ServletConfiguration;
51import org.greenstone.gatherer.cdm.CollectionDesignManager;
52import org.greenstone.gatherer.cdm.CollectionMeta;
53import org.greenstone.gatherer.cdm.CollectionMetaManager;
54import org.greenstone.gatherer.cdm.CommandTokenizer;
55import org.greenstone.gatherer.gui.LockFileDialog;
56import org.greenstone.gatherer.gui.NewCollectionMetadataPrompt;
57import org.greenstone.gatherer.gui.ExternalCollectionPrompt;
58import org.greenstone.gatherer.gui.WarningDialog;
59import org.greenstone.gatherer.metadata.DocXMLFileManager;
60import org.greenstone.gatherer.metadata.MetadataSet;
61import org.greenstone.gatherer.metadata.MetadataSetManager;
62import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
63import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
64import org.greenstone.gatherer.shell.GShell;
65import org.greenstone.gatherer.shell.GShellEvent;
66import org.greenstone.gatherer.shell.GShellListener;
67import org.greenstone.gatherer.shell.GShellProgressMonitor;
68import org.greenstone.gatherer.util.ArrayTools;
69import org.greenstone.gatherer.util.Codec;
70import org.greenstone.gatherer.util.StaticStrings;
71import org.greenstone.gatherer.util.Utility;
72import org.greenstone.gatherer.util.XMLTools;
73import org.w3c.dom.*;
74
75/** 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 resposible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
76 * @author John Thompson
77 * @version 2.3
78 */
79public class CollectionManager
80 implements GShellListener {
81
82 /** Are we currently in the process of building? */
83 private boolean building = false;
84 /** Are we currently in the process of importing? */
85 private boolean importing = false;
86 /** The objects listening for CollectionContentsChanged events. */
87 private ArrayList collection_contents_changed_listeners = new ArrayList();
88 /** The collection this manager is managing! */
89 static private Collection collection = null;
90 /** The collection_model. */
91 private CollectionTreeModel collection_model = null;
92 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
93 private FMTreeModelListener fm_tree_model_listener = null;
94 /** The monitor resposible for parsing the build process. */
95 private GShellProgressMonitor build_monitor = null;
96 /** The monitor resposible for parsing the import process. */
97 private GShellProgressMonitor import_monitor = null;
98
99 /** The name of the standard lock file. */
100 static final public String LOCK_FILE = "gli.lck";
101
102 /** Used to indicate the source of the message is the file collection methods. */
103 static final public int COLLECT = 3;
104 /** Used to indicate the source of the message is the building methods. */
105 static final public int BUILDING = 5;
106
107 /** Constructor. */
108 public CollectionManager() {
109 // Initialisation.
110 this.building = false;
111 this.importing = false;
112 this.collection = null;
113 }
114
115
116 public void addCollectionContentsChangedListener(CollectionContentsChangedListener listener)
117 {
118 collection_contents_changed_listeners.add(listener);
119 }
120
121
122 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
123 * @see org.greenstone.gatherer.Configuration
124 * @see org.greenstone.gatherer.Gatherer
125 * @see org.greenstone.gatherer.collection.Collection
126 * @see org.greenstone.gatherer.gui.BuildOptions
127 * @see org.greenstone.gatherer.shell.GShell
128 * @see org.greenstone.gatherer.shell.GShellListener
129 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
130 * @see org.greenstone.gatherer.util.Utility
131 */
132 private void buildCollection() {
133 DebugStream.println("CollectionManager.buildCollection()");
134 building = true;
135 String lang = Configuration.getLanguage();
136 String collect_dir = getCollectDirectory();
137
138 String args[];
139 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
140 args = new String[8];
141 args[0] = Configuration.perl_path;
142 args[1] = "-S";
143 args[2] = Configuration.getScriptPath() + "buildcol.pl";
144 args[3] = "-gli";
145 args[4] = "-language";
146 args[5] = lang;
147 args[6] = "-collectdir";
148 args[7] = collect_dir;
149 }
150 else {
151 args = new String[6];
152 args[0] = Configuration.getScriptPath() + "buildcol.pl";
153 args[1] = "-gli";
154 args[2] = "-language";
155 args[3] = lang;
156 args[4] = "-collectdir";
157 args[5] = collect_dir;
158 }
159 args = ArrayTools.add(args, collection.build_options.getBuildValues());
160 args = ArrayTools.add(args, collection.getName());
161 GShell shell = new GShell(args, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
162 shell.addGShellListener(Gatherer.g_man.create_pane);
163 shell.start();
164 DebugStream.println("CollectionManager.buildCollection().return");
165 }
166
167 /** Used to determine whether the currently active collection has been built.
168 * @return A boolean indicating the built status of the collection.
169 */
170 public boolean built() {
171 if(collection != null) {
172 // Determine if the collection has been built by looking for the build.cfg file
173 File build_cfg_file = new File(getCollectionIndex() + Utility.BUILD_CFG_FILENAME);
174 return build_cfg_file.exists();
175 }
176 return false;
177 }
178
179 /** 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 */
180 public boolean canDelete(File file) {
181 if (!file.isDirectory()) {
182 return file.canWrite();
183 }
184 File [] file_list = file.listFiles();
185 for (int i=0; i<file_list.length; i++) {
186 if (!canDelete(file_list[i])) {
187 return false;
188 }
189 }
190 return true;
191 }
192 /** Called to close the current collection and remove its lock file.
193 * @see org.greenstone.gatherer.Gatherer
194 * @see org.greenstone.gatherer.collection.Collection
195 * @see org.greenstone.gatherer.util.Utility
196 */
197 public void closeCollection() {
198 DebugStream.println("Close collection: " + collection.getName());
199
200 // Remove the lock on this file, then remove the collection.
201 String collection_dir;
202 if (Gatherer.GS3) {
203 collection_dir = Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName());
204 } else {
205 collection_dir = Utility.getCollectionDir(Configuration.gsdl_path, collection.getName());
206
207 }
208 File lock_file = new File(collection_dir + LOCK_FILE);
209 lock_file.delete();
210 if(lock_file.exists()) {
211 System.err.println("Lockfile was not successfully deleted.");
212 }
213
214 MetadataSetManager.clearMetadataSets();
215 MetadataXMLFileManager.clearMetadataXMLFiles();
216 DocXMLFileManager.clearDocXMLFiles();
217 ProfileXMLFileManager.clearProfileXMLFile();
218
219 collection = null;
220 collection_model = null;
221 // workspace_model = null;
222 Configuration.setCollectionConfiguration(null);
223 Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
224 if (Gatherer.g_man != null) {
225 Gatherer.g_man.updateUI(); // !!! Necessary?
226 }
227 }
228
229 /** Method that is called whenever something has changed in the configuration of this collection. */
230 public void configurationChanged() {
231 if(collection != null) {
232 collection.setSaved(false);
233 }
234 }
235
236 public void convertToGS3Collection() {
237 // Run the mkcol command.
238 String command[];
239 String collect_dir = getCollectDirectory();
240
241 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
242 command = new String[6];
243 command[0] = Configuration.perl_path;
244 command[1] = "-S";
245 command[2] = Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl";
246 command[3] = "-collectdir";
247 command[4] = collect_dir;
248 command[5] = collection.getName();
249 } else {
250 command = new String[4];
251 command[0] = Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl";
252 command[1] = "-collectdir";
253 command[2] = collect_dir;
254 command[3] = collection.getName();
255 }
256 DebugStream.println("running command "+command);
257 GShell process = new GShell(command, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
258 process.addGShellListener(this);
259 process.run(); // Don't bother threading this... yet
260
261 }
262
263 /** When basing a new collection on an existing one, we need to copy
264 * over some extra directories: images and macros
265 */
266 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
267 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
268 return false;
269 }
270 DebugStream.println("Copying images and macros dirs from the base collection");
271 try {
272 // do the images dir
273 File base_coll_images = new File(base_coll_dir, Utility.IMAGES_DIR);
274 if (base_coll_images.isDirectory()) {
275 // copy all the images over
276 File new_coll_images = new File(new_coll_dir, Utility.IMAGES_DIR);
277 new_coll_images.mkdirs();
278
279 // copy the contents over
280 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_images, new_coll_images, null);
281 }
282 }
283 catch (Exception e) {
284 DebugStream.println("Couldn't copy over the images dir from the base collection: "+e.toString());
285 }
286 try {
287 // do the macros dir
288 File base_coll_macros = new File(base_coll_dir, Utility.MACROS_DIR);
289 if (base_coll_macros.isDirectory()) {
290 // copy all the macros over
291 File new_coll_macros = new File(new_coll_dir, Utility.MACROS_DIR);
292 new_coll_macros.mkdirs();
293
294 // copy the contents over
295 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_macros, new_coll_macros, null);
296 }
297 }
298 catch (Exception e) {
299 DebugStream.println("Couldn't copy over the macros dir from the base collection: "+e.toString());
300 }
301 return true;
302 }
303
304 /** 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 colection 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.
305 * @param description a description of the collection as a String
306 * @param email the email address of the author/maintainer as a String
307 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
308 * @param title the longer title of the collection as a String
309 * @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
310 * @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
311 */
312 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
313 {
314 try {
315 // first make sure that the collect directory exists
316 File collect_dir = new File(getCollectDirectory());
317 if (!collect_dir.exists()) {
318 collect_dir.mkdirs();
319 }
320 // Create a progress monitor.
321 ProgressMonitor progress = new ProgressMonitor(Gatherer.g_man, Dictionary.get("CollectionManager.Creating_New"), "mkcol.pl", 0, 7);
322 // Create the new collection.
323 makeCollection(description, email, name, title);
324
325 // *******************
326 //check that this creation has worked - simply by checking for the existence of the collect.cfg file
327 String collection_dir;
328 if (Gatherer.GS3) {
329 collection_dir = Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, name);
330 } else {
331 collection_dir = Utility.getCollectionDir(Configuration.gsdl_path, name);
332 }
333 File config_file = new File(Utility.getConfigFile(collection_dir));
334 if (!config_file.exists()) {
335 // no point continuing
336 DebugStream.println("The collection could not be created");
337 progress.close();
338 return;
339 }
340 progress.setProgress(1);
341
342 // ACTIVE_DIR/log/
343 File log_dir_temp = new File(Utility.getLogDir(collection_dir)+"temp.dat");
344 File log_dir = log_dir_temp.getParentFile();
345 log_dir.mkdirs();
346 if(progress != null) {
347 progress.setNote(Dictionary.get("CollectionManager.Log_Created"));
348 }
349
350 // Make sure an import folder exists
351 File import_directory = new File(Utility.getImportDir(collection_dir));
352 if (!import_directory.exists()) {
353 import_directory.mkdirs();
354 }
355
356 progress.setProgress(2);
357
358 // Now create the collection object around the directory.
359 collection = new Collection(new File(collection_dir, name + ".col"));
360
361 MetadataSetManager.clearMetadataSets();
362 MetadataXMLFileManager.clearMetadataXMLFiles();
363 DocXMLFileManager.clearDocXMLFiles();
364
365 // Import default metadata sets, if any
366 for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
367 importMetadataSet((MetadataSet) metadata_sets.get(i));
368 }
369
370 ProfileXMLFileManager.loadProfileXMLFile(new File(collection_dir, Utility.META_DIR));
371
372 // Before we create the CollectionDesignManager we have to check if we are basing it upon some other collection.
373 if (base_collection_directory != null) {
374 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
375 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
376 // copy over other needed directories
377 copyExtraBaseCollStuff(new File(collection_dir), base_collection_directory);
378 // Try to import any existing metadata sets for this collection
379 // Look in base_collection_directory/metadata and import any metadata sets found.
380 File base_metadata_directory = new File(base_collection_directory, Utility.META_DIR);
381 ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
382 if (base_metadata_sets != null) {
383 for (int i = 0; i < base_metadata_sets.size(); i++) {
384 importMetadataSet((MetadataSet) base_metadata_sets.get(i));
385 }
386 }
387 else {
388 DebugStream.println("This base collection has no metadata directory.");
389 }
390
391 // If no sets were imported...
392 if (MetadataSetManager.getMetadataSets().size() == 0) {
393 // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
394 DebugStream.println("This collection has no metadata sets. Present the user with the metadata set selection prompt.");
395 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
396 // If cancelled then they really do mean to start a collection with no metadata sets.
397 if (!ncm_prompt.isCancelled()) {
398 ArrayList initial_sets = ncm_prompt.getSets();
399 for (int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
400 importMetadataSet((MetadataSet) initial_sets.get(i));
401 }
402 }
403 ncm_prompt.dispose();
404 ncm_prompt = null;
405 }
406
407 // Now we update our collect.cfg
408 DebugStream.println("Copy and update collect.cfg from base collection.");
409 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE), new File(collection_dir, Utility.CONFIG_FILE), description, email, title);
410 }
411
412 // Always import the extracted metadata set if we didn't already
413 if (MetadataSetManager.getMetadataSet(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE) == null) {
414 File extracted_metadata_set_file = new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
415 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
416 }
417
418 collection.cdm = new CollectionDesignManager(new File(getCollectionConfig()));
419
420 // 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
421 if (base_collection_directory != null) {
422 // Update the creator and maintainer
423 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
424 creator_collectionmeta.setValue(email);
425 creator_collectionmeta = null;
426 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
427 maintainer_collectionmeta.setValue(email);
428 maintainer_collectionmeta = null;
429
430 // Update the collection title
431 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
432 collection_name_collectionmeta.setValue(title);
433 collection_name_collectionmeta = null;
434
435 // And now the description
436 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
437 collection_extra_collectionmeta.setValue(description);
438 collection_extra_collectionmeta = null;
439
440 // All collections based on others are automatically public
441 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
442 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
443 public_collectionmeta = null;
444
445 // Finally reset the icons
446 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
447 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
448 icon_collection_collectionmeta = null;
449 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
450 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
451 icon_collection_small_collectionmeta = null;
452 }
453
454 progress.setProgress(3);
455
456 // Create a lock file.
457 File lock_file = new File(collection_dir, LOCK_FILE);
458 FileOutputStream out = new FileOutputStream(lock_file);
459 out.write(LOCK_FILE.getBytes());
460 out.close();
461 out = null;
462
463 progress.setProgress(7);
464 progress.setNote(Dictionary.get("CollectionManager.Session_Ready", name));
465 progress.close();
466 }
467 catch (Exception error) {
468 DebugStream.printStackTrace(error);
469 }
470 }
471
472
473 public void createLockFile(File destination) {
474 try {
475 Document default_lockfile = Utility.parse("xml/" + LOCK_FILE, true);
476 String user_name = System.getProperty("user.name");
477 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
478 person_element.appendChild(default_lockfile.createTextNode(user_name));
479 person_element = null;
480 user_name = null;
481 String machine_name = Utility.getMachineName();
482 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
483 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
484 machine_element = null;
485 machine_name = null;
486 String date_time = Utility.getDateString();
487 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
488 date_element.appendChild(default_lockfile.createTextNode(date_time));
489 date_element = null;
490 date_time = null;
491 XMLTools.export(default_lockfile, destination);
492 }
493 catch (Exception error) {
494 DebugStream.printStackTrace(error);
495 }
496 }
497
498
499 public boolean deleteCollection(String collection_name)
500 {
501 File collection_directory = null;
502 if (Gatherer.GS3) {
503 collection_directory = new File(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection_name));
504 }
505 else {
506 collection_directory = new File(Utility.getCollectionDir(Configuration.gsdl_path, collection_name));
507 }
508
509 return Utility.delete(collection_directory);
510 }
511
512
513 public void fireFileAddedToCollection(File file)
514 {
515 // Send the event off to all the CollectionContentsChangedListeners
516 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
517 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
518 }
519 }
520
521
522 /** Retrieve the current collection.
523 * @return The <strong>Collection</strong> itself.
524 */
525 public Collection getCollection() {
526 return collection;
527 }
528
529
530 /** Constructs the absolute filename of the collection archive directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archive/"
531 * @return A <strong>String</strong> containing the filename.
532 * @see org.greenstone.gatherer.Configuration
533 * @see org.greenstone.gatherer.Gatherer
534 * @see org.greenstone.gatherer.collection.Collection
535 * @see org.greenstone.gatherer.util.Utility
536 */
537 public String getCollectionArchives() {
538 if (Gatherer.GS3) {
539 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + "archives" + File.separator;
540 } else {
541 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + "archives" + File.separator;
542 }
543 }
544 /** Constructs the absolute filename of the collection building directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/building/"
545 * @return A <strong>String</strong> containing the filename.
546 * @see org.greenstone.gatherer.Configuration
547 * @see org.greenstone.gatherer.Gatherer
548 * @see org.greenstone.gatherer.collection.Collection
549 * @see org.greenstone.gatherer.util.Utility
550 */
551 public String getCollectionBuild() {
552 if (Gatherer.GS3) {
553 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + "building" + File.separator;
554 } else {
555 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + "building" + File.separator;
556 }
557 }
558 /** Constructs the absolute filename of the collection config file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/collect.cfg"
559 * @return A <strong>String</strong> containing the filename.
560 * @see org.greenstone.gatherer.Configuration
561 * @see org.greenstone.gatherer.Gatherer
562 * @see org.greenstone.gatherer.collection.Collection
563 * @see org.greenstone.gatherer.util.Utility
564 */
565 public String getCollectionConfig() {
566 if (Gatherer.GS3) {
567 return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
568 } else {
569 return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
570 }
571 }
572
573 /** Constructs the absolute filename of the collection directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;"
574 * @return A <strong>String</strong> containing the directory name.
575 * @see org.greenstone.gatherer.Configuration
576 * @see org.greenstone.gatherer.Gatherer
577 * @see org.greenstone.gatherer.collection.Collection
578 * @see org.greenstone.gatherer.util.Utility
579 */
580 public String getCollectionDirectory() {
581 if (Gatherer.GS3) {
582 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName());
583 } else {
584 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName());
585 }
586 }
587
588 /** Constructs the absolute filename of the collection etc directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/"
589 * @return A <strong>String</strong> containing the filename.
590 * @see org.greenstone.gatherer.Configuration
591 * @see org.greenstone.gatherer.Gatherer
592 * @see org.greenstone.gatherer.collection.Collection
593 * @see org.greenstone.gatherer.util.Utility
594 */
595 public String getCollectionEtc() {
596 if (Gatherer.GS3) {
597 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + "etc" + File.separator;
598 } else {
599 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + "etc" + File.separator;
600 }
601 }
602 /** Constructs the absolute filename of the collection file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/&lt;col_name&gt;.col"
603 * @return A <strong>String</strong> containing the filename.
604 * @see org.greenstone.gatherer.Configuration
605 * @see org.greenstone.gatherer.Gatherer
606 * @see org.greenstone.gatherer.collection.Collection
607 * @see org.greenstone.gatherer.util.Utility
608 */
609 public String getCollectionFilename() {
610 if (Gatherer.GS3) {
611 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + collection.getName() + ".col";
612 } else {
613 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + collection.getName() + ".col";
614 }
615 }
616 /** Constructs the absolute filename of the collection images directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/images/"
617 * @return A <strong>String</strong> containing the filename.
618 * @see org.greenstone.gatherer.Configuration
619 * @see org.greenstone.gatherer.Gatherer
620 * @see org.greenstone.gatherer.collection.Collection
621 * @see org.greenstone.gatherer.util.Utility
622 */
623 public String getCollectionImages() {
624 if (Gatherer.GS3) {
625 return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
626 } else {
627 return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
628 }
629 }
630 /** Constructs the absolute filename of the collection import directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/import/"
631 * @return A <strong>String</strong> containing the filename.
632 * @see org.greenstone.gatherer.Configuration
633 * @see org.greenstone.gatherer.Gatherer
634 * @see org.greenstone.gatherer.collection.Collection
635 * @see org.greenstone.gatherer.util.Utility
636 */
637 public String getCollectionImport() {
638 if (Gatherer.GS3) {
639 return Utility.getImportDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
640 } else {
641 return Utility.getImportDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
642 }
643 }
644 /** Constructs the absolute filename of the collection index directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/index/"
645 * @return A <strong>String</strong> containing the filename.
646 * @see org.greenstone.gatherer.Configuration
647 * @see org.greenstone.gatherer.Gatherer
648 * @see org.greenstone.gatherer.collection.Collection
649 * @see org.greenstone.gatherer.util.Utility
650 */
651 public String getCollectionIndex() {
652 if (Gatherer.GS3) {
653 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + "index" + File.separator;
654 } else {
655 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + "index" + File.separator;
656 }
657 }
658 /** Constructs the absolute filename of the collection log directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/log/"
659 * @return A <strong>String</strong> containing the filename.
660 * @see org.greenstone.gatherer.Configuration
661 * @see org.greenstone.gatherer.Gatherer
662 * @see org.greenstone.gatherer.collection.Collection
663 * @see org.greenstone.gatherer.util.Utility
664 */
665 public String getCollectionLog() {
666 if (Gatherer.GS3) {
667 return Utility.getLogDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
668 } else {
669 return Utility.getLogDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
670 }
671 }
672 /** Constructs the absolute filename of the collection metadata directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/metadata/"
673 * @return A <strong>String</strong> containing the filename.
674 * @see org.greenstone.gatherer.Configuration
675 * @see org.greenstone.gatherer.Gatherer
676 * @see org.greenstone.gatherer.collection.Collection
677 * @see org.greenstone.gatherer.util.Utility
678 */
679 public String getCollectionMetadata() {
680 if (Gatherer.GS3) {
681 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + "metadata" + File.separator;
682 } else {
683 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + "metadata" + File.separator;
684 }
685 }
686
687
688 /** Retrieve the tree model associated with the current collection. */
689 public CollectionTreeModel getCollectionTreeModel()
690 {
691 if (collection_model == null && collection != null) {
692 // Use the import directory to generate a new CollectionTreeModel
693 collection_model = new CollectionTreeModel(new CollectionTreeNode(new File(getCollectionImport())));
694 // Ensure that the manager is a change listener for the tree.
695 if (fm_tree_model_listener == null) {
696 fm_tree_model_listener = new FMTreeModelListener();
697 }
698 collection_model.addTreeModelListener(fm_tree_model_listener);
699 }
700 return collection_model;
701 }
702
703
704 /** This method when called, creates a new GShell in order to run the import.pl script.
705 * @see org.greenstone.gatherer.Configuration
706 * @see org.greenstone.gatherer.Gatherer
707 * @see org.greenstone.gatherer.gui.BuildOptions
708 * @see org.greenstone.gatherer.shell.GShell
709 * @see org.greenstone.gatherer.shell.GShellListener
710 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
711 * @see org.greenstone.gatherer.util.Utility
712 */
713 public void importCollection() {
714 importing = true;
715
716 if (!saved()) {
717 DebugStream.println("CollectionManager.importCollection().forcesave");
718 import_monitor.saving();
719 saveCollection();
720 }
721
722 DebugStream.println("CollectionManager.importCollection()");
723 //check that we can remove the old index before starting import
724 File index_dir = new File(getCollectionIndex(), "temp.txt");
725 index_dir = index_dir.getParentFile();
726 if(index_dir.exists()) {
727 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
728 if (!canDelete(index_dir)) {
729 // tell the user
730 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
731 // tell the gui manager
732 // a message for the building log
733 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
734 Gatherer.g_man.create_pane.message(event);
735 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
736 Gatherer.g_man.create_pane.processComplete(event);
737 importing = false;
738 return;
739 }
740 }
741
742 String collect_dir = getCollectDirectory();
743
744 String args[];
745 String lang = Configuration.getLanguage();
746 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
747 args = new String[8];
748 args[0] = Configuration.perl_path;
749 args[1] = "-S";
750 args[2] = Configuration.getScriptPath() + "import.pl";
751 args[3] = "-gli";
752 args[4] = "-language";
753 args[5] = lang;
754 args[6] = "-collectdir";
755 args[7] = collect_dir;
756 }
757 else {
758 args = new String[6];
759 args[0] = Configuration.getScriptPath() + "import.pl";
760 args[1] = "-gli";
761 args[2] = "-language";
762 args[3] = lang;
763 args[4] = "-collectdir";
764 args[5] = collect_dir;
765 }
766 collect_dir = null;
767 args = ArrayTools.add(args, collection.build_options.getImportValues());
768 args = ArrayTools.add(args, collection.getName());
769
770 GShell shell = new GShell(args, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
771 shell.addGShellListener(Gatherer.g_man.create_pane);
772 shell.start();
773 DebugStream.println("CollectionManager.importCollection().return");
774
775 importing = false;
776 }
777
778
779 public void importMetadataSet(MetadataSet external_metadata_set)
780 {
781 // Copy the .mds file into the collection's "metadata" folder...
782 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
783
784 // ...but not if it is the redundant "hidden.mds" file
785 if (external_metadata_set_file.getName().equals("hidden.mds")) {
786 return;
787 }
788
789 // ...and only if it doesn't already exist
790 File metadata_set_file = new File(getCollectionMetadata(), external_metadata_set_file.getName());
791 if (!metadata_set_file.exists()) {
792 try {
793 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, null);
794 }
795 catch (Exception ex) {
796 ex.printStackTrace();
797 }
798
799 // Load it into the MetadataSetManager
800 MetadataSetManager.loadMetadataSet(metadata_set_file);
801 }
802 }
803
804
805 /** 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.
806 * @return true if the gli is currently importing
807 */
808 public boolean isImporting() {
809 return importing;
810 }
811
812 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
813 * @param location The path to the collection as a <strong>String</strong>.
814 * @see org.greenstone.gatherer.Configuration
815 * @see org.greenstone.gatherer.Gatherer
816 * @see org.greenstone.gatherer.collection.Collection
817 * @see org.greenstone.gatherer.util.Utility
818 */
819 public boolean loadCollection(String location)
820 {
821 DebugStream.println("Loading collection " + location + "...");
822 boolean non_gatherer_collection = false;
823
824 // Check we have actually been given a .col file.
825 if (!location.endsWith(".col")) {
826 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
827 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
828 return false;
829 }
830
831 // Check that there is the collection configuration file available
832 File collection_file = new File(location);
833 // Ensure that the directory exists.
834 File collection_directory = collection_file.getParentFile();
835 if (!collection_directory.exists()) {
836 // we cant open this
837 collection_directory = null;
838 return false;
839 }
840 File collection_config_file = new File(collection_directory, Utility.CONFIG_FILE);
841 if (!collection_config_file.exists()) {
842 DebugStream.println("CollectionManager.loadCollection: No config file");
843 collection_directory = null;
844 collection_config_file = null;
845 return false;
846 }
847
848 // Special case of a user trying to open an old greenstone collection.
849 File collection_metadata_directory = new File(collection_directory, Utility.META_DIR);
850 if (!collection_metadata_directory.exists()) {
851 DebugStream.println("Loading non-gatherer collection...");
852 non_gatherer_collection = true;
853 }
854
855 // Now determine if a lock already exists on this collection.
856 String name = collection_directory.getName();
857 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
858 if (lock_file.exists()) {
859 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
860 int choice = dialog.getChoice();
861 dialog.dispose();
862 dialog = null;
863
864 if (choice != LockFileDialog.YES_OPTION) {
865 // user has cancelled
866 lock_file = null;
867 collection_directory = null;
868 collection_config_file = null;
869 return false;
870 }
871
872 lock_file.delete();
873 }
874
875 boolean result = false;
876 try {
877 // Create a lock file.
878 createLockFile(lock_file);
879 // This lock file may not have been created so check
880 if(!lock_file.canWrite()) {
881 // The lock file cannot be written to. Most likely cause incorrect file permissions.
882 System.err.println("Cannot write lock file!");
883 String args[] = new String[2];
884 args[0] = location;
885 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Title");
886 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
887 args = null;
888 return false;
889 }
890
891 // Open the collection file
892 this.collection = new Collection(collection_file);
893 if (collection.error) {
894 collection = null;
895 // Remove lock file
896 if (lock_file.exists()) {
897 lock_file.delete();
898 }
899 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
900 }
901
902 MetadataSetManager.clearMetadataSets();
903 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
904
905 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
906
907 // If this is a non-GLI (legacy) collection, ask the user to choose some metadata sets
908 if (non_gatherer_collection) {
909 if (!addSomeMetadataSets(collection_directory)) {
910 lock_file = null;
911 collection_directory = null;
912 closeCollection();
913 return false;
914 }
915
916 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
917 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
918 }
919
920 // Read through the metadata.xml files in the import directory, building up the metadata value trees
921 File collection_import_directory = new File(collection_directory, Utility.IMPORT_DIR);
922 MetadataXMLFileManager.clearMetadataXMLFiles();
923 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory);
924
925 // Read through the doc.xml files in the archives directory
926 File collection_archives_directory = new File(getCollectionArchives());
927 DocXMLFileManager.clearDocXMLFiles();
928 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
929
930 collection.cdm = new CollectionDesignManager(collection_config_file);
931 if (non_gatherer_collection) {
932 // Change the classifiers to use the namespaced element names
933 LegacyCollectionImporter.updateClassifiers(collection.cdm);
934 }
935
936 // Tell everyone that it worked.
937 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", name));
938
939 // We're done. Let everyone know.
940 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
941 result = true;
942 }
943 catch (Exception error) {
944 // There is obviously no existing collection present.
945 DebugStream.printStackTrace(error);
946 if(error.getMessage() != null) {
947 String[] args = new String[2];
948 args[0] = location;
949 args[1] = error.getMessage();
950 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
951 }
952 else {
953 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
954 }
955 }
956
957 lock_file = null;
958 collection_directory = null;
959 collection_config_file = null;
960
961 return result;
962 }
963
964
965 public void makeCollection(String description, String email, String name, String title) {
966 // Encode the description so it is safe to write to shell
967 if(Utility.isWindows()) {
968 description = Codec.transform(description, Codec.TEXT_TO_SHELL_WINDOWS);
969 }
970 else {
971 description = Codec.transform(description, Codec.TEXT_TO_SHELL_UNIX);
972 }
973 String collect_dir = getCollectDirectory();
974 // Run the mkcol command.
975 String command[];
976 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
977 if(description == null || title == null) {
978 command = new String[8];
979 command[0] = Configuration.perl_path;
980 command[1] = "-S";
981 command[2] = Configuration.getScriptPath() + "mkcol.pl";
982 command[3] = "-collectdir";
983 command[4] = collect_dir;
984 command[5] = "-win31compat";
985 command[6] = (Gatherer.isGsdlRemote) ? "false" : "true";
986 command[7] = name;
987 }
988 // Users are no longer required to supply an email
989 else if(email == null) {
990 command = new String[12];
991 command[0] = Configuration.perl_path;
992 command[1] = "-S";
993 command[2] = Configuration.getScriptPath() + "mkcol.pl";
994 command[3] = "-collectdir";
995 command[4] = collect_dir;
996 command[5] = "-win31compat";
997 command[6] = (Gatherer.isGsdlRemote) ? "false" : "true";
998 command[7] = "-title";
999 command[8] = title;
1000 command[9] = "-about";
1001 command[10] = description;
1002 command[11] = name;
1003 }
1004 else {
1005 command = new String[14];
1006 command[0] = Configuration.perl_path;
1007 command[1] = "-S";
1008 command[2] = Configuration.getScriptPath() + "mkcol.pl";
1009 command[3] = "-collectdir";
1010 command[4] = collect_dir;
1011 command[5] = "-win31compat";
1012 command[6] = (Gatherer.isGsdlRemote) ? "false" : "true";
1013 command[7] = "-title";
1014 command[8] = title;
1015 command[9] = "-creator";
1016 command[10] = email;
1017 command[11] = "-about";
1018 command[12] = description;
1019 command[13] = name;
1020 }
1021 }
1022 else {
1023 if(description == null || title == null) {
1024 command = new String[6];
1025 command[0] = "mkcol.pl";
1026 command[1] = "-collectdir";
1027 command[2] = collect_dir;
1028 command[3] = "-win31compat";
1029 command[4] = (Gatherer.isGsdlRemote) ? "false" : "true";
1030 command[5] = name;
1031 }
1032 else if(email == null) {
1033 command = new String[10];
1034 command[0] = "mkcol.pl";
1035 command[1] = "-collectdir";
1036 command[2] = collect_dir;
1037 command[3] = "-win31compat";
1038 command[4] = (Gatherer.isGsdlRemote) ? "false" : "true";
1039 command[5] = "-title";
1040 command[6] = title;
1041 command[7] = "-about";
1042 command[8] = description;
1043 command[9] = name;
1044 }
1045 else {
1046 command = new String[12];
1047 command[0] = "mkcol.pl";
1048 command[1] = "-collectdir";
1049 command[2] = collect_dir;
1050 command[3] = "-win31compat";
1051 command[4] = (Gatherer.isGsdlRemote) ? "false" : "true";
1052 command[5] = "-title";
1053 command[6] = title;
1054 command[7] = "-creator";
1055 command[8] = email;
1056 command[9] = "-about";
1057 command[10] = description;
1058 command[11] = name;
1059 }
1060 }
1061 GShell process = new GShell(command, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1062 process.run(); // Don't bother threading this... yet
1063 }
1064
1065 /** 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.
1066 * @param event A <strong>GShellEvent</strong> which contains a the message.
1067 */
1068 public synchronized void message(GShellEvent event) {
1069 }
1070
1071 /** This call is fired whenever a process within a GShell created by this class begins.
1072 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1073 * @see org.greenstone.gatherer.Gatherer
1074 * @see org.greenstone.gatherer.gui.GUIManager
1075 * @see org.greenstone.gatherer.shell.GShell
1076 */
1077 public synchronized void processBegun(GShellEvent event) {
1078 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1079 ///ystem.err.println("ProcessBegun " + event.getType());
1080 // If this is one of the types where we wish to lock user control
1081 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1082 }
1083 /** This call is fired whenever a process within a GShell created by this class ends.
1084 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1085 * @see org.greenstone.gatherer.Gatherer
1086 * @see org.greenstone.gatherer.gui.GUIManager
1087 * @see org.greenstone.gatherer.shell.GShell
1088 */
1089 public synchronized void processComplete(GShellEvent event) {
1090 DebugStream.println("CollectionManager.processComplete(" + event.getType() + ")");
1091 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1092 ///ystem.err.println("Recieved process complete event - " + event);
1093 // If we were running an import, now run a build.
1094 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1095 // Finish import.
1096 collection.setImported(true);
1097 buildCollection();
1098 }
1099 // If we were running a build, now is when we move files across.
1100 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1101 if(installCollection()) {
1102 // If we have a local library running then ask it to add our newly create collection
1103 if (LocalLibraryServer.isRunning() == true) {
1104 LocalLibraryServer.addCollection(collection.getName());
1105 }
1106 else if (Gatherer.GS3) {
1107 convertToGS3Collection();
1108 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1109 }
1110
1111 // Fire a collection changed first to update the preview etc buttons
1112 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1113
1114 // Now display a message dialog saying its all built
1115 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", null, false);
1116 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1117 collection_built_warning_dialog.display();
1118 collection_built_warning_dialog.dispose();
1119 collection_built_warning_dialog = null;
1120 }
1121 else {
1122 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1123 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1124 }
1125 }
1126 else if(event.getStatus() == GShell.ERROR || event.getStatus() == GShell.CANCELLED) {
1127 DebugStream.println("There was an error in the gshell:"+ event.getMessage());
1128 if (event.getType() == GShell.NEW) {
1129 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1130 } else {
1131 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1132 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1133 }
1134
1135 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.
1136 }
1137 }
1138
1139
1140 /** Determine if the manager is ready for actions apon its collection.
1141 * @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.
1142 */
1143 static public synchronized boolean ready() {
1144 if(collection != null) {
1145 return true;
1146 }
1147 else {
1148 return false;
1149 }
1150 }
1151
1152
1153 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1154 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1155 */
1156 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1157 build_monitor = monitor;
1158 }
1159 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1160 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1161 */
1162 public void registerImportMonitor(GShellProgressMonitor monitor) {
1163 import_monitor = monitor;
1164 }
1165
1166
1167 public void removeMetadataSet(MetadataSet metadata_set)
1168 {
1169 System.err.println("Removing metadata set...");
1170
1171 // Delete the .mds file from the collection's "metadata" folder...
1172 File metadata_set_file = metadata_set.getMetadataSetFile();
1173
1174 // ...but not if it is the "ex.mds" file
1175 if (metadata_set_file.getName().equals("ex.mds")) {
1176 return;
1177 }
1178
1179 // ...and only if it exists
1180 if (metadata_set_file.exists()) {
1181 metadata_set_file.delete();
1182
1183 // Unload it from the MetadataSetManager
1184 MetadataSetManager.unloadMetadataSet(metadata_set);
1185 }
1186 }
1187
1188
1189 /** Used to check whether all open collections have a 'saved' state.
1190 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1191 * @see org.greenstone.gatherer.collection.Collection
1192 */
1193 public boolean saved() {
1194 boolean result = true;
1195 if(collection != null) {
1196 result = collection.getSaved();
1197 }
1198 return result;
1199 }
1200
1201
1202 /** Saves the currently loaded collection. */
1203 public void saveCollection()
1204 {
1205 DebugStream.println("Saving collection " + collection.getName() + "...");
1206
1207 // Change cursor to hourglass
1208 Gatherer.g_man.wait(true);
1209
1210 // Create a backup of the collection file, just in case anything goes wrong
1211 File collection_file = new File(Gatherer.c_man.getCollectionFilename());
1212 if (collection_file.exists()) {
1213 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1214 if (!collection_file.renameTo(collection_file_backup)) {
1215 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1216 }
1217 collection_file_backup.deleteOnExit();
1218 }
1219
1220 // Write out the collection file
1221 collection.save();
1222
1223 // Write out the collection configuration file
1224 Gatherer.g_man.design_pane.saveConfiguration();
1225
1226 // Write hfiles for the loaded metadata elements into the collection "etc" directory
1227 MetadataSetManager.writeHierarchyFiles(new File(Gatherer.c_man.getCollectionEtc()));
1228
1229 // Change cursor back to normal
1230 Gatherer.g_man.wait(false);
1231 }
1232
1233
1234 /** 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] */
1235 private boolean addSomeMetadataSets(File collection_dir) {
1236
1237
1238 ExternalCollectionPrompt external_prompt = new ExternalCollectionPrompt();
1239 int meta_choice = external_prompt.getMetadataChoice();
1240 boolean cancelled = external_prompt.isCancelled();
1241 if (cancelled) {
1242 return false;
1243 }
1244
1245 // now we reuse the newcoll metadata prompt for the user to select metadata sets
1246 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt(true);
1247 if (ncm_prompt.isCancelled()) {
1248 return false;
1249 }
1250 ArrayList metadata_sets = ncm_prompt.getSets();
1251 // Import default metadata sets if any.
1252 for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
1253 importMetadataSet((MetadataSet) metadata_sets.get(i));
1254 }
1255
1256 // Always import the extracted metadata set
1257 File extracted_metadata_set_file = new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1258 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1259
1260 return true;
1261 }
1262
1263
1264 // used as arg in the perl scripts
1265 private String getCollectDirectory() {
1266 String collect_dir;
1267 if (Gatherer.GS3) {
1268 collect_dir = Utility.getCollectDir(Configuration.gsdl3_path, Configuration.site_name);
1269 } else {
1270 collect_dir = Utility.getCollectDir(Configuration.gsdl_path);
1271 }
1272
1273 // Remove erroneous file windows file separator as it causes problems when running import.pl
1274 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1275 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1276 }
1277
1278 return collect_dir;
1279 }
1280
1281
1282 /** Install collection by moving its files from building to index after a successful build.
1283 * @see org.greenstone.gatherer.Gatherer
1284 * @see org.greenstone.gatherer.util.Utility
1285 */
1286 private boolean installCollection()
1287 {
1288 DebugStream.println("Build complete. Moving files.");
1289
1290 try {
1291 // Ensure that the local library has released this collection so we can delete the index directory
1292 if (LocalLibraryServer.isRunning() == true) {
1293 LocalLibraryServer.releaseCollection(collection.getName());
1294 }
1295
1296 File index_dir = new File(getCollectionIndex());
1297 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1298
1299 File building_dir = new File(getCollectionBuild());
1300 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1301
1302 // Get the build mode from the build options
1303 String build_mode = collection.build_options.getBuildValue("mode");
1304
1305 // Special case for build mode "all": replace index dir with building dir
1306 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1307 // Remove the old index directory
1308 if (index_dir.exists()) {
1309 Utility.delete(index_dir);
1310
1311 // Wait for a couple of seconds, just for luck
1312 wait(2000);
1313
1314 // Check the delete worked
1315 if (index_dir.exists()) {
1316 throw new Exception("Index directory could not be removed.");
1317 }
1318 }
1319
1320 // Move the building directory to become the new index directory
1321 if (building_dir.renameTo(index_dir) == false) {
1322 throw new Exception("Build directory could not be moved.");
1323 }
1324 }
1325
1326 // Otherwise copy everything in the building dir into the index dir
1327 else {
1328 moveContentsInto(building_dir, index_dir);
1329 }
1330 }
1331 catch (Exception exception) {
1332 JOptionPane.showMessageDialog(Gatherer.g_man, "Exception detected during collection install.\nMost likely caused by Windows or Local Library holding locks on files:\n" + exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
1333 return false;
1334 }
1335 return true;
1336 }
1337
1338
1339 /** Moves all the files in one directory into another, overwriting existing files */
1340 private void moveContentsInto(File source_directory, File target_directory)
1341 {
1342 File[] source_files = source_directory.listFiles();
1343 for (int i = 0; i < source_files.length; i++) {
1344 File source_file = source_files[i];
1345 File target_file = new File(target_directory, source_file.getName());
1346
1347 if (source_file.isDirectory()) {
1348 moveContentsInto(source_file, target_file);
1349 source_file.delete();
1350 }
1351 else {
1352 if (target_file.exists()) {
1353 target_file.delete();
1354 }
1355
1356 source_file.renameTo(target_file);
1357 }
1358 }
1359 }
1360
1361
1362 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1363 {
1364 boolean first_name = true;
1365 boolean first_extra = true;
1366 String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
1367
1368 // 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.
1369 try {
1370 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1371 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1372 String command = null;
1373 while((command = in.readLine()) != null) {
1374 if (command.length()==0) {
1375 // output a new line
1376 out.newLine();
1377 continue;
1378 }
1379 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1380 while(command.trim().endsWith("\\")) {
1381 command = command.substring(0, command.lastIndexOf("\\"));
1382 String next_line = in.readLine();
1383 if(next_line != null) {
1384 command = command + next_line;
1385 }
1386 }
1387 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1388 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1389 String command_type_str = tokenizer.nextToken().toLowerCase();
1390
1391 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1392 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1393 StringBuffer new_command = new StringBuffer(command_type_str);
1394 String meta_name = tokenizer.nextToken();
1395 new_command.append(' ');
1396 new_command.append(meta_name);
1397 while (tokenizer.hasMoreTokens()) {
1398 new_command.append(' ');
1399 new_command.append(tokenizer.nextToken());
1400 }
1401 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)) {
1402 // dont save
1403 } else {
1404 write(out, new_command.toString());
1405 }
1406 new_command = null;
1407 continue;
1408 } // if collectionmeta
1409
1410 if(command_type_str.equals(Utility.CFG_CLASSIFY)) {
1411 StringBuffer text = new StringBuffer(command_type_str);
1412 // Read in the classifier command watching for hfile, metadata and sort arguments.
1413 String buttonname = null;
1414 String hfile = null;
1415 String new_metadata = null;
1416 String old_metadata = null;
1417
1418 while(tokenizer.hasMoreTokens()) {
1419 String token = tokenizer.nextToken();
1420 if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
1421 if(tokenizer.hasMoreTokens()) {
1422 text.append(" ");
1423 text.append(token);
1424 token = tokenizer.nextToken();
1425 hfile = token;
1426 }
1427 }
1428 else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
1429 if(tokenizer.hasMoreTokens()) {
1430 text.append(" ");
1431 text.append(token);
1432 String temp_metadata = tokenizer.nextToken();
1433 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1434 if (replacement != null && !replacement.equals("")) {
1435 token = replacement;
1436 old_metadata = temp_metadata;
1437 new_metadata = replacement;
1438 }
1439 else {
1440 token = temp_metadata;
1441 }
1442 temp_metadata = null;
1443 replacement = null;
1444 }
1445 }
1446 else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
1447 if(tokenizer.hasMoreTokens()) {
1448 text.append(" ");
1449 text.append(token);
1450 String temp_metadata = tokenizer.nextToken();
1451 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1452 if (replacement != null && !replacement.equals("")) {
1453 token = replacement;
1454 }
1455 else {
1456 token = temp_metadata;
1457 }
1458 temp_metadata = null;
1459 replacement = null;
1460 }
1461 }
1462 else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
1463 buttonname = token;
1464 }
1465 text.append(' ');
1466 text.append(token);
1467 token = null;
1468 }
1469
1470 // 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)!
1471 if(old_metadata != null && new_metadata != null && buttonname == null) {
1472 text.append(' ');
1473 text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
1474 text.append(' ');
1475 text.append(old_metadata);
1476 }
1477 command = text.toString();
1478 // Replace the hfile if we found it
1479 if(hfile != null && new_metadata != null) {
1480 command = command.replaceAll(hfile, new_metadata + ".txt");
1481 }
1482
1483 buttonname = null;
1484 hfile = null;
1485 new_metadata = null;
1486 old_metadata = null;
1487 write(out, command);
1488 } else {
1489 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
1490 StringBuffer new_command = new StringBuffer(command_type_str);
1491 while (tokenizer.hasMoreTokens()) {
1492 new_command.append(' ');
1493 new_command.append(tokenizer.nextToken());
1494 }
1495
1496 command = new_command.toString();
1497
1498 // 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.
1499 // we really want to build up the whole command here
1500 boolean format_command = command_type_str.equals(Utility.CFG_FORMAT);
1501 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
1502 if (metadata_mapping != null) {
1503 Iterator keys = metadata_mapping.keySet().iterator();
1504 while (keys.hasNext()) {
1505 String target = (String) keys.next();
1506 String replacement = (String) metadata_mapping.get(target);
1507 if (replacement != null && !replacement.equals("")) {
1508 if (format_command) {
1509 target = "\\[" + target + "\\]";
1510 replacement = "{Or}{[" + replacement + "]," + target + "}";
1511 }
1512 command = command.replaceAll(target, replacement);
1513 }
1514 }
1515 }
1516
1517 write(out, command);
1518 }
1519 tokenizer = null;
1520 }
1521 in.close();
1522 in = null;
1523 out.flush();
1524 out.close();
1525 out = null;
1526 }
1527 catch(Exception error) {
1528 DebugStream.printStackTrace(error);
1529 }
1530 // All done, I hope.
1531 }
1532
1533 private void write(BufferedWriter out, String message)
1534 throws Exception {
1535 out.write(message, 0, message.length());
1536 out.newLine();
1537 }
1538
1539
1540 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
1541 private class FMTreeModelListener
1542 implements TreeModelListener {
1543 /** 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.
1544 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1545 */
1546 public void treeNodesChanged(TreeModelEvent event) {
1547 if(collection != null) {
1548 collection.setSaved(false);
1549 }
1550 }
1551 /** 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.
1552 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1553 */
1554 public void treeNodesInserted(TreeModelEvent event) {
1555 if(collection != null) {
1556 collection.setSaved(false);
1557 }
1558 }
1559 /** 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.
1560 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1561 */
1562 public void treeNodesRemoved(TreeModelEvent event) {
1563 if(collection != null) {
1564 collection.setSaved(false);
1565 }
1566 }
1567 /** 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.
1568 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1569 */
1570 public void treeStructureChanged(TreeModelEvent event) {
1571 if(collection != null) {
1572 collection.setSaved(false);
1573 }
1574 }
1575 }
1576}
Note: See TracBrowser for help on using the repository browser.