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

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

Minor change.

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