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

Last change on this file since 11627 was 11627, checked in by mdewsnip, 18 years ago

The collection tree object is now created and owned by CollectionManager.

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