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

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

For some reason the lock file written when a collection is just created is different from that when the collection is reloaded. Worse, it wasn't valid XML so the tidied up parsing would barf on it. Now the same lock file is written is both circumstances, making everything a lot tidier.

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