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

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

Now uploads and deletes metadata sets on the server when metadata sets are added/removed to a collection (using remote building).

  • Property svn:keywords set to Author Date Id Revision
File size: 60.3 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.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 // If we're using a remote Greenstone server, upload the metadata file
705 if (Gatherer.isGsdlRemote) {
706 RemoteGreenstoneServer.uploadCollectionFile(metadata_set_file);
707 }
708 }
709 catch (Exception ex) {
710 ex.printStackTrace();
711 }
712
713 // Load it into the MetadataSetManager
714 MetadataSetManager.loadMetadataSet(metadata_set_file);
715 }
716 }
717
718
719 /** 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.
720 * @return true if the gli is currently importing
721 */
722 public boolean isImporting() {
723 return importing;
724 }
725
726
727 public void loadCollection(String collection_file_path)
728 {
729 // Display a modal progress popup to indicate that the collection is being loaded
730 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
731 load_collection_progress_popup.display();
732
733 // Load the collection on a separate thread so the progress bar updates correctly
734 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
735 }
736
737
738 private class LoadCollectionTask
739 extends Thread
740 {
741 private String collection_file_path = null;
742 private ModalProgressPopup load_collection_progress_popup = null;
743
744 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
745 {
746 this.collection_file_path = collection_file_path;
747 this.load_collection_progress_popup = load_collection_progress_popup;
748 }
749
750 public void run()
751 {
752 loadCollectionInternal(collection_file_path);
753 load_collection_progress_popup.close();
754 }
755 }
756
757
758 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
759 * @param location The path to the collection as a <strong>String</strong>.
760 * @see org.greenstone.gatherer.Configuration
761 * @see org.greenstone.gatherer.Gatherer
762 * @see org.greenstone.gatherer.collection.Collection
763 * @see org.greenstone.gatherer.util.Utility
764 */
765 private void loadCollectionInternal(String location)
766 {
767 DebugStream.println("Loading collection " + location + "...");
768
769 if (Gatherer.isGsdlRemote) {
770 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
771 RemoteGreenstoneServer.downloadCollection(collection_name);
772 }
773
774 boolean non_gli_collection = false;
775
776 // Check we have actually been given a .col file.
777 if (!location.endsWith(".col")) {
778 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
779 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
780 return;
781 }
782
783 // Check that the collection configuration file is available
784 File collection_file = new File(location);
785
786 // Ensure that the directory exists
787 File collection_directory = collection_file.getParentFile();
788 if (collection_directory == null || !collection_directory.exists()) {
789 // We can't open this
790 System.err.println("CollectionManager.loadCollection: No collection directory.");
791 return;
792 }
793
794 File collection_config_file = new File(collection_directory, Utility.CONFIG_FILE);
795 if (!collection_config_file.exists()) {
796 System.err.println("CollectionManager.loadCollection: No config file.");
797 collection_directory = null;
798 collection_config_file = null;
799 return;
800 }
801
802 // Ensure that an import directory exists for this collection
803 File collection_import_directory = new File(collection_directory, Utility.IMPORT_DIR);
804 if (!collection_import_directory.exists()) {
805 collection_import_directory.mkdir();
806 }
807
808 // Special case of a user trying to open an old greenstone collection.
809 File collection_metadata_directory = new File(collection_directory, Utility.META_DIR);
810 if (!collection_metadata_directory.exists()) {
811 DebugStream.println("Loading non-gatherer collection...");
812 non_gli_collection = true;
813 }
814
815 // Now determine if a lock already exists on this collection.
816 String name = collection_directory.getName();
817 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
818 if (lock_file.exists()) {
819 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
820 int choice = dialog.getChoice();
821 dialog.dispose();
822 dialog = null;
823
824 if (choice != LockFileDialog.YES_OPTION) {
825 // user has cancelled
826 lock_file = null;
827 collection_directory = null;
828 collection_config_file = null;
829 return;
830 }
831
832 lock_file.delete();
833 }
834
835 try {
836 // Create a lock file.
837 createLockFile(lock_file);
838 // This lock file may not have been created so check
839 if(!lock_file.canWrite()) {
840 // The lock file cannot be written to. Most likely cause incorrect file permissions.
841 System.err.println("Cannot write lock file!");
842 String args[] = new String[2];
843 args[0] = location;
844 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Title");
845 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
846 args = null;
847 return;
848 }
849
850 // Open the collection file
851 this.collection = new Collection(collection_file);
852 if (collection.error) {
853 collection = null;
854 // Remove lock file
855 if (lock_file.exists()) {
856 lock_file.delete();
857 }
858 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
859 }
860
861 MetadataSetManager.clearMetadataSets();
862 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
863
864 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
865
866 // If this is a non-GLI (legacy) collection, ask the user to choose some metadata sets
867 if (non_gli_collection) {
868 if (!addSomeMetadataSets(collection_directory)) {
869 lock_file = null;
870 collection_directory = null;
871 closeCollection();
872 return;
873 }
874
875 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
876 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
877 }
878
879 // Read through the metadata.xml files in the import directory, building up the metadata value trees
880 MetadataXMLFileManager.clearMetadataXMLFiles();
881 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory);
882
883 // Read through the doc.xml files in the archives directory
884 File collection_archives_directory = new File(getCollectionArchivesDirectoryPath());
885 DocXMLFileManager.clearDocXMLFiles();
886 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
887
888 collection.cdm = new CollectionDesignManager(collection_config_file);
889 if (non_gli_collection) {
890 // Change the classifiers to use the namespaced element names
891 LegacyCollectionImporter.updateClassifiers(collection.cdm);
892 }
893
894 // We're done. Let everyone know.
895 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", name));
896 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
897 }
898 catch (Exception error) {
899 // There is obviously no existing collection present.
900 DebugStream.printStackTrace(error);
901 if(error.getMessage() != null) {
902 String[] args = new String[2];
903 args[0] = location;
904 args[1] = error.getMessage();
905 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
906 }
907 else {
908 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
909 }
910 }
911
912 lock_file = null;
913 collection_directory = null;
914 collection_config_file = null;
915 }
916
917
918 private void makeCollection(String name, String email)
919 {
920 // Generate the mkcol.pl command
921 ArrayList command_parts_list = new ArrayList();
922 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
923 command_parts_list.add(Configuration.perl_path);
924 command_parts_list.add("-S");
925 }
926 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
927
928 command_parts_list.add("-collectdir");
929 command_parts_list.add(getCollectDirectory());
930 command_parts_list.add("-win31compat");
931 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
932
933 if (email != null && !email.equals("")) {
934 command_parts_list.add("-creator");
935 command_parts_list.add(email);
936 }
937
938 command_parts_list.add(name);
939
940 // Run the mkcol.pl command
941 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
942 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
943 process.run(); // Don't bother threading this... yet
944 }
945
946
947 /** 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.
948 * @param event A <strong>GShellEvent</strong> which contains a the message.
949 */
950 public synchronized void message(GShellEvent event) {
951 }
952
953
954 public void metadataChanged(CollectionTreeNode[] file_nodes)
955 {
956 if (collection != null) {
957 collection.setMetadataChanged(true);
958 }
959 }
960
961
962 /** This call is fired whenever a process within a GShell created by this class begins.
963 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
964 * @see org.greenstone.gatherer.Gatherer
965 * @see org.greenstone.gatherer.gui.GUIManager
966 * @see org.greenstone.gatherer.shell.GShell
967 */
968 public synchronized void processBegun(GShellEvent event) {
969 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
970 ///ystem.err.println("ProcessBegun " + event.getType());
971 // If this is one of the types where we wish to lock user control
972 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
973 }
974 /** This call is fired whenever a process within a GShell created by this class ends.
975 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
976 * @see org.greenstone.gatherer.Gatherer
977 * @see org.greenstone.gatherer.gui.GUIManager
978 * @see org.greenstone.gatherer.shell.GShell
979 */
980 public synchronized void processComplete(GShellEvent event) {
981 DebugStream.println("CollectionManager.processComplete(" + event.getType() + ")");
982 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
983 ///ystem.err.println("Recieved process complete event - " + event);
984 // If we were running an import, now run a build.
985 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
986 // Finish import.
987 collection.setImported(true);
988 buildCollection();
989 }
990 // If we were running a build, now is when we move files across.
991 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
992 if(installCollection()) {
993 // If we have a local library running then ask it to add our newly create collection
994 if (LocalLibraryServer.isRunning() == true) {
995 LocalLibraryServer.addCollection(collection.getName());
996 }
997 else if (Gatherer.GS3) {
998 convertToGS3Collection();
999 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1000 }
1001
1002 // Fire a collection changed first to update the preview etc buttons
1003 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1004
1005 // Now display a message dialog saying its all built
1006 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", "CollectionBuilt.Title", Dictionary.get("CollectionBuilt.Message"), null, false);
1007 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1008 collection_built_warning_dialog.display();
1009 collection_built_warning_dialog.dispose();
1010 collection_built_warning_dialog = null;
1011
1012 //Set nothing as needing rebuilding, as a build has just finished :-)
1013 CollectionDesignManager.resetRebuildTypeRequired();
1014 }
1015 else {
1016 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1017 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1018 DebugStream.println("Status is ok but !installCollection()");
1019 }
1020 }
1021 else if (event.getStatus() == GShell.CANCELLED) {
1022 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1023 Gatherer.g_man.repaint();
1024 }
1025 else if (event.getStatus() == GShell.ERROR) {
1026 DebugStream.println("There was an error in the gshell:"+ event.getMessage());
1027 if (event.getType() == GShell.NEW) {
1028 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1029 } else {
1030 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1031 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1032 }
1033
1034 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.
1035 }
1036 }
1037
1038
1039 /** Determine if the manager is ready for actions apon its collection.
1040 * @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.
1041 */
1042 static public synchronized boolean ready() {
1043 if(collection != null) {
1044 return true;
1045 }
1046 else {
1047 return false;
1048 }
1049 }
1050
1051
1052 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1053 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1054 */
1055 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1056 build_monitor = monitor;
1057 }
1058 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1059 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1060 */
1061 public void registerImportMonitor(GShellProgressMonitor monitor) {
1062 import_monitor = monitor;
1063 }
1064
1065
1066 public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1067 {
1068 collection_contents_changed_listeners.remove(listener);
1069 }
1070
1071
1072 public void removeMetadataSet(MetadataSet metadata_set)
1073 {
1074 System.err.println("Removing metadata set...");
1075
1076 // Delete the .mds file from the collection's "metadata" folder...
1077 File metadata_set_file = metadata_set.getMetadataSetFile();
1078
1079 // ...but not if it is the "ex.mds" file
1080 if (metadata_set_file.getName().equals("ex.mds")) {
1081 return;
1082 }
1083
1084 // ...and only if it exists
1085 if (metadata_set_file.exists()) {
1086 metadata_set_file.delete();
1087
1088 // Unload it from the MetadataSetManager
1089 MetadataSetManager.unloadMetadataSet(metadata_set);
1090
1091 // If we're using a remote Greenstone server, delete the metadata file on the server
1092 if (Gatherer.isGsdlRemote) {
1093 String relative_metadata_set_file_path = RemoteGreenstoneServer.getPathRelativeToDirectory(metadata_set_file.getAbsolutePath(), Gatherer.getGLIUserDirectoryPath());
1094 RemoteGreenstoneServer.sendDeleteFileCommand(relative_metadata_set_file_path);
1095 }
1096 }
1097 }
1098
1099
1100 /** Used to check whether all open collections have a 'saved' state.
1101 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1102 * @see org.greenstone.gatherer.collection.Collection
1103 */
1104 public boolean saved() {
1105 boolean result = true;
1106 if(collection != null) {
1107 result = collection.getSaved();
1108 }
1109 return result;
1110 }
1111
1112
1113 /** Saves the currently loaded collection. */
1114 public void saveCollection()
1115 {
1116 DebugStream.println("Saving collection " + collection.getName() + "...");
1117
1118 // Change cursor to hourglass
1119 Gatherer.g_man.wait(true);
1120
1121 // Create a backup of the collection file, just in case anything goes wrong
1122 File collection_file = new File(getCollectionFilePath());
1123 if (collection_file.exists()) {
1124 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1125 if (!collection_file.renameTo(collection_file_backup)) {
1126 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1127 }
1128 collection_file_backup.deleteOnExit();
1129 }
1130
1131 // Write out the collection file
1132 collection.save();
1133
1134 // Write out the collection configuration file
1135 Gatherer.g_man.design_pane.saveConfiguration();
1136
1137 // Change cursor back to normal
1138 Gatherer.g_man.wait(false);
1139 }
1140
1141
1142 /** 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] */
1143 private boolean addSomeMetadataSets(File collection_dir) {
1144
1145
1146 ExternalCollectionPrompt external_prompt = new ExternalCollectionPrompt();
1147 int meta_choice = external_prompt.getMetadataChoice();
1148 boolean cancelled = external_prompt.isCancelled();
1149 if (cancelled) {
1150 return false;
1151 }
1152
1153 // now we reuse the newcoll metadata prompt for the user to select metadata sets
1154 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt(true);
1155 if (ncm_prompt.isCancelled()) {
1156 return false;
1157 }
1158 ArrayList metadata_sets = ncm_prompt.getSets();
1159 // Import default metadata sets if any.
1160 for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
1161 importMetadataSet((MetadataSet) metadata_sets.get(i));
1162 }
1163
1164 // Always import the extracted metadata set
1165 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1166 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1167
1168 return true;
1169 }
1170
1171
1172 // used as arg in the perl scripts
1173 private String getCollectDirectory() {
1174 String collect_dir = Gatherer.getCollectDirectoryPath();
1175
1176 // Remove erroneous file windows file separator as it causes problems when running import.pl
1177 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1178 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1179 }
1180
1181 return collect_dir;
1182 }
1183
1184
1185 /** Install collection by moving its files from building to index after a successful build.
1186 * @see org.greenstone.gatherer.Gatherer
1187 * @see org.greenstone.gatherer.util.Utility
1188 */
1189 private boolean installCollection()
1190 {
1191 DebugStream.println("Build complete. Moving files.");
1192
1193 try {
1194 // Ensure that the local library has released this collection so we can delete the index directory
1195 if (LocalLibraryServer.isRunning() == true) {
1196 LocalLibraryServer.releaseCollection(collection.getName());
1197 }
1198 // deactivate it in tomcat so that windows will release the index files
1199 if (Gatherer.GS3) {
1200 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1201 }
1202 File index_dir = new File(getCollectionIndexDirectoryPath());
1203 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1204
1205 File building_dir = new File(getCollectionBuildingDirectoryPath());
1206 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1207
1208 // Get the build mode from the build options
1209 String build_mode = collection.build_options.getValue("mode");
1210
1211 // Special case for build mode "all": replace index dir with building dir
1212 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1213 // Remove the old index directory
1214 if (index_dir.exists()) {
1215 Utility.delete(index_dir);
1216
1217 // Wait for a couple of seconds, just for luck
1218 wait(2000);
1219
1220 // Check the delete worked
1221 if (index_dir.exists()) {
1222 throw new Exception("Index directory could not be removed.");
1223 }
1224 }
1225
1226 // Move the building directory to become the new index directory
1227 if (building_dir.renameTo(index_dir) == false) {
1228 throw new Exception("Build directory could not be moved.");
1229 }
1230 }
1231
1232 // Otherwise copy everything in the building dir into the index dir
1233 else {
1234 moveContentsInto(building_dir, index_dir);
1235 }
1236 }
1237 catch (Exception exception) {
1238 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);
1239 return false;
1240 }
1241 return true;
1242 }
1243
1244
1245 /** Moves all the files in one directory into another, overwriting existing files */
1246 private void moveContentsInto(File source_directory, File target_directory)
1247 {
1248 File[] source_files = source_directory.listFiles();
1249 for (int i = 0; i < source_files.length; i++) {
1250 File source_file = source_files[i];
1251 File target_file = new File(target_directory, source_file.getName());
1252
1253 if (source_file.isDirectory()) {
1254 moveContentsInto(source_file, target_file);
1255 source_file.delete();
1256 }
1257 else {
1258 if (target_file.exists()) {
1259 target_file.delete();
1260 }
1261
1262 source_file.renameTo(target_file);
1263 }
1264 }
1265 }
1266
1267
1268 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1269 {
1270 boolean first_name = true;
1271 boolean first_extra = true;
1272 String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
1273
1274 // 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.
1275 try {
1276 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1277 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1278 String command = null;
1279 while((command = in.readLine()) != null) {
1280 if (command.length()==0) {
1281 // output a new line
1282 out.newLine();
1283 continue;
1284 }
1285 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1286 while(command.trim().endsWith("\\")) {
1287 command = command.substring(0, command.lastIndexOf("\\"));
1288 String next_line = in.readLine();
1289 if(next_line != null) {
1290 command = command + next_line;
1291 }
1292 }
1293 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1294 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1295 String command_type_str = tokenizer.nextToken().toLowerCase();
1296
1297 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1298 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1299 StringBuffer new_command = new StringBuffer(command_type_str);
1300 String meta_name = tokenizer.nextToken();
1301 new_command.append(' ');
1302 new_command.append(meta_name);
1303 while (tokenizer.hasMoreTokens()) {
1304 new_command.append(' ');
1305 new_command.append(tokenizer.nextToken());
1306 }
1307 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)) {
1308 // dont save
1309 } else {
1310 write(out, new_command.toString());
1311 }
1312 new_command = null;
1313 continue;
1314 } // if collectionmeta
1315
1316 if(command_type_str.equals(Utility.CFG_CLASSIFY)) {
1317 StringBuffer text = new StringBuffer(command_type_str);
1318 // Read in the classifier command watching for hfile, metadata and sort arguments.
1319 String buttonname = null;
1320 String hfile = null;
1321 String new_metadata = null;
1322 String old_metadata = null;
1323
1324 while(tokenizer.hasMoreTokens()) {
1325 String token = tokenizer.nextToken();
1326 if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
1327 if(tokenizer.hasMoreTokens()) {
1328 text.append(" ");
1329 text.append(token);
1330 token = tokenizer.nextToken();
1331 hfile = token;
1332 }
1333 }
1334 else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
1335 if(tokenizer.hasMoreTokens()) {
1336 text.append(" ");
1337 text.append(token);
1338 String temp_metadata = tokenizer.nextToken();
1339 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1340 if (replacement != null && !replacement.equals("")) {
1341 token = replacement;
1342 old_metadata = temp_metadata;
1343 new_metadata = replacement;
1344 }
1345 else {
1346 token = temp_metadata;
1347 }
1348 temp_metadata = null;
1349 replacement = null;
1350 }
1351 }
1352 else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
1353 if(tokenizer.hasMoreTokens()) {
1354 text.append(" ");
1355 text.append(token);
1356 String temp_metadata = tokenizer.nextToken();
1357 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1358 if (replacement != null && !replacement.equals("")) {
1359 token = replacement;
1360 }
1361 else {
1362 token = temp_metadata;
1363 }
1364 temp_metadata = null;
1365 replacement = null;
1366 }
1367 }
1368 else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
1369 buttonname = token;
1370 }
1371 text.append(' ');
1372 text.append(token);
1373 token = null;
1374 }
1375
1376 // 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)!
1377 if(old_metadata != null && new_metadata != null && buttonname == null) {
1378 text.append(' ');
1379 text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
1380 text.append(' ');
1381 text.append(old_metadata);
1382 }
1383 command = text.toString();
1384 // Replace the hfile if we found it
1385 if(hfile != null && new_metadata != null) {
1386 command = command.replaceAll(hfile, new_metadata + ".txt");
1387 }
1388
1389 buttonname = null;
1390 hfile = null;
1391 new_metadata = null;
1392 old_metadata = null;
1393 write(out, command);
1394 } else {
1395 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
1396 StringBuffer new_command = new StringBuffer(command_type_str);
1397 while (tokenizer.hasMoreTokens()) {
1398 new_command.append(' ');
1399 new_command.append(tokenizer.nextToken());
1400 }
1401
1402 command = new_command.toString();
1403
1404 // 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.
1405 // we really want to build up the whole command here
1406 boolean format_command = command_type_str.equals(Utility.CFG_FORMAT);
1407 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
1408 if (metadata_mapping != null) {
1409 Iterator keys = metadata_mapping.keySet().iterator();
1410 while (keys.hasNext()) {
1411 String target = (String) keys.next();
1412 String replacement = (String) metadata_mapping.get(target);
1413 if (replacement != null && !replacement.equals("")) {
1414 if (format_command) {
1415 target = "\\[" + target + "\\]";
1416 replacement = "{Or}{[" + replacement + "]," + target + "}";
1417 }
1418 command = command.replaceAll(target, replacement);
1419 }
1420 }
1421 }
1422
1423 write(out, command);
1424 }
1425 tokenizer = null;
1426 }
1427 in.close();
1428 in = null;
1429 out.flush();
1430 out.close();
1431 out = null;
1432 }
1433 catch(Exception error) {
1434 DebugStream.printStackTrace(error);
1435 }
1436 // All done, I hope.
1437 }
1438
1439 private void write(BufferedWriter out, String message)
1440 throws Exception {
1441 out.write(message, 0, message.length());
1442 out.newLine();
1443 }
1444
1445
1446 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
1447 private class FMTreeModelListener
1448 implements TreeModelListener {
1449 /** 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.
1450 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1451 */
1452 public void treeNodesChanged(TreeModelEvent event) {
1453 if(collection != null) {
1454 collection.setSaved(false);
1455 collection.setFilesChanged(true);
1456 }
1457 }
1458 /** 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.
1459 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1460 */
1461 public void treeNodesInserted(TreeModelEvent event) {
1462 if(collection != null) {
1463 collection.setSaved(false);
1464 collection.setFilesChanged(true);
1465 }
1466 }
1467 /** 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.
1468 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1469 */
1470 public void treeNodesRemoved(TreeModelEvent event) {
1471 if(collection != null) {
1472 collection.setSaved(false);
1473 collection.setFilesChanged(true);
1474
1475 }
1476 }
1477 /** 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.
1478 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1479 */
1480 public void treeStructureChanged(TreeModelEvent event) {
1481 if(collection != null) {
1482 collection.setSaved(false);
1483 }
1484 }
1485 }
1486}
Note: See TracBrowser for help on using the repository browser.