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

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

Now downloads the collection configurations (when using a remote Greenstone server) when the GLI starts up, rather than when File -> Open is selected.

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