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

Last change on this file since 19404 was 19404, checked in by oranfry, 15 years ago

incremental import and build in gli (brought over from branch)

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