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

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

Tidied up the workspace and collection trees a bit more, in preparation for having special icons for some collection files.

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