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

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

Removed another unused class.

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