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

Last change on this file since 16265 was 16265, checked in by ak19, 16 years ago

Scheduling method requires that Greenstone be version 2 AND that the GLI that is running it is located inside the Greenstone 2 installation (since it requires the main.cfg inside GS2's etc folder). In other cases GLI crashes when trying to create a new collection. This will need to be fixed later so that it is no longer dependent on 1. where GLI is located; 2. Whether GS is v2 or v3; 3. Whether GS is a remote server or local.

  • Property svn:keywords set to Author Date Id Revision
File size: 80.2 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.cdm.CollectionDesignManager;
50import org.greenstone.gatherer.cdm.CollectionMeta;
51import org.greenstone.gatherer.cdm.CollectionMetaManager;
52import org.greenstone.gatherer.cdm.CommandTokenizer;
53import org.greenstone.gatherer.greenstone.Classifiers;
54import org.greenstone.gatherer.greenstone.LocalGreenstone;
55import org.greenstone.gatherer.greenstone.LocalLibraryServer;
56import org.greenstone.gatherer.greenstone.Plugins;
57import org.greenstone.gatherer.greenstone3.ServletConfiguration;
58import org.greenstone.gatherer.gui.LockFileDialog;
59import org.greenstone.gatherer.gui.ModalProgressPopup;
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 responsible 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 static private boolean building = false;
87 /** Are we currently in the process of importing? */
88 static private boolean importing = false;
89 /** Are we currently in the process of scheduling? */
90 static private boolean scheduling = false;
91 /** The objects listening for CollectionContentsChanged events. */
92 static private ArrayList collection_contents_changed_listeners = new ArrayList();
93 /** The collection this manager is managing! */
94 static private Collection collection = null;
95 /** The collection tree (used in both Gather and Enrich panes). */
96 static private CollectionTree collection_tree = null;
97 /** The collection tree model. */
98 static private CollectionTreeModel collection_tree_model = null;
99 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
100 static private FMTreeModelListener fm_tree_model_listener = null;
101 /** The monitor responsible for parsing the build process. */
102 static private GShellProgressMonitor build_monitor = null;
103 /** The monitor responsible for parsing the import process. */
104 static private GShellProgressMonitor import_monitor = null;
105 /** The monitor responsible for parsing the scheduler process. */
106 static private GShellProgressMonitor schedule_monitor = null;
107
108 /** The name of the standard lock file. */
109 static final public String LOCK_FILE = "gli.lck";
110
111 /** Used to indicate the source of the message is the file collection methods. */
112 static final public int COLLECT = 3;
113 /** Used to indicate the source of the message is the building methods. */
114 static final public int BUILDING = 5;
115 /** Used to indicate the source of the message is in the scheduling methods...? */
116 static final public int SCHEDULING = 7;
117
118
119 /** Constructor. */
120 public CollectionManager() {
121 // Initialisation.
122 this.building = false;
123 this.importing = false;
124 this.scheduling = false;
125 this.collection = null;
126
127 MetadataXMLFileManager.addMetadataChangedListener(this);
128
129 // If using a remote Greenstone server, delete the local collect directory because it will be out of date
130 if (Gatherer.isGsdlRemote) {
131 System.err.println("Deleting user's local collect directory...");
132 Utility.delete(new File(Gatherer.getCollectDirectoryPath()));
133 System.err.println("Done.");
134 new File(Gatherer.getCollectDirectoryPath()).mkdirs();
135 }
136 }
137
138
139 static public void addCollectionContentsChangedListener(CollectionContentsChangedListener listener)
140 {
141 collection_contents_changed_listeners.add(listener);
142 }
143
144
145 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
146 * @see org.greenstone.gatherer.Configuration
147 * @see org.greenstone.gatherer.Gatherer
148 * @see org.greenstone.gatherer.collection.Collection
149 * @see org.greenstone.gatherer.gui.BuildOptions
150 * @see org.greenstone.gatherer.shell.GShell
151 * @see org.greenstone.gatherer.shell.GShellListener
152 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
153 * @see org.greenstone.gatherer.util.Utility
154 */
155 public void buildCollection(boolean incremental_build)
156 {
157
158 DebugStream.println("In CollectionManager.buildCollection(), incremental_build: " + incremental_build);
159 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
160 building = true;
161
162 // Generate the buildcol.pl command
163 ArrayList command_parts_list = new ArrayList();
164 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
165 command_parts_list.add(Configuration.perl_path);
166 command_parts_list.add("-S");
167 }
168
169 if (Configuration.fedora_info.isActive()) {
170 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-buildcol.pl");
171
172 command_parts_list.add("-hostname");
173 command_parts_list.add(Configuration.fedora_info.getHostname());
174
175 command_parts_list.add("-port");
176 command_parts_list.add(Configuration.fedora_info.getPort());
177
178 command_parts_list.add("-username");
179 command_parts_list.add(Configuration.fedora_info.getUsername());
180
181 command_parts_list.add("-password");
182 command_parts_list.add(Configuration.fedora_info.getPassword());
183
184 command_parts_list.add("-protocol");
185 command_parts_list.add(Configuration.fedora_info.getProtocol());
186
187 }
188 else {
189 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "buildcol.pl");
190 }
191 command_parts_list.add("-gli");
192 command_parts_list.add("-language");
193 command_parts_list.add(Configuration.getLanguage());
194 command_parts_list.add("-collectdir");
195 command_parts_list.add(getCollectDirectory());
196
197 // If the user hasn't manually specified "-keepold" or "-removeold" then pick one based on incremental_build
198 if (!collection.build_options.getValueEnabled("keepold") && !collection.build_options.getValueEnabled("removeold")) {
199 command_parts_list.add(incremental_build ? "-keepold" : "-removeold");
200 }
201
202 String[] build_options = collection.build_options.getValues();
203 for (int i = 0; i < build_options.length; i++) {
204 command_parts_list.add(build_options[i]);
205 }
206
207 command_parts_list.add(collection.getName());
208
209 // Run the buildcol.pl command
210 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
211 GShell shell = new GShell(command_parts, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
212 shell.addGShellListener(Gatherer.g_man.create_pane);
213 shell.addGShellListener(Gatherer.g_man.format_pane);
214 shell.start();
215
216 }
217
218 /*probably repeating alot of work, but I want to keep this separate... wendy*/
219 public void scheduleBuild(boolean incremental_build)
220 {
221
222 DebugStream.println("In CollectionManager.scheduleBuild(), incremental_build: " + incremental_build);
223 DebugStream.println("Is event dispatch threa: " + SwingUtilities.isEventDispatchThread());
224
225 ArrayList sched_list = new ArrayList();
226 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
227 sched_list.add(Configuration.perl_path);
228 sched_list.add("-S");
229 }
230 sched_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "schedule.pl");
231 sched_list.add("-colname");
232 sched_list.add(collection.getName());
233 sched_list.add("-gli");
234
235 // First, generate the import.pl command, also converting to a string
236 // Generate the import.pl command
237 ArrayList import_list = new ArrayList();
238 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
239 import_list.add(Configuration.perl_path);
240 import_list.add("-S");
241 }
242 import_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
243 import_list.add("-language");
244 import_list.add(Configuration.getLanguage());
245 import_list.add("-collectdir");
246 import_list.add(getCollectDirectory());
247
248 String[] import_options = collection.import_options.getValues();
249 int i = 0;
250 for (i = 0; i < import_options.length; i++) {
251 import_list.add(import_options[i]);
252 }
253
254 import_list.add(collection.getName());
255
256 String[] import_parts = (String[]) import_list.toArray(new String[0]);
257 String command = "";
258 i = 0;
259 for (i = 0; i < import_parts.length-1; i++) {
260 command = command + import_parts[i] + " ";
261 }
262 command = command + import_parts[i];
263
264 sched_list.add("-import");
265 sched_list.add("\"" + command + "\"");
266
267 // Generate the buildcol.pl command, also converting to a string
268 ArrayList build_list = new ArrayList();
269
270 // i'm not doing this in schedule.pl right now - should i be?
271 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
272 build_list.add(Configuration.perl_path);
273 build_list.add("-S");
274 }
275 build_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "buildcol.pl");
276 build_list.add("-language");
277 build_list.add(Configuration.getLanguage());
278 build_list.add("-collectdir");
279 build_list.add(getCollectDirectory());
280
281 // If the user hasn't manually specified "-keepold" or "-removeold" then pick one based on incremental_build
282 if (!collection.build_options.getValueEnabled("keepold") && !collection.build_options.getValueEnabled("removeold")) {
283 build_list.add(incremental_build ? "-keepold" : "-removeold");
284 }
285
286 String[] build_options = collection.build_options.getValues();
287 for (i = 0; i < build_options.length; i++) {
288 build_list.add(build_options[i]);
289 }
290
291 build_list.add(collection.getName());
292
293 //build actual string
294 String[] build_parts = (String[]) build_list.toArray(new String[0]);
295 String command2 = "";
296 for(i = 0; i < build_parts.length-1; i++) {
297 command2 = command2 + build_parts[i] + " ";
298 }
299 command2 = command2 + build_parts[i];
300
301 sched_list.add("-build");
302 sched_list.add("\"" + command2 + "\"");
303
304 //next, the scheduling frequency goes here
305 String[] schedule_options = collection.schedule_options.getValues();
306 for(i = 0; i < schedule_options.length; i++) {
307 sched_list.add(schedule_options[i]);
308 }
309
310 //now, hope it will run. ;)
311 String[] sched_parts = (String[]) sched_list.toArray(new String[0]);
312
313 GShell shell = new GShell(sched_parts, GShell.SCHEDULE, SCHEDULING, this, schedule_monitor, GShell.GSHELL_SCHEDULE);
314 shell.addGShellListener(Gatherer.g_man.create_pane);
315 shell.addGShellListener(Gatherer.g_man.format_pane);
316 shell.start();
317 }
318
319 /** Used to determine whether the currently active collection has been built.
320 * @return A boolean indicating the built status of the collection.
321 */
322 public boolean built() {
323 if(collection != null) {
324 // Determine if the collection has been built by looking for the build.cfg (gs2)
325 // buildConfig.xml (gs3) or export.inf (fedora) file
326 String file_name = "";
327
328 if (Configuration.fedora_info.isActive()) { // FLI case
329 // Fedora build
330 //file_name = getLoadedCollectionArchivesDirectoryPath() + "import.inf";
331 file_name = getLoadedCollectionExportDirectoryPath() + "export.inf";
332 } else {
333 // GLI is running, check if it's greenstone 3 or greenstone 2
334 if (Gatherer.GS3) { // GS3 GLI
335 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CONFIG_XML;
336 }
337 else { // greenstone 2 GLI
338 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CFG;
339 }
340 }
341 File test_file = new File(file_name);
342 return test_file.exists();
343 }
344 return false;
345 }
346
347
348 /** 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 */
349 static private boolean canDelete(File file)
350 {
351 if (!file.isDirectory()) {
352 return file.canWrite();
353 }
354 File [] file_list = file.listFiles();
355 for (int i=0; i<file_list.length; i++) {
356 if (!canDelete(file_list[i])) {
357 return false;
358 }
359 }
360 return true;
361 }
362
363
364 /** Called to close the current collection and remove its lock file.
365 * @see org.greenstone.gatherer.Gatherer
366 * @see org.greenstone.gatherer.collection.Collection
367 * @see org.greenstone.gatherer.util.Utility
368 */
369 public void closeCollection() {
370 DebugStream.println("Close collection: " + collection.getName());
371
372 // Remove the lock on this file, then remove the collection.
373 File lock_file = new File(getLoadedCollectionDirectoryPath() + LOCK_FILE);
374 lock_file.delete();
375 if (lock_file.exists()) {
376 System.err.println("Warning: Lockfile was not successfully deleted.");
377 }
378
379 // Remove the lock file on the server
380 if (Gatherer.isGsdlRemote) {
381 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), lock_file);
382 }
383
384 MetadataSetManager.clearMetadataSets();
385 MetadataXMLFileManager.clearMetadataXMLFiles();
386 DocXMLFileManager.clearDocXMLFiles();
387 ProfileXMLFileManager.clearProfileXMLFile();
388
389 collection.destroy();
390 collection = null;
391 collection_tree_model = null;
392 //Configuration.setCollectionConfiguration(null);
393 Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
394 if (Gatherer.g_man != null) {
395 Gatherer.g_man.updateUI(); // !!! Necessary?
396 }
397 }
398
399//This method is no longer used in gs3 since the modification of CollectionConfiguration.java
400// public void convertToGS3Collection() {
401// // Generate the convert_coll_from_gs2.pl command
402// ArrayList command_parts_list = new ArrayList();
403// if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
404// command_parts_list.add(Configuration.perl_path);
405// command_parts_list.add("-S");
406// }
407// command_parts_list.add(Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl");
408// command_parts_list.add("-collectdir");
409// command_parts_list.add(getCollectDirectory());
410// command_parts_list.add(collection.getName());
411//
412// // Run the convert_coll_from_gs2.pl command
413// String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
414// GShell process = new GShell(command_parts, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
415// process.addGShellListener(this);
416// process.run(); // Don't bother threading this... yet
417//
418// }
419
420 /** When basing a new collection on an existing one, we need to copy
421 * over some extra directories: images and macros
422 */
423 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
424 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
425 return false;
426 }
427 DebugStream.println("Copying images and macros dirs from the base collection");
428 try {
429 // do the images dir
430 File base_coll_images = new File(base_coll_dir, "images");
431 if (base_coll_images.isDirectory()) {
432 // copy all the images over
433 File new_coll_images = new File(new_coll_dir, "images");
434 new_coll_images.mkdirs();
435
436 // copy the contents over
437 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_images, new_coll_images);
438 }
439 }
440 catch (Exception e) {
441 DebugStream.println("Couldn't copy over the images dir from the base collection: "+e.toString());
442 }
443 try {
444 // do the macros dir
445 File base_coll_macros = new File(base_coll_dir, "macros");
446 if (base_coll_macros.isDirectory()) {
447 // copy all the macros over
448 File new_coll_macros = new File(new_coll_dir, "macros");
449 new_coll_macros.mkdirs();
450
451 // copy the contents over
452 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_macros, new_coll_macros);
453 }
454 }
455 catch (Exception e) {
456 DebugStream.println("Couldn't copy over the macros dir from the base collection: "+e.toString());
457 }
458 return true;
459 }
460
461 /** Used to set the current collection to the given collection. Note that this call should -always- be proceeded by a ready call, and if the collection is ready and the saved flag is unset then the user should be prompted to save. Also note that this method creates yet another GShell to run buildcol.pl.
462 * @param description a description of the collection as a String
463 * @param email the email address of the author/maintainer as a String
464 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
465 * @param title the longer title of the collection as a String
466 * @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
467 * @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
468 */
469 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
470 {
471 // Display a modal progress popup to indicate that the collection is being loaded
472 ModalProgressPopup create_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Creating_Collection"), Dictionary.get("CollectionManager.Creating_Collection_Please_Wait"));
473 create_collection_progress_popup.display();
474
475 // Create the collection on a separate thread so the progress bar updates correctly
476 (new CreateCollectionTask(description, email, name, title, base_collection_directory, metadata_sets, create_collection_progress_popup)).start();
477 }
478
479
480 private class CreateCollectionTask
481 extends Thread
482 {
483 private String description = null;
484 private String email = null;
485 private String name = null;
486 private String title = null;
487 private File base_collection_directory = null;
488 private ArrayList metadata_sets = null;
489 private ModalProgressPopup create_collection_progress_popup = null;
490
491 public CreateCollectionTask(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets, ModalProgressPopup create_collection_progress_popup)
492 {
493 this.description = description;
494 this.email = email;
495 this.name = name;
496 this.title = title;
497 this.base_collection_directory = base_collection_directory;
498 this.metadata_sets = metadata_sets;
499 this.create_collection_progress_popup = create_collection_progress_popup;
500 }
501
502 public void run()
503 {
504 createCollectionInternal(description, email, name, title, base_collection_directory, metadata_sets);
505 create_collection_progress_popup.close();
506 }
507 }
508
509
510 private void createCollectionInternal(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
511 {
512 try {
513 // first make sure that the collect directory exists
514 File collect_dir = new File(getCollectDirectory());
515 if (!collect_dir.exists()) {
516 collect_dir.mkdirs();
517 }
518
519 // Create the new collection
520 makeCollection(name, email);
521
522 // Check that the collection has been created successfully
523 String collection_directory_path = getCollectionDirectoryPath(name);
524 if (!new File(collection_directory_path).exists()) {
525 // If there is no collection directory then the creation was unsuccessful, or cancelled
526
527 return;
528 }
529
530 // Check for the existence of the collection configuration file
531 String file_name = ((Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG);
532 File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + file_name);
533
534 if (!collect_cfg_file.exists()) {
535 System.err.println("Error: no " + file_name + " file has been created!");
536 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);
537 return;
538 }
539
540 // ACTIVE_DIR/log/
541 File log_dir = new File(collection_directory_path + "log");
542 log_dir.mkdirs();
543
544 // Make sure an import folder exists
545 File collection_import_directory = new File(collection_directory_path + "import");
546 if (!collection_import_directory.exists()) {
547 collection_import_directory.mkdirs();
548 if (Gatherer.isGsdlRemote) {
549 RemoteGreenstoneServer.newCollectionDirectory(name, collection_import_directory);
550 }
551 }
552
553 // Now create the collection object around the directory.
554 collection = new Collection(new File(collection_directory_path, name + ".col"));
555
556 // "-removeold" is on by default for import.pl
557 collection.import_options.setValue("removeold", true, null);
558
559 // for remote case, scheduling causes an Exception on creating a new collection that
560 // can't be recovered from. For GS3, it doesn't work since it it trying to access etc/main.cfg
561 if (!Gatherer.isGsdlRemote && !Gatherer.GS3) {
562 scheduling();
563 }
564
565 MetadataSetManager.clearMetadataSets();
566 MetadataXMLFileManager.clearMetadataXMLFiles();
567 DocXMLFileManager.clearDocXMLFiles();
568
569 // Import default metadata sets, if any
570 // for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
571 // importMetadataSet((MetadataSet) metadata_sets.get(i));
572 // }
573
574 ProfileXMLFileManager.loadProfileXMLFile(new File(collection_directory_path + "metadata"));
575
576 // Before creating the CollectionDesignManager check if we are basing it upon some other collection
577 if (base_collection_directory != null) {
578 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
579
580 // If we're using a remote Greenstone server, download the collection shell to get the files needed
581 if (Gatherer.isGsdlRemote) {
582 String base_collection_name = base_collection_directory.getName();
583 RemoteGreenstoneServer.downloadCollection(base_collection_name);
584 }
585
586 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
587 // copy over other needed directories
588 copyExtraBaseCollStuff(new File(collection_directory_path), base_collection_directory);
589
590 // Try to import any existing metadata sets for this collection
591 // Look in base_collection_directory/metadata and import any metadata sets found.
592 File base_metadata_directory = new File(base_collection_directory, "metadata");
593 ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
594 if (base_metadata_sets != null) {
595 for (int i = 0; i < base_metadata_sets.size(); i++) {
596 importMetadataSet((MetadataSet) base_metadata_sets.get(i));
597 }
598 }
599 else {
600 DebugStream.println("This base collection has no metadata directory.");
601 }
602
603 // Now we update our collect.cfg
604 DebugStream.println("Copy and update " + file_name + " from base collection.");
605
606 if (Gatherer.GS3 == true) {
607 updateCollectionConfigXML(new File(base_collection_directory, Utility.CONFIG_GS3_FILE),
608 new File(collection_directory_path, Utility.CONFIG_GS3_FILE));
609 } else {
610 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE),
611 new File(collection_directory_path, Utility.CONFIG_FILE),
612 description, email, title);
613 }
614 }
615
616 // Load the default metadata sets
617 addDefaultMetadataSets();
618
619 // Make sure we always have the extracted metadata set
620 addRequiredMetadataSets();
621
622 collection.cdm = new CollectionDesignManager(new File(getLoadedCollectionCfgFilePath()));
623
624 // We always set title and description here rather than calling mkcol.pl with Unicode arguments
625 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
626 collection_name_collectionmeta.setValue(title);
627 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
628 collection_extra_collectionmeta.setValue(description);
629
630 // 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. This update is done to the internal xml structure which may be saved into collect.cfg or collectionConfig.xml accordingly.
631 if (base_collection_directory != null) {
632 // Update the creator and maintainer
633 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
634 creator_collectionmeta.setValue(email);
635 creator_collectionmeta = null;
636 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
637 maintainer_collectionmeta.setValue(email);
638 maintainer_collectionmeta = null;
639
640 // All collections based on others are automatically public
641 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
642 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
643 public_collectionmeta = null;
644
645 // Finally reset the icons
646 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
647 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
648 icon_collection_collectionmeta = null;
649 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
650 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
651 icon_collection_small_collectionmeta = null;
652 }
653
654 saveCollection();
655
656 // Create a lock file
657 createLockFile(new File(collection_directory_path, LOCK_FILE));
658
659 // We're done. Let everyone know.
660 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
661 }
662 catch (Exception error) {
663 DebugStream.printStackTrace(error);
664 }
665 }
666
667 private void scheduling()
668 throws Exception
669 {
670 //try to obtain email address of collection owner if it exists...
671 String stmp = Configuration.getEmail();
672 if(stmp != null) {
673 collection.schedule_options.setValue("toaddr", false, Configuration.getEmail());
674 }
675
676 //The next few items deal with updating the SMTP server, and the to: and from: addresses
677 //from main.cfg and the collection configuration. if no changes are made, or the
678 //values are result to NULL, any existing values are kept.
679
680 //try to obtain email address of Greenstone installation webmaster for - used to indicate "sender".
681 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
682 if(!mcfg.exists()) {
683 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
684 + ".\nScheduling presently depends on GLI running from inside a GS2.");
685 return;
686 }
687 BufferedReader maincfg = new BufferedReader(new FileReader(mcfg));
688 stmp = "";
689 String fromaddr = "";
690 while((stmp = maincfg.readLine()) != null) {
691 if(stmp.startsWith("maintainer")) {
692 fromaddr = stmp.substring(10); //length of MailServer
693 fromaddr = fromaddr.trim();
694 break;
695 }
696 }
697 maincfg.close();
698 if(!fromaddr.equals("NULL") && !fromaddr.equals("null")) {
699 collection.schedule_options.setValue("fromaddr", false, fromaddr);
700 }
701
702 //try to obtain an smtp server address from main.cfg. If that fails,
703 //try mail.server if an email address exists. If that fails,
704 //maybe a message to set attribute in main.cfg?
705 //i'm pretty sure there exists functionality to do this, but
706 //i'll finish this faster if I just wrote it
707
708
709 maincfg = new BufferedReader(new FileReader(mcfg));
710 String smtptmp = "NULL";
711 while((stmp = maincfg.readLine()) != null) {
712 if(stmp.startsWith("MailServer")) {
713 smtptmp = stmp.substring(10); //length of MailServer
714 smtptmp = smtptmp.trim();
715 break;
716 }
717 }
718 maincfg.close();
719
720 //try if lookup fails
721 if(smtptmp.equals("NULL") || smtptmp.equals("null")) {
722 String email2=fromaddr;
723 if(!email2.equals("NULL") && !email2.equals("null")) {
724 int loc = email2.indexOf('@');
725 email2 = email2.substring(loc+1);
726 smtptmp = "mail."+email2;
727 }
728 }
729 if(!smtptmp.equals("NULL") && !smtptmp.equals("null")) {
730 collection.schedule_options.setValue("smtp", false, smtptmp);
731 }
732
733 }
734
735
736 private void createLockFile(File lock_file)
737 {
738 try {
739 Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
740 String user_name = System.getProperty("user.name");
741 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
742 person_element.appendChild(default_lockfile.createTextNode(user_name));
743 person_element = null;
744 user_name = null;
745 String machine_name = Utility.getMachineName();
746 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
747 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
748 machine_element = null;
749 machine_name = null;
750 String date_time = Utility.getDateString();
751 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
752 date_element.appendChild(default_lockfile.createTextNode(date_time));
753 date_element = null;
754 date_time = null;
755 XMLTools.writeXMLFile(lock_file, default_lockfile);
756 }
757 catch (Exception exception) {
758 DebugStream.printStackTrace(exception);
759 }
760 }
761
762
763 public boolean deleteCollection(String collection_name)
764 {
765 // First we must release the collection from the local library, if it's running
766 if (LocalLibraryServer.isRunning() == true) {
767 LocalLibraryServer.releaseCollection(collection_name);
768 }
769
770 // Delete the collection on the server if we're using a remote Greenstone
771 if (Gatherer.isGsdlRemote) {
772 RemoteGreenstoneServer.deleteCollection(collection_name);
773 }
774
775 // Now delete the collection directory
776 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
777 }
778
779
780 public void fireFileAddedToCollection(File file)
781 {
782 // Send the event off to all the CollectionContentsChangedListeners
783 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
784 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
785 }
786 }
787
788
789 /** Retrieve the current collection.
790 * @return The <strong>Collection</strong> itself.
791 */
792 public Collection getCollection() {
793 return collection;
794 }
795
796
797 /** Returns the absolute filename of the specified collection's directory.
798 */
799 static public String getCollectionDirectoryPath(String collection_name)
800 {
801 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
802 }
803
804
805 /** Returns the absolute filename of the loaded collection's archives directory.
806 */
807 static public String getLoadedCollectionArchivesDirectoryPath()
808 {
809 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
810 }
811
812 /** Returns the absolute filename of the loaded collection's export directory.
813 */
814 static public String getLoadedCollectionExportDirectoryPath()
815 {
816 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
817 }
818
819
820
821 /** Returns the absolute filename of the loaded collection's building directory.
822 */
823 static public String getLoadedCollectionBuildingDirectoryPath()
824 {
825 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
826 }
827
828
829 /** Returns the absolute filename of the loaded collection's collect.cfg file.
830 */
831 static public String getLoadedCollectionCfgFilePath()
832 {
833 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
834 return getLoadedCollectionEtcDirectoryPath() + path;
835 }
836
837
838 /** Returns the absolute filename of the loaded collection's directory.
839 */
840 static public String getLoadedCollectionDirectoryPath()
841 {
842 return Gatherer.getCollectDirectoryPath() + collection.getName() + File.separator;
843 }
844
845
846 /** Returns the absolute filename of the loaded collection's etc directory.
847 */
848 static public String getLoadedCollectionEtcDirectoryPath()
849 {
850 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
851 }
852
853
854 /** Returns the absolute filename of the loaded collection's .col file.
855 */
856 static public String getLoadedCollectionColFilePath()
857 {
858 return getLoadedCollectionDirectoryPath() + collection.getName() + ".col";
859 }
860
861
862 /** Returns the absolute filename of the loaded collection's images directory.
863 */
864 static public String getLoadedCollectionImagesDirectoryPath()
865 {
866 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
867 }
868
869
870 /** Returns the absolute filename of the loaded collection's import directory.
871 */
872 static public String getLoadedCollectionImportDirectoryPath()
873 {
874 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
875 }
876
877
878 /** Returns the absolute filename of the loaded collection's index directory.
879 */
880 static public String getLoadedCollectionIndexDirectoryPath()
881 {
882 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
883 }
884
885
886 /** Returns the absolute filename of the loaded collection's log directory.
887 */
888 static public String getLoadedCollectionLogDirectoryPath()
889 {
890 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
891 }
892
893
894 /** Returns the absolute filename of the loaded collection's macros directory.
895 */
896 static public String getLoadedCollectionMacrosDirectoryPath()
897 {
898 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
899 }
900
901
902 /** Returns the absolute filename of the loaded collection's metadata directory.
903 */
904 static public String getLoadedCollectionMetadataDirectoryPath()
905 {
906 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
907 }
908
909
910 /** Returns the name of the loaded collection.
911 */
912 static public String getLoadedCollectionName()
913 {
914 if (collection != null) {
915 return collection.getName();
916 }
917
918 return null;
919 }
920
921
922 public CollectionTree getCollectionTree()
923 {
924 if (collection_tree == null) {
925 collection_tree = new CollectionTree(collection_tree_model, true);
926 }
927
928 return collection_tree;
929 }
930
931
932 /** Retrieve the tree model associated with the current collection. */
933 public CollectionTreeModel getCollectionTreeModel()
934 {
935 if (collection_tree_model == null && collection != null) {
936 // Use the import directory to generate a new CollectionTreeModel
937 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
938 // Ensure that the manager is a change listener for the tree.
939 if (fm_tree_model_listener == null) {
940 fm_tree_model_listener = new FMTreeModelListener();
941 }
942 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
943 }
944 return collection_tree_model;
945 }
946
947
948 /** This method when called, creates a new GShell in order to run the import.pl script.
949 * @see org.greenstone.gatherer.Configuration
950 * @see org.greenstone.gatherer.Gatherer
951 * @see org.greenstone.gatherer.gui.BuildOptions
952 * @see org.greenstone.gatherer.shell.GShell
953 * @see org.greenstone.gatherer.shell.GShellListener
954 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
955 * @see org.greenstone.gatherer.util.Utility
956 */
957 public void importCollection() {
958 importing = true;
959
960 if (!saved()) {
961 DebugStream.println("CollectionManager.importCollection().forcesave");
962 import_monitor.saving();
963 saveCollection();
964 }
965
966 DebugStream.println("CollectionManager.importCollection()");
967 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
968 //check that we can remove the old index before starting import
969 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
970 if (index_dir.exists()) {
971 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
972 if (!canDelete(index_dir)) {
973 // tell the user
974 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
975 // tell the gui manager
976 // a message for the building log
977 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
978 Gatherer.g_man.create_pane.message(event);
979 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
980 Gatherer.g_man.create_pane.processComplete(event);
981 importing = false;
982 return;
983 }
984 }
985
986 // Generate the import.pl command
987 ArrayList command_parts_list = new ArrayList();
988 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
989 command_parts_list.add(Configuration.perl_path);
990 command_parts_list.add("-S");
991 }
992
993 if (Configuration.fedora_info.isActive()) {
994 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-import.pl");
995
996 command_parts_list.add("-hostname");
997 command_parts_list.add(Configuration.fedora_info.getHostname());
998
999 command_parts_list.add("-port");
1000 command_parts_list.add(Configuration.fedora_info.getPort());
1001
1002 command_parts_list.add("-username");
1003 command_parts_list.add(Configuration.fedora_info.getUsername());
1004
1005 command_parts_list.add("-password");
1006 command_parts_list.add(Configuration.fedora_info.getPassword());
1007
1008 command_parts_list.add("-protocol");
1009 command_parts_list.add(Configuration.fedora_info.getProtocol());
1010 }
1011 else {
1012 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
1013 }
1014
1015 command_parts_list.add("-gli");
1016 command_parts_list.add("-language");
1017 command_parts_list.add(Configuration.getLanguage());
1018 command_parts_list.add("-collectdir");
1019 command_parts_list.add(getCollectDirectory());
1020
1021 String[] import_options = collection.import_options.getValues();
1022 for (int i = 0; i < import_options.length; i++) {
1023 command_parts_list.add(import_options[i]);
1024 }
1025
1026 command_parts_list.add(collection.getName());
1027
1028 // Run the import.pl command
1029 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1030 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1031 shell.addGShellListener(Gatherer.g_man.create_pane);
1032 shell.addGShellListener(Gatherer.g_man.format_pane);
1033 shell.start();
1034 DebugStream.println("CollectionManager.importCollection().return");
1035
1036 importing = false;
1037 }
1038
1039
1040 public void importMetadataSet(MetadataSet external_metadata_set)
1041 {
1042 // Copy the .mds file into the collection's "metadata" folder...
1043 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1044
1045 // ...but not if it is the redundant "hidden.mds" file
1046 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1047 return;
1048 }
1049
1050 // ...and only if it doesn't already exist
1051 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1052 if (!metadata_set_file.exists()) {
1053 try {
1054 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1055
1056 // If we're using a remote Greenstone server, upload the metadata file
1057 if (Gatherer.isGsdlRemote) {
1058 RemoteGreenstoneServer.uploadCollectionFile(collection.getName(), metadata_set_file);
1059 }
1060 }
1061 catch (Exception exception) {
1062 DebugStream.printStackTrace(exception);
1063 }
1064
1065 // Load it into the MetadataSetManager
1066 MetadataSetManager.loadMetadataSet(metadata_set_file);
1067 }
1068 }
1069
1070
1071 /** 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.
1072 * @return true if the gli is currently importing
1073 */
1074 public boolean isImporting() {
1075 return importing;
1076 }
1077
1078
1079 public void loadCollection(String collection_file_path)
1080 {
1081 // Display a modal progress popup to indicate that the collection is being loaded
1082 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1083 load_collection_progress_popup.display();
1084
1085 // Load the collection on a separate thread so the progress bar updates correctly
1086 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1087 }
1088
1089
1090 private class LoadCollectionTask
1091 extends Thread
1092 {
1093 private String collection_file_path = null;
1094 private ModalProgressPopup load_collection_progress_popup = null;
1095
1096 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1097 {
1098 this.collection_file_path = collection_file_path;
1099 this.load_collection_progress_popup = load_collection_progress_popup;
1100 }
1101
1102 public void run()
1103 {
1104 loadCollectionInternal(collection_file_path);
1105 load_collection_progress_popup.close();
1106 Gatherer.setMenuBarEnabled(true);
1107 }
1108 }
1109
1110
1111 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1112 * @param location The path to the collection as a <strong>String</strong>.
1113 * @see org.greenstone.gatherer.Configuration
1114 * @see org.greenstone.gatherer.Gatherer
1115 * @see org.greenstone.gatherer.collection.Collection
1116 * @see org.greenstone.gatherer.util.Utility
1117 */
1118 private void loadCollectionInternal(String location)
1119 {
1120 DebugStream.println("Loading collection " + location + "...");
1121
1122 if (Gatherer.isGsdlRemote) {
1123 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
1124 if (RemoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1125 return;
1126 }
1127 }
1128
1129 // Check we have actually been given a .col file.
1130 if (!location.endsWith(".col")) {
1131 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1132 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1133 return;
1134 }
1135
1136 // Check that the collection configuration file is available
1137 File collection_file = new File(location);
1138
1139 // Ensure that the directory exists
1140 File collection_directory = collection_file.getParentFile();
1141
1142 if (collection_directory == null || !collection_directory.exists()) {
1143 // We can't open this
1144 System.err.println("CollectionManager.loadCollection: No collection directory.");
1145 return;
1146 }
1147
1148 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1149 File collection_config_file = new File(collection_directory, file_str);
1150 if (!collection_config_file.exists()) {
1151 System.err.println("CollectionManager.loadCollection: No config file.");
1152 collection_directory = null;
1153 collection_config_file = null;
1154 return;
1155 }
1156
1157 // Ensure that an import directory exists for this collection
1158 File collection_import_directory = new File(collection_directory, "import");
1159 if (!collection_import_directory.exists()) {
1160 collection_import_directory.mkdir();
1161 }
1162
1163 // Special case of a user trying to open an old greenstone collection.
1164 boolean non_gli_collection = false;
1165 File collection_metadata_directory = new File(collection_directory, "metadata");
1166 if (!collection_metadata_directory.exists()) {
1167 DebugStream.println("Loading non-gatherer collection...");
1168 // Show a warning message in case user wants to quit now
1169 non_gli_collection = true;
1170 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1171 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1172 legacy_dialog.dispose();
1173 collection_directory = null;
1174 collection_config_file = null;
1175 return;
1176 }
1177 legacy_dialog.dispose();
1178
1179 }
1180
1181 // Now determine if a lock already exists on this collection.
1182 String collection_name = collection_directory.getName();
1183 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1184 if (lock_file.exists()) {
1185 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1186 int choice = dialog.getChoice();
1187 dialog.dispose();
1188 dialog = null;
1189
1190 if (choice != LockFileDialog.YES_OPTION) {
1191 // user has cancelled
1192 lock_file = null;
1193 collection_directory = null;
1194 collection_config_file = null;
1195 return;
1196 }
1197
1198 lock_file.delete();
1199 }
1200
1201 try {
1202 // Create a lock file.
1203 createLockFile(lock_file);
1204 // This lock file may not have been created so check
1205 if(!lock_file.canWrite()) {
1206 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1207 System.err.println("Cannot write lock file!");
1208 String args[] = new String[2];
1209 args[0] = location;
1210 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1211 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1212 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1213 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1214 //}
1215 }
1216 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1217 args = null;
1218 return;
1219 }
1220
1221 if (!Gatherer.isGsdlRemote && !Gatherer.GS3) {
1222 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1223
1224 //First, see if "Schedule" exists in the XMl File...
1225 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1226 boolean flag = false;
1227 try {
1228 String stmp = new String();
1229
1230 while((stmp = bir.readLine()) != null) {
1231 stmp = stmp.trim();
1232 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1233 flag = true;
1234 break;
1235 }
1236 }
1237 bir.close();
1238
1239 } catch (IOException ioe) {
1240 DebugStream.printStackTrace(ioe);
1241 }
1242
1243 //modify if old .col (i.e. no Schedule exists in XML file)
1244 if(!flag) {
1245 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1246
1247
1248 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1249 bir = new BufferedReader(new FileReader(collection_file));
1250
1251 try {
1252 String stmp = new String();
1253 while((stmp = bir.readLine()) != null) {
1254 String stmp2 = stmp.trim();
1255 if(stmp2.startsWith("<!ELEMENT Argument")) {
1256 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1257 }
1258 else if(stmp2.equals("</BuildConfig>")) {
1259 bor.write(" <Schedule/>\n");
1260 }
1261
1262 bor.write(stmp + "\n");
1263
1264 }
1265 bir.close();
1266 bor.close();
1267 } catch (IOException ioe) {
1268 DebugStream.printStackTrace(ioe);
1269 }
1270
1271 //copy over tmp.col to replace
1272 try {
1273 collection_file.delete();
1274 new_collection_file.renameTo(collection_file);
1275 } catch (Exception e) {
1276 DebugStream.printStackTrace(e);
1277 }
1278 }
1279 }
1280
1281 // Open the collection file
1282 this.collection = new Collection(collection_file);
1283 if (collection.error) {
1284 collection = null;
1285 // Remove lock file
1286 if (lock_file.exists()) {
1287 lock_file.delete();
1288 }
1289 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1290 }
1291
1292 if (!Gatherer.isGsdlRemote && !Gatherer.GS3) {
1293 scheduling();
1294 }
1295
1296 MetadataSetManager.clearMetadataSets();
1297 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1298
1299 // Make sure we always have the extracted metadata set
1300 addRequiredMetadataSets();
1301
1302 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1303
1304 // If this is a non-GLI (legacy) collection, load the default metadata sets
1305 if (non_gli_collection) {
1306 addDefaultMetadataSets();
1307
1308 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1309 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1310 }
1311
1312 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1313 MetadataXMLFileManager.clearMetadataXMLFiles();
1314 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1315
1316 // Read through the doc.xml files in the archives directory
1317 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1318 DocXMLFileManager.clearDocXMLFiles();
1319 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
1320
1321 // Get a list of the collection specific classifiers and plugins
1322 Classifiers.loadClassifiersList(collection_name);
1323 Plugins.loadPluginsList(collection_name);
1324
1325 collection.cdm = new CollectionDesignManager(collection_config_file);
1326 if (non_gli_collection) {
1327 // Change the classifiers to use the namespaced element names
1328 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1329 }
1330
1331 // We're done. Let everyone know.
1332 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1333 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1334 }
1335 catch (Exception error) {
1336 // There is obviously no existing collection present.
1337 DebugStream.printStackTrace(error);
1338 error.printStackTrace();
1339 if(error.getMessage() != null) {
1340 String[] args = new String[2];
1341 args[0] = location;
1342 //args[1] = error.getMessage();
1343 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1344 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1345 }
1346 else {
1347 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1348 }
1349 }
1350
1351 lock_file = null;
1352 collection_directory = null;
1353 collection_config_file = null;
1354 }
1355
1356
1357 private void makeCollection(String name, String email)
1358 {
1359 // Generate the mkcol.pl command
1360 ArrayList command_parts_list = new ArrayList();
1361 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1362 command_parts_list.add(Configuration.perl_path);
1363 command_parts_list.add("-S");
1364 }
1365 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1366 if(Gatherer.GS3) {
1367 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1368 }
1369
1370 command_parts_list.add("-collectdir");
1371 command_parts_list.add(getCollectDirectory());
1372
1373 command_parts_list.add("-win31compat");
1374 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1375
1376 if (email != null && !email.equals("")) {
1377 command_parts_list.add("-creator");
1378 command_parts_list.add(email);
1379 }
1380
1381 command_parts_list.add(name);
1382
1383 // Run the mkcol.pl command
1384 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1385 //for(int i = 0; i < command_parts.length; i++) {
1386 ///ystem.err.println("\""+command_parts[i]+"\"");
1387 //}
1388
1389 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1390 process.run(); // Don't bother threading this... yet
1391 }
1392
1393
1394 /** 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.
1395 * @param event A <strong>GShellEvent</strong> which contains a the message.
1396 */
1397 public synchronized void message(GShellEvent event) {
1398
1399 }
1400
1401
1402 public void metadataChanged(CollectionTreeNode[] file_nodes)
1403 {
1404 if (collection != null) {
1405 collection.setMetadataChanged(true);
1406 }
1407 }
1408
1409
1410 public void openCollectionFromLastTime() {
1411 // If there was an open collection last session, reopen it
1412 if (Gatherer.open_collection_file_path != null) {
1413 // Load the collection now
1414 loadCollection(Gatherer.open_collection_file_path);
1415 }
1416
1417 }
1418
1419
1420 /** This call is fired whenever a process within a GShell created by this class begins.
1421 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1422 * @see org.greenstone.gatherer.Gatherer
1423 * @see org.greenstone.gatherer.gui.GUIManager
1424 * @see org.greenstone.gatherer.shell.GShell
1425 */
1426 public synchronized void processBegun(GShellEvent event) {
1427 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1428 ///ystem.err.println("ProcessBegun " + event.getType());
1429 // If this is one of the types where we wish to lock user control
1430 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1431 }
1432 /** This call is fired whenever a process within a GShell created by this class ends.
1433 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1434 * @see org.greenstone.gatherer.Gatherer
1435 * @see org.greenstone.gatherer.gui.GUIManager
1436 * @see org.greenstone.gatherer.shell.GShell
1437 */
1438 public synchronized void processComplete(GShellEvent event) {
1439 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1440 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1441 ///ystem.err.println("Recieved process complete event - " + event);
1442 // If we were running an import, now run a build.
1443 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1444 // Finish import.
1445 collection.setImported(true);
1446 collection.setFilesChanged(false);
1447 collection.setMetadataChanged(false);
1448 buildCollection(false);
1449 }
1450 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1451
1452 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1453 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1454 collection_built_warning_dialog.display();
1455 collection_built_warning_dialog.dispose();
1456 collection_built_warning_dialog = null;
1457 }
1458 // If we were running a build, now is when we move files across.
1459 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1460
1461 if(installCollection()) {
1462 // If we have a local library running then ask it to add our newly create collection
1463 if (LocalLibraryServer.isRunning() == true) {
1464 LocalLibraryServer.addCollection(collection.getName());
1465 }
1466 else if (Gatherer.GS3) {
1467 //xiao comment out this: convertToGS3Collection();
1468 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1469 }
1470
1471 // Fire a collection changed first to update the preview etc buttons
1472 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1473
1474 // Now display a message dialog saying its all built
1475 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1476 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1477 collection_built_warning_dialog.display();
1478 collection_built_warning_dialog.dispose();
1479 collection_built_warning_dialog = null;
1480
1481 //Set nothing as needing rebuilding, as a build has just finished :-)
1482 CollectionDesignManager.resetRebuildTypeRequired();
1483 }
1484 else {
1485 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1486 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1487 DebugStream.println("Status is ok but !installCollection()");
1488 }
1489 }
1490 else if (event.getStatus() == GShell.CANCELLED) {
1491 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1492 Gatherer.g_man.repaint();
1493 }
1494 else if (event.getStatus() == GShell.ERROR) {
1495 if (event.getType() == GShell.NEW) {
1496 String name = event.getMessage();
1497 String collectDir = getCollectionDirectoryPath(name);
1498 String errMsg = "";
1499 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1500 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1501 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1502 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1503 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1504 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1505 //}
1506 }
1507 } else {
1508 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1509 }
1510 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1511 }
1512 else if(event.getType() == GShell.SCHEDULE) {
1513 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1514 }
1515 else {
1516 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1517 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1518 }
1519
1520 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.
1521 }
1522 }
1523
1524
1525 /** Determine if the manager is ready for actions apon its collection.
1526 * @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.
1527 */
1528 static public synchronized boolean ready() {
1529 if(collection != null) {
1530 return true;
1531 }
1532 else {
1533 return false;
1534 }
1535 }
1536
1537
1538 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1539 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1540 */
1541 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1542 build_monitor = monitor;
1543 }
1544 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1545 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1546 */
1547 public void registerImportMonitor(GShellProgressMonitor monitor) {
1548 import_monitor = monitor;
1549 }
1550
1551 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1552 schedule_monitor = monitor;
1553 }
1554
1555
1556 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1557 {
1558 collection_contents_changed_listeners.remove(listener);
1559 }
1560
1561
1562 public void removeMetadataSet(MetadataSet metadata_set)
1563 {
1564 DebugStream.println("Removing metadata set...");
1565
1566 // Delete the .mds file from the collection's "metadata" folder...
1567 File metadata_set_file = metadata_set.getMetadataSetFile();
1568
1569 // ...but not if it is the "ex.mds" file
1570 if (metadata_set_file.getName().equals("ex.mds")) {
1571 return;
1572 }
1573
1574 // ...and only if it exists
1575 if (metadata_set_file.exists()) {
1576 metadata_set_file.delete();
1577
1578 // Unload it from the MetadataSetManager
1579 MetadataSetManager.unloadMetadataSet(metadata_set);
1580
1581 // If we're using a remote Greenstone server, delete the metadata file on the server
1582 if (Gatherer.isGsdlRemote) {
1583 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), metadata_set_file);
1584 }
1585 }
1586 }
1587
1588
1589 /** Used to check whether all open collections have a 'saved' state.
1590 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1591 * @see org.greenstone.gatherer.collection.Collection
1592 */
1593 public boolean saved() {
1594 boolean result = true;
1595 if(collection != null) {
1596 result = collection.getSaved();
1597 }
1598 return result;
1599 }
1600
1601
1602 /** Saves the currently loaded collection. */
1603 public void saveCollection()
1604 {
1605
1606 if (collection == null) return;
1607
1608 DebugStream.println("Saving collection " + collection.getName() + "...");
1609
1610 // Change cursor to hourglass
1611 Gatherer.g_man.wait(true);
1612
1613 // Create a backup of the collection file, just in case anything goes wrong
1614 File collection_file = new File(getLoadedCollectionColFilePath());
1615 if (collection_file.exists()) {
1616 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1617 if (!collection_file.renameTo(collection_file_backup)) {
1618 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1619 }
1620 collection_file_backup.deleteOnExit();
1621 }
1622
1623 // Write out the collection file
1624 collection.save();
1625
1626 // Write out the collection configuration file
1627 collection.cdm.save();
1628
1629 // Change cursor back to normal
1630 Gatherer.g_man.wait(false);
1631 }
1632
1633
1634 /** 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] */
1635 private void addDefaultMetadataSets()
1636 {
1637 // Add dublin core which is the default metadata set. The user
1638 // can change this later
1639 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1640 if (dc_file.exists()) {
1641 importMetadataSet(new MetadataSet(dc_file));
1642 }
1643 }
1644
1645
1646 private void addRequiredMetadataSets()
1647 {
1648 // Always import the extracted metadata set
1649 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1650 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1651 }
1652
1653
1654 // used as arg in the perl scripts
1655 private String getCollectDirectory() {
1656 String collect_dir = Gatherer.getCollectDirectoryPath();
1657
1658 // Remove erroneous file windows file separator as it causes problems when running import.pl
1659 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1660 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1661 }
1662
1663 return collect_dir;
1664 }
1665
1666
1667 /** Install collection by moving its files from building to index after a successful build.
1668 * @see org.greenstone.gatherer.Gatherer
1669 * @see org.greenstone.gatherer.util.Utility
1670 */
1671 private boolean installCollection()
1672 {
1673 if (Configuration.fedora_info.isActive()) {
1674 DebugStream.println("Fedora build complete. No need to move files.");
1675 return true;
1676 }
1677
1678
1679 DebugStream.println("Build complete. Moving files.");
1680
1681 try {
1682 // Ensure that the local library has released this collection so we can delete the index directory
1683 if (LocalLibraryServer.isRunning() == true) {
1684 LocalLibraryServer.releaseCollection(collection.getName());
1685 }
1686 // deactivate it in tomcat so that windows will release the index files
1687 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1688 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1689 }
1690 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1691 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1692
1693 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1694 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1695
1696 // Get the build mode from the build options
1697 String build_mode = collection.build_options.getValue("mode");
1698
1699 // Special case for build mode "all": replace index dir with building dir
1700 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1701 // Remove the old index directory
1702 if (index_dir.exists()) {
1703 Utility.delete(index_dir);
1704
1705 // Wait for a couple of seconds, just for luck
1706 wait(2000);
1707
1708 // Check the delete worked
1709 if (index_dir.exists()) {
1710 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1711 }
1712 }
1713
1714 if (Gatherer.isGsdlRemote) {
1715 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), new File(getLoadedCollectionIndexDirectoryPath()));
1716 RemoteGreenstoneServer.moveCollectionFile(collection.getName(), new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1717 }
1718
1719 // Move the building directory to become the new index directory
1720 if (building_dir.renameTo(index_dir) == false) {
1721 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1722 }
1723 }
1724
1725 // Otherwise copy everything in the building dir into the index dir
1726 else {
1727 moveContentsInto(building_dir, index_dir);
1728 }
1729 }
1730 catch (Exception exception) {
1731 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1732 return false;
1733 }
1734 return true;
1735 }
1736
1737
1738 /** Moves all the files in one directory into another, overwriting existing files */
1739 private void moveContentsInto(File source_directory, File target_directory)
1740 {
1741 File[] source_files = source_directory.listFiles();
1742 for (int i = 0; i < source_files.length; i++) {
1743 File source_file = source_files[i];
1744 File target_file = new File(target_directory, source_file.getName());
1745
1746 if (source_file.isDirectory()) {
1747 moveContentsInto(source_file, target_file);
1748 source_file.delete();
1749 }
1750 else {
1751 if (target_file.exists()) {
1752 target_file.delete();
1753 }
1754
1755 source_file.renameTo(target_file);
1756 }
1757 }
1758 }
1759
1760 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1761 //In this method, the files base_cfg and new_cfg are all xml files.
1762
1763 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1764 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1765 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1766 Element collection_config = new_cfg_doc.getDocumentElement();
1767
1768 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1769 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1770 int num_nodes = classifier_children.getLength();
1771
1772 if (num_nodes < 1) {
1773 return;
1774 }
1775
1776 // Read in the classifier command watching for hfile, metadata and sort arguments.
1777 String buttonname = null;
1778 String hfile = null;
1779 String metadata = null;
1780 String sort = null;
1781
1782 for (int i=0; i<num_nodes; i++) {
1783 Element classifier_element = (Element)classifier_children.item(i);
1784 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1785 for (int j=0; j<option_children.getLength(); j++) {
1786 Element option_element = (Element)option_children.item(j);
1787 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1788 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1789
1790 if (name_str == null || name_str.equals("")) {
1791 continue;
1792 }
1793 if (name_str != null && value_str == null ) {
1794 value_str = "";
1795 }
1796 if (name_str.equals("hfile")) {
1797 hfile = value_str;
1798 }
1799 else if (name_str.equals("metadata") && value_str != null) {
1800 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1801 if (replacement != null && !replacement.equals("")) {
1802 metadata = replacement;
1803 }
1804 }
1805 else if (name_str.equals("sort") && value_str != null) {
1806 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1807 if (replacement != null && !replacement.equals("")) {
1808 sort = replacement;
1809 }
1810 }
1811 else if(name_str.equals("buttonname") && value_str != null) {
1812 buttonname = value_str;
1813 }
1814 }
1815 }
1816 for (int i=0; i<num_nodes; i++) {
1817 Element classifier_element = (Element)classifier_children.item(i);
1818 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1819 for (int j=0; j<option_children.getLength(); j++) {
1820 Element option_element = (Element)option_children.item(j);
1821 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1822
1823 if (name_str.equals("metadata") && metadata != null) {
1824 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1825 }
1826 else if (name_str.equals("hfile") && hfile != null) {
1827 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1828 }
1829 else if (name_str.equals("sort") && sort != null) {
1830 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1831 }
1832 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1833 // No buttonname has been specified. Lets create one using the metadata as its value
1834 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1835 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1836 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1837 classifier_element.appendChild(option);
1838 }
1839 }
1840 }
1841 }
1842
1843 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1844 {
1845 boolean first_name = true;
1846 boolean first_extra = true;
1847
1848 // 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.
1849 try {
1850 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1851 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1852 String command = null;
1853 while((command = in.readLine()) != null) {
1854 if (command.length()==0) {
1855 // output a new line
1856 out.newLine();
1857 continue;
1858 }
1859 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1860 while(command.trim().endsWith("\\")) {
1861 command = command.substring(0, command.lastIndexOf("\\"));
1862 String next_line = in.readLine();
1863 if(next_line != null) {
1864 command = command + next_line;
1865 }
1866 }
1867 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1868 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1869 String command_type_str = tokenizer.nextToken().toLowerCase();
1870
1871 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1872 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1873 StringBuffer new_command = new StringBuffer(command_type_str);
1874 String meta_name = tokenizer.nextToken();
1875 new_command.append(' ');
1876 new_command.append(meta_name);
1877 while (tokenizer.hasMoreTokens()) {
1878 new_command.append(' ');
1879 new_command.append(tokenizer.nextToken());
1880 }
1881 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)) {
1882 // dont save
1883 } else {
1884 write(out, new_command.toString());
1885 }
1886 new_command = null;
1887 continue;
1888 } // if collectionmeta
1889
1890 if (command_type_str.equals("classify")) {
1891 StringBuffer text = new StringBuffer(command_type_str);
1892 // Read in the classifier command watching for hfile, metadata and sort arguments.
1893 String buttonname = null;
1894 String hfile = null;
1895 String new_metadata = null;
1896 String old_metadata = null;
1897
1898 while(tokenizer.hasMoreTokens()) {
1899 String token = tokenizer.nextToken();
1900 if (token.equals("-hfile")) {
1901 if(tokenizer.hasMoreTokens()) {
1902 text.append(" ");
1903 text.append(token);
1904 token = tokenizer.nextToken();
1905 hfile = token;
1906 }
1907 }
1908 else if (token.equals("-metadata")) {
1909 if(tokenizer.hasMoreTokens()) {
1910 text.append(" ");
1911 text.append(token);
1912 String temp_metadata = tokenizer.nextToken();
1913 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1914 if (replacement != null && !replacement.equals("")) {
1915 token = replacement;
1916 old_metadata = temp_metadata;
1917 new_metadata = replacement;
1918 }
1919 else {
1920 token = temp_metadata;
1921 }
1922 temp_metadata = null;
1923 replacement = null;
1924 }
1925 }
1926 else if (token.equals("-sort")) {
1927 if(tokenizer.hasMoreTokens()) {
1928 text.append(" ");
1929 text.append(token);
1930 String temp_metadata = tokenizer.nextToken();
1931 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1932 if (replacement != null && !replacement.equals("")) {
1933 token = replacement;
1934 }
1935 else {
1936 token = temp_metadata;
1937 }
1938 temp_metadata = null;
1939 replacement = null;
1940 }
1941 }
1942 else if(token.equals("-buttonname")) {
1943 buttonname = token;
1944 }
1945 text.append(' ');
1946 text.append(token);
1947 token = null;
1948 }
1949
1950 // 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)!
1951 if(old_metadata != null && new_metadata != null && buttonname == null) {
1952 text.append(' ');
1953 text.append("-buttonname");
1954 text.append(' ');
1955 text.append(old_metadata);
1956 }
1957 command = text.toString();
1958 // Replace the hfile if we found it
1959 if(hfile != null && new_metadata != null) {
1960 command = command.replaceAll(hfile, new_metadata + ".txt");
1961 }
1962
1963 buttonname = null;
1964 hfile = null;
1965 new_metadata = null;
1966 old_metadata = null;
1967 write(out, command);
1968 } else {
1969 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
1970 StringBuffer new_command = new StringBuffer(command_type_str);
1971 while (tokenizer.hasMoreTokens()) {
1972 new_command.append(' ');
1973 new_command.append(tokenizer.nextToken());
1974 }
1975
1976 command = new_command.toString();
1977
1978 // 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.
1979 // we really want to build up the whole command here
1980 boolean format_command = command_type_str.equals("format");
1981 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
1982 if (metadata_mapping != null) {
1983 Iterator keys = metadata_mapping.keySet().iterator();
1984 while (keys.hasNext()) {
1985 String target = (String) keys.next();
1986 String replacement = (String) metadata_mapping.get(target);
1987 if (replacement != null && !replacement.equals("")) {
1988 if (format_command) {
1989 target = "\\[" + target + "\\]";
1990 replacement = "{Or}{[" + replacement + "]," + target + "}";
1991 }
1992 command = command.replaceAll(target, replacement);
1993 }
1994 }
1995 }
1996
1997 write(out, command);
1998 }
1999 tokenizer = null;
2000 }
2001 in.close();
2002 in = null;
2003 out.flush();
2004 out.close();
2005 out = null;
2006 }
2007 catch(Exception error) {
2008 DebugStream.printStackTrace(error);
2009 }
2010 // All done, I hope.
2011 }
2012
2013 private void write(BufferedWriter out, String message)
2014 throws Exception {
2015 out.write(message, 0, message.length());
2016 out.newLine();
2017 }
2018
2019
2020 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2021 private class FMTreeModelListener
2022 implements TreeModelListener {
2023 /** 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.
2024 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2025 */
2026 public void treeNodesChanged(TreeModelEvent event) {
2027 if(collection != null) {
2028 collection.setSaved(false);
2029 collection.setFilesChanged(true);
2030 }
2031 }
2032 /** 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.
2033 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2034 */
2035 public void treeNodesInserted(TreeModelEvent event) {
2036 if(collection != null) {
2037 collection.setSaved(false);
2038 collection.setFilesChanged(true);
2039 }
2040 }
2041 /** 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.
2042 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2043 */
2044 public void treeNodesRemoved(TreeModelEvent event) {
2045 if(collection != null) {
2046 collection.setSaved(false);
2047 collection.setFilesChanged(true);
2048
2049 }
2050 }
2051 /** 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.
2052 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2053 */
2054 public void treeStructureChanged(TreeModelEvent event) {
2055 if(collection != null) {
2056 collection.setSaved(false);
2057 }
2058 }
2059 }
2060}
Note: See TracBrowser for help on using the repository browser.