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

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

Making canDoScheduling() a static public method

  • Property svn:keywords set to Author Date Id Revision
File size: 80.8 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.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 (canDoScheduling()) {
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 BufferedReader maincfg = new BufferedReader(new FileReader(mcfg));
683 stmp = "";
684 String fromaddr = "";
685 while((stmp = maincfg.readLine()) != null) {
686 if(stmp.startsWith("maintainer")) {
687 fromaddr = stmp.substring(10); //length of MailServer
688 fromaddr = fromaddr.trim();
689 break;
690 }
691 }
692 maincfg.close();
693 if(!fromaddr.equals("NULL") && !fromaddr.equals("null")) {
694 collection.schedule_options.setValue("fromaddr", false, fromaddr);
695 }
696
697 //try to obtain an smtp server address from main.cfg. If that fails,
698 //try mail.server if an email address exists. If that fails,
699 //maybe a message to set attribute in main.cfg?
700 //i'm pretty sure there exists functionality to do this, but
701 //i'll finish this faster if I just wrote it
702
703
704 maincfg = new BufferedReader(new FileReader(mcfg));
705 String smtptmp = "NULL";
706 while((stmp = maincfg.readLine()) != null) {
707 if(stmp.startsWith("MailServer")) {
708 smtptmp = stmp.substring(10); //length of MailServer
709 smtptmp = smtptmp.trim();
710 break;
711 }
712 }
713 maincfg.close();
714
715 //try if lookup fails
716 if(smtptmp.equals("NULL") || smtptmp.equals("null")) {
717 String email2=fromaddr;
718 if(!email2.equals("NULL") && !email2.equals("null")) {
719 int loc = email2.indexOf('@');
720 email2 = email2.substring(loc+1);
721 smtptmp = "mail."+email2;
722 }
723 }
724 if(!smtptmp.equals("NULL") && !smtptmp.equals("null")) {
725 collection.schedule_options.setValue("smtp", false, smtptmp);
726 }
727
728 }
729
730
731 private void createLockFile(File lock_file)
732 {
733 try {
734 Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
735 String user_name = System.getProperty("user.name");
736 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
737 person_element.appendChild(default_lockfile.createTextNode(user_name));
738 person_element = null;
739 user_name = null;
740 String machine_name = Utility.getMachineName();
741 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
742 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
743 machine_element = null;
744 machine_name = null;
745 String date_time = Utility.getDateString();
746 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
747 date_element.appendChild(default_lockfile.createTextNode(date_time));
748 date_element = null;
749 date_time = null;
750 XMLTools.writeXMLFile(lock_file, default_lockfile);
751 }
752 catch (Exception exception) {
753 DebugStream.printStackTrace(exception);
754 }
755 }
756
757
758 public boolean deleteCollection(String collection_name)
759 {
760 // First we must release the collection from the local library, if it's running
761 if (LocalLibraryServer.isRunning() == true) {
762 LocalLibraryServer.releaseCollection(collection_name);
763 }
764
765 // Delete the collection on the server if we're using a remote Greenstone
766 if (Gatherer.isGsdlRemote) {
767 RemoteGreenstoneServer.deleteCollection(collection_name);
768 }
769
770 // Now delete the collection directory
771 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
772 }
773
774
775 public void fireFileAddedToCollection(File file)
776 {
777 // Send the event off to all the CollectionContentsChangedListeners
778 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
779 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
780 }
781 }
782
783
784 /** Retrieve the current collection.
785 * @return The <strong>Collection</strong> itself.
786 */
787 public Collection getCollection() {
788 return collection;
789 }
790
791
792 /** Returns the absolute filename of the specified collection's directory.
793 */
794 static public String getCollectionDirectoryPath(String collection_name)
795 {
796 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
797 }
798
799
800 /** Returns the absolute filename of the loaded collection's archives directory.
801 */
802 static public String getLoadedCollectionArchivesDirectoryPath()
803 {
804 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
805 }
806
807 /** Returns the absolute filename of the loaded collection's export directory.
808 */
809 static public String getLoadedCollectionExportDirectoryPath()
810 {
811 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
812 }
813
814
815
816 /** Returns the absolute filename of the loaded collection's building directory.
817 */
818 static public String getLoadedCollectionBuildingDirectoryPath()
819 {
820 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
821 }
822
823
824 /** Returns the absolute filename of the loaded collection's collect.cfg file.
825 */
826 static public String getLoadedCollectionCfgFilePath()
827 {
828 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
829 return getLoadedCollectionEtcDirectoryPath() + path;
830 }
831
832
833 /** Returns the absolute filename of the loaded collection's directory.
834 */
835 static public String getLoadedCollectionDirectoryPath()
836 {
837 return Gatherer.getCollectDirectoryPath() + collection.getName() + File.separator;
838 }
839
840
841 /** Returns the absolute filename of the loaded collection's etc directory.
842 */
843 static public String getLoadedCollectionEtcDirectoryPath()
844 {
845 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
846 }
847
848
849 /** Returns the absolute filename of the loaded collection's .col file.
850 */
851 static public String getLoadedCollectionColFilePath()
852 {
853 return getLoadedCollectionDirectoryPath() + collection.getName() + ".col";
854 }
855
856
857 /** Returns the absolute filename of the loaded collection's images directory.
858 */
859 static public String getLoadedCollectionImagesDirectoryPath()
860 {
861 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
862 }
863
864
865 /** Returns the absolute filename of the loaded collection's import directory.
866 */
867 static public String getLoadedCollectionImportDirectoryPath()
868 {
869 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
870 }
871
872
873 /** Returns the absolute filename of the loaded collection's index directory.
874 */
875 static public String getLoadedCollectionIndexDirectoryPath()
876 {
877 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
878 }
879
880
881 /** Returns the absolute filename of the loaded collection's log directory.
882 */
883 static public String getLoadedCollectionLogDirectoryPath()
884 {
885 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
886 }
887
888
889 /** Returns the absolute filename of the loaded collection's macros directory.
890 */
891 static public String getLoadedCollectionMacrosDirectoryPath()
892 {
893 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
894 }
895
896
897 /** Returns the absolute filename of the loaded collection's metadata directory.
898 */
899 static public String getLoadedCollectionMetadataDirectoryPath()
900 {
901 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
902 }
903
904
905 /** Returns the name of the loaded collection.
906 */
907 static public String getLoadedCollectionName()
908 {
909 if (collection != null) {
910 return collection.getName();
911 }
912
913 return null;
914 }
915
916
917 public CollectionTree getCollectionTree()
918 {
919 if (collection_tree == null) {
920 collection_tree = new CollectionTree(collection_tree_model, true);
921 }
922
923 return collection_tree;
924 }
925
926
927 /** Retrieve the tree model associated with the current collection. */
928 public CollectionTreeModel getCollectionTreeModel()
929 {
930 if (collection_tree_model == null && collection != null) {
931 // Use the import directory to generate a new CollectionTreeModel
932 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
933 // Ensure that the manager is a change listener for the tree.
934 if (fm_tree_model_listener == null) {
935 fm_tree_model_listener = new FMTreeModelListener();
936 }
937 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
938 }
939 return collection_tree_model;
940 }
941
942
943 /** This method when called, creates a new GShell in order to run the import.pl script.
944 * @see org.greenstone.gatherer.Configuration
945 * @see org.greenstone.gatherer.Gatherer
946 * @see org.greenstone.gatherer.gui.BuildOptions
947 * @see org.greenstone.gatherer.shell.GShell
948 * @see org.greenstone.gatherer.shell.GShellListener
949 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
950 * @see org.greenstone.gatherer.util.Utility
951 */
952 public void importCollection() {
953 importing = true;
954
955 if (!saved()) {
956 DebugStream.println("CollectionManager.importCollection().forcesave");
957 import_monitor.saving();
958 saveCollection();
959 }
960
961 DebugStream.println("CollectionManager.importCollection()");
962 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
963 //check that we can remove the old index before starting import
964 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
965 if (index_dir.exists()) {
966 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
967 if (!canDelete(index_dir)) {
968 // tell the user
969 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
970 // tell the gui manager
971 // a message for the building log
972 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
973 Gatherer.g_man.create_pane.message(event);
974 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
975 Gatherer.g_man.create_pane.processComplete(event);
976 importing = false;
977 return;
978 }
979 }
980
981 // Generate the import.pl command
982 ArrayList command_parts_list = new ArrayList();
983 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
984 command_parts_list.add(Configuration.perl_path);
985 command_parts_list.add("-S");
986 }
987
988 if (Configuration.fedora_info.isActive()) {
989 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-import.pl");
990
991 command_parts_list.add("-hostname");
992 command_parts_list.add(Configuration.fedora_info.getHostname());
993
994 command_parts_list.add("-port");
995 command_parts_list.add(Configuration.fedora_info.getPort());
996
997 command_parts_list.add("-username");
998 command_parts_list.add(Configuration.fedora_info.getUsername());
999
1000 command_parts_list.add("-password");
1001 command_parts_list.add(Configuration.fedora_info.getPassword());
1002
1003 command_parts_list.add("-protocol");
1004 command_parts_list.add(Configuration.fedora_info.getProtocol());
1005 }
1006 else {
1007 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
1008 }
1009
1010 command_parts_list.add("-gli");
1011 command_parts_list.add("-language");
1012 command_parts_list.add(Configuration.getLanguage());
1013 command_parts_list.add("-collectdir");
1014 command_parts_list.add(getCollectDirectory());
1015
1016 String[] import_options = collection.import_options.getValues();
1017 for (int i = 0; i < import_options.length; i++) {
1018 command_parts_list.add(import_options[i]);
1019 }
1020
1021 command_parts_list.add(collection.getName());
1022
1023 // Run the import.pl command
1024 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1025 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1026 shell.addGShellListener(Gatherer.g_man.create_pane);
1027 shell.addGShellListener(Gatherer.g_man.format_pane);
1028 shell.start();
1029 DebugStream.println("CollectionManager.importCollection().return");
1030
1031 importing = false;
1032 }
1033
1034
1035 public void importMetadataSet(MetadataSet external_metadata_set)
1036 {
1037 // Copy the .mds file into the collection's "metadata" folder...
1038 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1039
1040 // ...but not if it is the redundant "hidden.mds" file
1041 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1042 return;
1043 }
1044
1045 // ...and only if it doesn't already exist
1046 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1047 if (!metadata_set_file.exists()) {
1048 try {
1049 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1050
1051 // If we're using a remote Greenstone server, upload the metadata file
1052 if (Gatherer.isGsdlRemote) {
1053 RemoteGreenstoneServer.uploadCollectionFile(collection.getName(), metadata_set_file);
1054 }
1055 }
1056 catch (Exception exception) {
1057 DebugStream.printStackTrace(exception);
1058 }
1059
1060 // Load it into the MetadataSetManager
1061 MetadataSetManager.loadMetadataSet(metadata_set_file);
1062 }
1063 }
1064
1065
1066 /** 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.
1067 * @return true if the gli is currently importing
1068 */
1069 public boolean isImporting() {
1070 return importing;
1071 }
1072
1073
1074 public void loadCollection(String collection_file_path)
1075 {
1076 // Display a modal progress popup to indicate that the collection is being loaded
1077 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1078 load_collection_progress_popup.display();
1079
1080 // Load the collection on a separate thread so the progress bar updates correctly
1081 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1082 }
1083
1084
1085 private class LoadCollectionTask
1086 extends Thread
1087 {
1088 private String collection_file_path = null;
1089 private ModalProgressPopup load_collection_progress_popup = null;
1090
1091 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1092 {
1093 this.collection_file_path = collection_file_path;
1094 this.load_collection_progress_popup = load_collection_progress_popup;
1095 }
1096
1097 public void run()
1098 {
1099 loadCollectionInternal(collection_file_path);
1100 load_collection_progress_popup.close();
1101 Gatherer.setMenuBarEnabled(true);
1102 }
1103 }
1104
1105
1106 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1107 * @param location The path to the collection as a <strong>String</strong>.
1108 * @see org.greenstone.gatherer.Configuration
1109 * @see org.greenstone.gatherer.Gatherer
1110 * @see org.greenstone.gatherer.collection.Collection
1111 * @see org.greenstone.gatherer.util.Utility
1112 */
1113 private void loadCollectionInternal(String location)
1114 {
1115 DebugStream.println("Loading collection " + location + "...");
1116
1117 if (Gatherer.isGsdlRemote) {
1118 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
1119 if (RemoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1120 return;
1121 }
1122 }
1123
1124 // Check we have actually been given a .col file.
1125 if (!location.endsWith(".col")) {
1126 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1127 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1128 return;
1129 }
1130
1131 // Check that the collection configuration file is available
1132 File collection_file = new File(location);
1133
1134 // Ensure that the directory exists
1135 File collection_directory = collection_file.getParentFile();
1136
1137 if (collection_directory == null || !collection_directory.exists()) {
1138 // We can't open this
1139 System.err.println("CollectionManager.loadCollection: No collection directory.");
1140 return;
1141 }
1142
1143 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1144 File collection_config_file = new File(collection_directory, file_str);
1145 if (!collection_config_file.exists()) {
1146 System.err.println("CollectionManager.loadCollection: No config file.");
1147 collection_directory = null;
1148 collection_config_file = null;
1149 return;
1150 }
1151
1152 // Ensure that an import directory exists for this collection
1153 File collection_import_directory = new File(collection_directory, "import");
1154 if (!collection_import_directory.exists()) {
1155 collection_import_directory.mkdir();
1156 }
1157
1158 // Special case of a user trying to open an old greenstone collection.
1159 boolean non_gli_collection = false;
1160 File collection_metadata_directory = new File(collection_directory, "metadata");
1161 if (!collection_metadata_directory.exists()) {
1162 DebugStream.println("Loading non-gatherer collection...");
1163 // Show a warning message in case user wants to quit now
1164 non_gli_collection = true;
1165 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1166 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1167 legacy_dialog.dispose();
1168 collection_directory = null;
1169 collection_config_file = null;
1170 return;
1171 }
1172 legacy_dialog.dispose();
1173
1174 }
1175
1176 // Now determine if a lock already exists on this collection.
1177 String collection_name = collection_directory.getName();
1178 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1179 if (lock_file.exists()) {
1180 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1181 int choice = dialog.getChoice();
1182 dialog.dispose();
1183 dialog = null;
1184
1185 if (choice != LockFileDialog.YES_OPTION) {
1186 // user has cancelled
1187 lock_file = null;
1188 collection_directory = null;
1189 collection_config_file = null;
1190 return;
1191 }
1192
1193 lock_file.delete();
1194 }
1195
1196 try {
1197 // Create a lock file.
1198 createLockFile(lock_file);
1199 // This lock file may not have been created so check
1200 if(!lock_file.canWrite()) {
1201 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1202 System.err.println("Cannot write lock file!");
1203 String args[] = new String[2];
1204 args[0] = location;
1205 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1206 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1207 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1208 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1209 //}
1210 }
1211 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1212 args = null;
1213 return;
1214 }
1215
1216 if (canDoScheduling()) {
1217 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1218
1219 //First, see if "Schedule" exists in the XMl File...
1220 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1221 boolean flag = false;
1222 try {
1223 String stmp = new String();
1224
1225 while((stmp = bir.readLine()) != null) {
1226 stmp = stmp.trim();
1227 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1228 flag = true;
1229 break;
1230 }
1231 }
1232 bir.close();
1233
1234 } catch (IOException ioe) {
1235 DebugStream.printStackTrace(ioe);
1236 }
1237
1238 //modify if old .col (i.e. no Schedule exists in XML file)
1239 if(!flag) {
1240 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1241
1242
1243 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1244 bir = new BufferedReader(new FileReader(collection_file));
1245
1246 try {
1247 String stmp = new String();
1248 while((stmp = bir.readLine()) != null) {
1249 String stmp2 = stmp.trim();
1250 if(stmp2.startsWith("<!ELEMENT Argument")) {
1251 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1252 }
1253 else if(stmp2.equals("</BuildConfig>")) {
1254 bor.write(" <Schedule/>\n");
1255 }
1256
1257 bor.write(stmp + "\n");
1258
1259 }
1260 bir.close();
1261 bor.close();
1262 } catch (IOException ioe) {
1263 DebugStream.printStackTrace(ioe);
1264 }
1265
1266 //copy over tmp.col to replace
1267 try {
1268 collection_file.delete();
1269 new_collection_file.renameTo(collection_file);
1270 } catch (Exception e) {
1271 DebugStream.printStackTrace(e);
1272 }
1273 }
1274 }
1275
1276 // Open the collection file
1277 this.collection = new Collection(collection_file);
1278 if (collection.error) {
1279 collection = null;
1280 // Remove lock file
1281 if (lock_file.exists()) {
1282 lock_file.delete();
1283 }
1284 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1285 }
1286
1287 if (canDoScheduling()) {
1288 scheduling();
1289 }
1290
1291 MetadataSetManager.clearMetadataSets();
1292 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1293
1294 // Make sure we always have the extracted metadata set
1295 addRequiredMetadataSets();
1296
1297 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1298
1299 // If this is a non-GLI (legacy) collection, load the default metadata sets
1300 if (non_gli_collection) {
1301 addDefaultMetadataSets();
1302
1303 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1304 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1305 }
1306
1307 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1308 MetadataXMLFileManager.clearMetadataXMLFiles();
1309 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1310
1311 // Read through the doc.xml files in the archives directory
1312 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1313 DocXMLFileManager.clearDocXMLFiles();
1314 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
1315
1316 // Get a list of the collection specific classifiers and plugins
1317 Classifiers.loadClassifiersList(collection_name);
1318 Plugins.loadPluginsList(collection_name);
1319
1320 collection.cdm = new CollectionDesignManager(collection_config_file);
1321 if (non_gli_collection) {
1322 // Change the classifiers to use the namespaced element names
1323 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1324 }
1325
1326 // We're done. Let everyone know.
1327 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1328 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1329 }
1330 catch (Exception error) {
1331 // There is obviously no existing collection present.
1332 DebugStream.printStackTrace(error);
1333 error.printStackTrace();
1334 if(error.getMessage() != null) {
1335 String[] args = new String[2];
1336 args[0] = location;
1337 //args[1] = error.getMessage();
1338 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1339 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1340 }
1341 else {
1342 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1343 }
1344 }
1345
1346 lock_file = null;
1347 collection_directory = null;
1348 collection_config_file = null;
1349 }
1350
1351 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1352 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1353 * more situations. */
1354 public static boolean canDoScheduling() {
1355 if(Gatherer.isGsdlRemote) {
1356 return false;
1357 }
1358 if(Gatherer.GS3) {
1359 return false;
1360 }
1361
1362 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1363 // it assumes GLI is inside a GS2 installation
1364 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1365 if(!mcfg.exists()) {
1366 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1367 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1368 return false;
1369 }
1370
1371 return true;
1372 }
1373
1374 private void makeCollection(String name, String email)
1375 {
1376 // Generate the mkcol.pl command
1377 ArrayList command_parts_list = new ArrayList();
1378 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1379 command_parts_list.add(Configuration.perl_path);
1380 command_parts_list.add("-S");
1381 }
1382 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1383 if(Gatherer.GS3) {
1384 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1385 }
1386
1387 command_parts_list.add("-collectdir");
1388 command_parts_list.add(getCollectDirectory());
1389
1390 command_parts_list.add("-win31compat");
1391 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1392
1393 if (email != null && !email.equals("")) {
1394 command_parts_list.add("-creator");
1395 command_parts_list.add(email);
1396 }
1397
1398 command_parts_list.add(name);
1399
1400 // Run the mkcol.pl command
1401 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1402 //for(int i = 0; i < command_parts.length; i++) {
1403 ///ystem.err.println("\""+command_parts[i]+"\"");
1404 //}
1405
1406 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1407 process.run(); // Don't bother threading this... yet
1408 }
1409
1410
1411 /** 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.
1412 * @param event A <strong>GShellEvent</strong> which contains a the message.
1413 */
1414 public synchronized void message(GShellEvent event) {
1415
1416 }
1417
1418
1419 public void metadataChanged(CollectionTreeNode[] file_nodes)
1420 {
1421 if (collection != null) {
1422 collection.setMetadataChanged(true);
1423 }
1424 }
1425
1426
1427 public void openCollectionFromLastTime() {
1428 // If there was an open collection last session, reopen it
1429 if (Gatherer.open_collection_file_path != null) {
1430 // Load the collection now
1431 loadCollection(Gatherer.open_collection_file_path);
1432 }
1433
1434 }
1435
1436
1437 /** This call is fired whenever a process within a GShell created by this class begins.
1438 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1439 * @see org.greenstone.gatherer.Gatherer
1440 * @see org.greenstone.gatherer.gui.GUIManager
1441 * @see org.greenstone.gatherer.shell.GShell
1442 */
1443 public synchronized void processBegun(GShellEvent event) {
1444 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1445 ///ystem.err.println("ProcessBegun " + event.getType());
1446 // If this is one of the types where we wish to lock user control
1447 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1448 }
1449 /** This call is fired whenever a process within a GShell created by this class ends.
1450 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1451 * @see org.greenstone.gatherer.Gatherer
1452 * @see org.greenstone.gatherer.gui.GUIManager
1453 * @see org.greenstone.gatherer.shell.GShell
1454 */
1455 public synchronized void processComplete(GShellEvent event) {
1456 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1457 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1458 ///ystem.err.println("Recieved process complete event - " + event);
1459 // If we were running an import, now run a build.
1460 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1461 // Finish import.
1462 collection.setImported(true);
1463 collection.setFilesChanged(false);
1464 collection.setMetadataChanged(false);
1465 buildCollection(false);
1466 }
1467 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1468
1469 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1470 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1471 collection_built_warning_dialog.display();
1472 collection_built_warning_dialog.dispose();
1473 collection_built_warning_dialog = null;
1474 }
1475 // If we were running a build, now is when we move files across.
1476 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1477
1478 if(installCollection()) {
1479 // If we have a local library running then ask it to add our newly create collection
1480 if (LocalLibraryServer.isRunning() == true) {
1481 LocalLibraryServer.addCollection(collection.getName());
1482 }
1483 else if (Gatherer.GS3) {
1484 //xiao comment out this: convertToGS3Collection();
1485 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1486 }
1487
1488 // Fire a collection changed first to update the preview etc buttons
1489 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1490
1491 // Now display a message dialog saying its all built
1492 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1493 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1494 collection_built_warning_dialog.display();
1495 collection_built_warning_dialog.dispose();
1496 collection_built_warning_dialog = null;
1497
1498 //Set nothing as needing rebuilding, as a build has just finished :-)
1499 CollectionDesignManager.resetRebuildTypeRequired();
1500 }
1501 else {
1502 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1503 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1504 DebugStream.println("Status is ok but !installCollection()");
1505 }
1506 }
1507 else if (event.getStatus() == GShell.CANCELLED) {
1508 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1509 Gatherer.g_man.repaint();
1510 }
1511 else if (event.getStatus() == GShell.ERROR) {
1512 if (event.getType() == GShell.NEW) {
1513 String name = event.getMessage();
1514 String collectDir = getCollectionDirectoryPath(name);
1515 String errMsg = "";
1516 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1517 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1518 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1519 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1520 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1521 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1522 //}
1523 }
1524 } else {
1525 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1526 }
1527 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1528 }
1529 else if(event.getType() == GShell.SCHEDULE) {
1530 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1531 }
1532 else {
1533 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1534 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1535 }
1536
1537 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.
1538 }
1539 }
1540
1541
1542 /** Determine if the manager is ready for actions apon its collection.
1543 * @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.
1544 */
1545 static public synchronized boolean ready() {
1546 if(collection != null) {
1547 return true;
1548 }
1549 else {
1550 return false;
1551 }
1552 }
1553
1554
1555 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1556 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1557 */
1558 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1559 build_monitor = monitor;
1560 }
1561 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1562 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1563 */
1564 public void registerImportMonitor(GShellProgressMonitor monitor) {
1565 import_monitor = monitor;
1566 }
1567
1568 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1569 schedule_monitor = monitor;
1570 }
1571
1572
1573 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1574 {
1575 collection_contents_changed_listeners.remove(listener);
1576 }
1577
1578
1579 public void removeMetadataSet(MetadataSet metadata_set)
1580 {
1581 DebugStream.println("Removing metadata set...");
1582
1583 // Delete the .mds file from the collection's "metadata" folder...
1584 File metadata_set_file = metadata_set.getMetadataSetFile();
1585
1586 // ...but not if it is the "ex.mds" file
1587 if (metadata_set_file.getName().equals("ex.mds")) {
1588 return;
1589 }
1590
1591 // ...and only if it exists
1592 if (metadata_set_file.exists()) {
1593 metadata_set_file.delete();
1594
1595 // Unload it from the MetadataSetManager
1596 MetadataSetManager.unloadMetadataSet(metadata_set);
1597
1598 // If we're using a remote Greenstone server, delete the metadata file on the server
1599 if (Gatherer.isGsdlRemote) {
1600 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), metadata_set_file);
1601 }
1602 }
1603 }
1604
1605
1606 /** Used to check whether all open collections have a 'saved' state.
1607 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1608 * @see org.greenstone.gatherer.collection.Collection
1609 */
1610 public boolean saved() {
1611 boolean result = true;
1612 if(collection != null) {
1613 result = collection.getSaved();
1614 }
1615 return result;
1616 }
1617
1618
1619 /** Saves the currently loaded collection. */
1620 public void saveCollection()
1621 {
1622
1623 if (collection == null) return;
1624
1625 DebugStream.println("Saving collection " + collection.getName() + "...");
1626
1627 // Change cursor to hourglass
1628 Gatherer.g_man.wait(true);
1629
1630 // Create a backup of the collection file, just in case anything goes wrong
1631 File collection_file = new File(getLoadedCollectionColFilePath());
1632 if (collection_file.exists()) {
1633 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1634 if (!collection_file.renameTo(collection_file_backup)) {
1635 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1636 }
1637 collection_file_backup.deleteOnExit();
1638 }
1639
1640 // Write out the collection file
1641 collection.save();
1642
1643 // Write out the collection configuration file
1644 collection.cdm.save();
1645
1646 // Change cursor back to normal
1647 Gatherer.g_man.wait(false);
1648 }
1649
1650
1651 /** 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] */
1652 private void addDefaultMetadataSets()
1653 {
1654 // Add dublin core which is the default metadata set. The user
1655 // can change this later
1656 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1657 if (dc_file.exists()) {
1658 importMetadataSet(new MetadataSet(dc_file));
1659 }
1660 }
1661
1662
1663 private void addRequiredMetadataSets()
1664 {
1665 // Always import the extracted metadata set
1666 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1667 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1668 }
1669
1670
1671 // used as arg in the perl scripts
1672 private String getCollectDirectory() {
1673 String collect_dir = Gatherer.getCollectDirectoryPath();
1674
1675 // Remove erroneous file windows file separator as it causes problems when running import.pl
1676 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1677 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1678 }
1679
1680 return collect_dir;
1681 }
1682
1683
1684 /** Install collection by moving its files from building to index after a successful build.
1685 * @see org.greenstone.gatherer.Gatherer
1686 * @see org.greenstone.gatherer.util.Utility
1687 */
1688 private boolean installCollection()
1689 {
1690 if (Configuration.fedora_info.isActive()) {
1691 DebugStream.println("Fedora build complete. No need to move files.");
1692 return true;
1693 }
1694
1695
1696 DebugStream.println("Build complete. Moving files.");
1697
1698 try {
1699 // Ensure that the local library has released this collection so we can delete the index directory
1700 if (LocalLibraryServer.isRunning() == true) {
1701 LocalLibraryServer.releaseCollection(collection.getName());
1702 }
1703 // deactivate it in tomcat so that windows will release the index files
1704 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1705 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1706 }
1707 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1708 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1709
1710 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1711 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1712
1713 // Get the build mode from the build options
1714 String build_mode = collection.build_options.getValue("mode");
1715
1716 // Special case for build mode "all": replace index dir with building dir
1717 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1718 // Remove the old index directory
1719 if (index_dir.exists()) {
1720 Utility.delete(index_dir);
1721
1722 // Wait for a couple of seconds, just for luck
1723 wait(2000);
1724
1725 // Check the delete worked
1726 if (index_dir.exists()) {
1727 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1728 }
1729 }
1730
1731 if (Gatherer.isGsdlRemote) {
1732 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), new File(getLoadedCollectionIndexDirectoryPath()));
1733 RemoteGreenstoneServer.moveCollectionFile(collection.getName(), new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1734 }
1735
1736 // Move the building directory to become the new index directory
1737 if (building_dir.renameTo(index_dir) == false) {
1738 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1739 }
1740 }
1741
1742 // Otherwise copy everything in the building dir into the index dir
1743 else {
1744 moveContentsInto(building_dir, index_dir);
1745 }
1746 }
1747 catch (Exception exception) {
1748 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1749 return false;
1750 }
1751 return true;
1752 }
1753
1754
1755 /** Moves all the files in one directory into another, overwriting existing files */
1756 private void moveContentsInto(File source_directory, File target_directory)
1757 {
1758 File[] source_files = source_directory.listFiles();
1759 for (int i = 0; i < source_files.length; i++) {
1760 File source_file = source_files[i];
1761 File target_file = new File(target_directory, source_file.getName());
1762
1763 if (source_file.isDirectory()) {
1764 moveContentsInto(source_file, target_file);
1765 source_file.delete();
1766 }
1767 else {
1768 if (target_file.exists()) {
1769 target_file.delete();
1770 }
1771
1772 source_file.renameTo(target_file);
1773 }
1774 }
1775 }
1776
1777 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1778 //In this method, the files base_cfg and new_cfg are all xml files.
1779
1780 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1781 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1782 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1783 Element collection_config = new_cfg_doc.getDocumentElement();
1784
1785 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1786 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1787 int num_nodes = classifier_children.getLength();
1788
1789 if (num_nodes < 1) {
1790 return;
1791 }
1792
1793 // Read in the classifier command watching for hfile, metadata and sort arguments.
1794 String buttonname = null;
1795 String hfile = null;
1796 String metadata = null;
1797 String sort = null;
1798
1799 for (int i=0; i<num_nodes; i++) {
1800 Element classifier_element = (Element)classifier_children.item(i);
1801 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1802 for (int j=0; j<option_children.getLength(); j++) {
1803 Element option_element = (Element)option_children.item(j);
1804 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1805 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1806
1807 if (name_str == null || name_str.equals("")) {
1808 continue;
1809 }
1810 if (name_str != null && value_str == null ) {
1811 value_str = "";
1812 }
1813 if (name_str.equals("hfile")) {
1814 hfile = value_str;
1815 }
1816 else if (name_str.equals("metadata") && value_str != null) {
1817 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1818 if (replacement != null && !replacement.equals("")) {
1819 metadata = replacement;
1820 }
1821 }
1822 else if (name_str.equals("sort") && value_str != null) {
1823 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1824 if (replacement != null && !replacement.equals("")) {
1825 sort = replacement;
1826 }
1827 }
1828 else if(name_str.equals("buttonname") && value_str != null) {
1829 buttonname = value_str;
1830 }
1831 }
1832 }
1833 for (int i=0; i<num_nodes; i++) {
1834 Element classifier_element = (Element)classifier_children.item(i);
1835 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1836 for (int j=0; j<option_children.getLength(); j++) {
1837 Element option_element = (Element)option_children.item(j);
1838 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1839
1840 if (name_str.equals("metadata") && metadata != null) {
1841 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1842 }
1843 else if (name_str.equals("hfile") && hfile != null) {
1844 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1845 }
1846 else if (name_str.equals("sort") && sort != null) {
1847 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1848 }
1849 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1850 // No buttonname has been specified. Lets create one using the metadata as its value
1851 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1852 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1853 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1854 classifier_element.appendChild(option);
1855 }
1856 }
1857 }
1858 }
1859
1860 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1861 {
1862 boolean first_name = true;
1863 boolean first_extra = true;
1864
1865 // 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.
1866 try {
1867 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1868 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1869 String command = null;
1870 while((command = in.readLine()) != null) {
1871 if (command.length()==0) {
1872 // output a new line
1873 out.newLine();
1874 continue;
1875 }
1876 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1877 while(command.trim().endsWith("\\")) {
1878 command = command.substring(0, command.lastIndexOf("\\"));
1879 String next_line = in.readLine();
1880 if(next_line != null) {
1881 command = command + next_line;
1882 }
1883 }
1884 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1885 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1886 String command_type_str = tokenizer.nextToken().toLowerCase();
1887
1888 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1889 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1890 StringBuffer new_command = new StringBuffer(command_type_str);
1891 String meta_name = tokenizer.nextToken();
1892 new_command.append(' ');
1893 new_command.append(meta_name);
1894 while (tokenizer.hasMoreTokens()) {
1895 new_command.append(' ');
1896 new_command.append(tokenizer.nextToken());
1897 }
1898 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)) {
1899 // dont save
1900 } else {
1901 write(out, new_command.toString());
1902 }
1903 new_command = null;
1904 continue;
1905 } // if collectionmeta
1906
1907 if (command_type_str.equals("classify")) {
1908 StringBuffer text = new StringBuffer(command_type_str);
1909 // Read in the classifier command watching for hfile, metadata and sort arguments.
1910 String buttonname = null;
1911 String hfile = null;
1912 String new_metadata = null;
1913 String old_metadata = null;
1914
1915 while(tokenizer.hasMoreTokens()) {
1916 String token = tokenizer.nextToken();
1917 if (token.equals("-hfile")) {
1918 if(tokenizer.hasMoreTokens()) {
1919 text.append(" ");
1920 text.append(token);
1921 token = tokenizer.nextToken();
1922 hfile = token;
1923 }
1924 }
1925 else if (token.equals("-metadata")) {
1926 if(tokenizer.hasMoreTokens()) {
1927 text.append(" ");
1928 text.append(token);
1929 String temp_metadata = tokenizer.nextToken();
1930 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1931 if (replacement != null && !replacement.equals("")) {
1932 token = replacement;
1933 old_metadata = temp_metadata;
1934 new_metadata = replacement;
1935 }
1936 else {
1937 token = temp_metadata;
1938 }
1939 temp_metadata = null;
1940 replacement = null;
1941 }
1942 }
1943 else if (token.equals("-sort")) {
1944 if(tokenizer.hasMoreTokens()) {
1945 text.append(" ");
1946 text.append(token);
1947 String temp_metadata = tokenizer.nextToken();
1948 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1949 if (replacement != null && !replacement.equals("")) {
1950 token = replacement;
1951 }
1952 else {
1953 token = temp_metadata;
1954 }
1955 temp_metadata = null;
1956 replacement = null;
1957 }
1958 }
1959 else if(token.equals("-buttonname")) {
1960 buttonname = token;
1961 }
1962 text.append(' ');
1963 text.append(token);
1964 token = null;
1965 }
1966
1967 // 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)!
1968 if(old_metadata != null && new_metadata != null && buttonname == null) {
1969 text.append(' ');
1970 text.append("-buttonname");
1971 text.append(' ');
1972 text.append(old_metadata);
1973 }
1974 command = text.toString();
1975 // Replace the hfile if we found it
1976 if(hfile != null && new_metadata != null) {
1977 command = command.replaceAll(hfile, new_metadata + ".txt");
1978 }
1979
1980 buttonname = null;
1981 hfile = null;
1982 new_metadata = null;
1983 old_metadata = null;
1984 write(out, command);
1985 } else {
1986 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
1987 StringBuffer new_command = new StringBuffer(command_type_str);
1988 while (tokenizer.hasMoreTokens()) {
1989 new_command.append(' ');
1990 new_command.append(tokenizer.nextToken());
1991 }
1992
1993 command = new_command.toString();
1994
1995 // 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.
1996 // we really want to build up the whole command here
1997 boolean format_command = command_type_str.equals("format");
1998 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
1999 if (metadata_mapping != null) {
2000 Iterator keys = metadata_mapping.keySet().iterator();
2001 while (keys.hasNext()) {
2002 String target = (String) keys.next();
2003 String replacement = (String) metadata_mapping.get(target);
2004 if (replacement != null && !replacement.equals("")) {
2005 if (format_command) {
2006 target = "\\[" + target + "\\]";
2007 replacement = "{Or}{[" + replacement + "]," + target + "}";
2008 }
2009 command = command.replaceAll(target, replacement);
2010 }
2011 }
2012 }
2013
2014 write(out, command);
2015 }
2016 tokenizer = null;
2017 }
2018 in.close();
2019 in = null;
2020 out.flush();
2021 out.close();
2022 out = null;
2023 }
2024 catch(Exception error) {
2025 DebugStream.printStackTrace(error);
2026 }
2027 // All done, I hope.
2028 }
2029
2030 private void write(BufferedWriter out, String message)
2031 throws Exception {
2032 out.write(message, 0, message.length());
2033 out.newLine();
2034 }
2035
2036
2037 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2038 private class FMTreeModelListener
2039 implements TreeModelListener {
2040 /** 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.
2041 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2042 */
2043 public void treeNodesChanged(TreeModelEvent event) {
2044 if(collection != null) {
2045 collection.setSaved(false);
2046 collection.setFilesChanged(true);
2047 }
2048 }
2049 /** 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.
2050 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2051 */
2052 public void treeNodesInserted(TreeModelEvent event) {
2053 if(collection != null) {
2054 collection.setSaved(false);
2055 collection.setFilesChanged(true);
2056 }
2057 }
2058 /** 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.
2059 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2060 */
2061 public void treeNodesRemoved(TreeModelEvent event) {
2062 if(collection != null) {
2063 collection.setSaved(false);
2064 collection.setFilesChanged(true);
2065
2066 }
2067 }
2068 /** 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.
2069 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2070 */
2071 public void treeStructureChanged(TreeModelEvent event) {
2072 if(collection != null) {
2073 collection.setSaved(false);
2074 }
2075 }
2076 }
2077}
Note: See TracBrowser for help on using the repository browser.