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

Last change on this file since 20924 was 20924, checked in by oranfry, 14 years ago

Since we can now have a Perl installation inside Greenstone on linux as well, GLI code for Linux also launches perl with the -S flag.

  • Property svn:keywords set to Author Date Id Revision
File size: 84.2 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.cdm.CollectionDesignManager;
50import org.greenstone.gatherer.cdm.CollectionMeta;
51import org.greenstone.gatherer.cdm.CollectionMetaManager;
52import org.greenstone.gatherer.cdm.CommandTokenizer;
53import org.greenstone.gatherer.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 (!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
192 if ( !CollectionDesignManager.isCompleteBuild() && CollectionDesignManager.index_manager.isLucene() ) {
193 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "incremental-buildcol.pl");
194 CollectionDesignManager.setBuildcolWasFull(false);
195 } else {
196 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "full-buildcol.pl");
197 CollectionDesignManager.setBuildcolWasFull(true);
198 }
199 }
200
201 command_parts_list.add("-gli");
202 command_parts_list.add("-language");
203 command_parts_list.add(Configuration.getLanguage());
204 command_parts_list.add("-collectdir");
205 command_parts_list.add(getCollectDirectory());
206
207 String[] build_options = collection.build_options.getValues();
208 for (int i = 0; i < build_options.length; i++) {
209 command_parts_list.add(build_options[i]);
210 }
211
212 command_parts_list.add(collection.getName());
213
214 // Run the buildcol.pl and
215 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
216 GShell shell = new GShell(command_parts, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
217 shell.addGShellListener(Gatherer.g_man.create_pane);
218 shell.addGShellListener(Gatherer.g_man.format_pane);
219 shell.start();
220
221 }
222
223 /*probably repeating alot of work, but I want to keep this separate... wendy*/
224 public void scheduleBuild()
225 {
226 DebugStream.println("In CollectionManager.scheduleBuild(), CollectionDesignManager.isCompleteBuild(): " + CollectionDesignManager.isCompleteBuild());
227 DebugStream.println("Is event dispatch threa: " + SwingUtilities.isEventDispatchThread());
228
229 ArrayList sched_list = new ArrayList();
230 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
231 sched_list.add(Configuration.perl_path);
232 sched_list.add("-S");
233 }
234 sched_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "schedule.pl");
235 sched_list.add("-colname");
236 sched_list.add(collection.getName());
237 sched_list.add("-gli");
238
239 // First, generate the import.pl command, also converting to a string
240 // Generate the import.pl command
241 ArrayList import_list = new ArrayList();
242 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
243 import_list.add(Configuration.perl_path);
244 import_list.add("-S");
245 }
246
247 String cmdPrefix = CollectionDesignManager.isCompleteBuild() ? "full-" : "incremental-";
248 import_list.add(LocalGreenstone.getBinScriptDirectoryPath() + cmdPrefix + "import.pl");
249 import_list.add("-language");
250 import_list.add(Configuration.getLanguage());
251 import_list.add("-collectdir");
252 import_list.add(getCollectDirectory());
253
254 String[] import_options = collection.import_options.getValues();
255 int i = 0;
256 for (i = 0; i < import_options.length; i++) {
257 import_list.add(import_options[i]);
258 }
259
260 import_list.add(collection.getName());
261
262 String[] import_parts = (String[]) import_list.toArray(new String[0]);
263 String command = "";
264 i = 0;
265 for (i = 0; i < import_parts.length-1; i++) {
266 command = command + import_parts[i] + " ";
267 }
268 command = command + import_parts[i];
269
270 sched_list.add("-import");
271 sched_list.add("\"" + command + "\"");
272
273 // Generate the buildcol.pl command, also converting to a string
274 ArrayList build_list = new ArrayList();
275
276 // i'm not doing this in schedule.pl right now - should i be?
277 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
278 build_list.add(Configuration.perl_path);
279 build_list.add("-S");
280 }
281
282 String buildType = (new CollectionMeta( CollectionDesignManager.collect_config.getBuildType() )).getValue(CollectionMeta.TEXT);
283 if ( !CollectionDesignManager.isCompleteBuild() && buildType.equals( BuildTypeManager.BUILD_TYPE_LUCENE ) ) {
284 build_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "incremental-buildcol.pl");
285 } else {
286 build_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "full-buildcol.pl");
287 }
288
289 build_list.add("-language");
290 build_list.add(Configuration.getLanguage());
291 build_list.add("-collectdir");
292 build_list.add(getCollectDirectory());
293
294 String[] build_options = collection.build_options.getValues();
295 for (i = 0; i < build_options.length; i++) {
296 build_list.add(build_options[i]);
297 }
298
299 build_list.add(collection.getName());
300
301 //build actual string
302 String[] build_parts = (String[]) build_list.toArray(new String[0]);
303 String command2 = "";
304 for(i = 0; i < build_parts.length-1; i++) {
305 command2 = command2 + build_parts[i] + " ";
306 }
307 command2 = command2 + build_parts[i];
308
309 sched_list.add("-build");
310 sched_list.add("\"" + command2 + "\"");
311
312 //next, the scheduling frequency goes here
313 String[] schedule_options = collection.schedule_options.getValues();
314 for(i = 0; i < schedule_options.length; i++) {
315 sched_list.add(schedule_options[i]);
316 }
317
318 //now, hope it will run. ;)
319 String[] sched_parts = (String[]) sched_list.toArray(new String[0]);
320
321 GShell shell = new GShell(sched_parts, GShell.SCHEDULE, SCHEDULING, this, schedule_monitor, GShell.GSHELL_SCHEDULE);
322 shell.addGShellListener(Gatherer.g_man.create_pane);
323 shell.addGShellListener(Gatherer.g_man.format_pane);
324 shell.start();
325 }
326
327 /** Used to determine whether the currently active collection has been built.
328 * @return A boolean indicating the built status of the collection.
329 */
330 public boolean built() {
331 if(collection != null) {
332 // Determine if the collection has been built by looking for the build.cfg (gs2)
333 // buildConfig.xml (gs3) or export.inf (fedora) file
334 String file_name = "";
335
336 if (Configuration.fedora_info != null && Configuration.fedora_info.isActive()) { // FLI case
337 // Fedora build
338 //file_name = getLoadedCollectionArchivesDirectoryPath() + "import.inf";
339 file_name = getLoadedCollectionExportDirectoryPath() + "export.inf";
340 } else {
341 // GLI is running, check if it's greenstone 3 or greenstone 2
342 if (Gatherer.GS3) { // GS3 GLI
343 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CONFIG_XML;
344 }
345 else { // greenstone 2 GLI
346 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CFG;
347 }
348 }
349 File test_file = new File(file_name);
350 return test_file.exists();
351 }
352 return false;
353 }
354
355 /** Used to determine whether the currently active collection has been imported.
356 * @return A boolean indicating the imported status of the collection.
357 */
358 public boolean imported() {
359 if ( collection != null ) {
360 String file_name = getLoadedCollectionDirectoryPath() + "archives";
361 File test_file = new File(file_name);
362 return test_file.exists();
363 }
364 return false;
365 }
366
367 /** 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 */
368 static private boolean canDelete(File file)
369 {
370 if (!file.isDirectory()) {
371 return file.canWrite();
372 }
373 File [] file_list = file.listFiles();
374 for (int i=0; i<file_list.length; i++) {
375 if (!canDelete(file_list[i])) {
376 return false;
377 }
378 }
379 return true;
380 }
381
382
383 /** Called to close the current collection and remove its lock file.
384 * @see org.greenstone.gatherer.Gatherer
385 * @see org.greenstone.gatherer.collection.Collection
386 * @see org.greenstone.gatherer.util.Utility
387 */
388 public void closeCollection() {
389 DebugStream.println("Close collection: " + collection.getName());
390
391 // Remove the lock on this file, then remove the collection.
392 File lock_file = new File(getLoadedCollectionDirectoryPath() + LOCK_FILE);
393 lock_file.delete();
394 if (lock_file.exists()) {
395 System.err.println("Warning: Lockfile was not successfully deleted.");
396 }
397
398 // Remove the lock file on the server
399 if (Gatherer.isGsdlRemote) {
400 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getName(), lock_file);
401 }
402
403 MetadataSetManager.clearMetadataSets();
404 MetadataXMLFileManager.clearMetadataXMLFiles();
405 DocXMLFileManager.clearDocXMLFiles();
406 ProfileXMLFileManager.clearProfileXMLFile();
407
408 collection.destroy();
409 collection = null;
410 collection_tree_model = null;
411 //Configuration.setCollectionConfiguration(null);
412 Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
413 if (Gatherer.g_man != null) {
414 Gatherer.g_man.updateUI(); // !!! Necessary?
415 }
416 }
417
418//This method is no longer used in gs3 since the modification of CollectionConfiguration.java
419// public void convertToGS3Collection() {
420// // Generate the convert_coll_from_gs2.pl command
421// ArrayList command_parts_list = new ArrayList();
422// if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
423// command_parts_list.add(Configuration.perl_path);
424// command_parts_list.add("-S");
425// }
426// command_parts_list.add(Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl");
427// command_parts_list.add("-collectdir");
428// command_parts_list.add(getCollectDirectory());
429// command_parts_list.add(collection.getName());
430//
431// // Run the convert_coll_from_gs2.pl command
432// String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
433// GShell process = new GShell(command_parts, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
434// process.addGShellListener(this);
435// process.run(); // Don't bother threading this... yet
436//
437// }
438
439 /** When basing a new collection on an existing one, we need to copy
440 * over some extra directories: all except import, archives, building, index
441 * really we just want images, macros, perllib, but there may also be eg style, or other dirs.
442 */
443 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
444 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
445 return false;
446 }
447 DebugStream.println("Copying extra dirs from the base collection");
448
449
450 File subdirs[] = base_coll_dir.listFiles();
451 for (int i = 0; subdirs != null && i < subdirs.length; i++) {
452 File subdir = subdirs[i];
453 if (subdir.isDirectory()) {
454 String dir_name = subdir.getName();
455 // ignore those we don't need, (archives, buildng, index) and
456 // those we are handling in another place (import, etc, metadata)
457 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")) {
458 continue;
459 }
460 try {
461 // copy the directory
462 File new_coll_subdir = new File(new_coll_dir, dir_name);
463 new_coll_subdir.mkdirs();
464 Gatherer.f_man.getQueue().copyDirectoryContents(subdir, new_coll_subdir);
465 }
466 catch (Exception e) {
467 DebugStream.println("Couldn't copy over the" + subdir+" dir from the base collection: "+e.toString());
468 }
469 }
470 }
471
472 return true;
473 }
474
475 /** 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.
476 * @param description a description of the collection as a String
477 * @param email the email address of the author/maintainer as a String
478 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
479 * @param title the longer title of the collection as a String
480 * @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
481 * @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
482 */
483 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
484 {
485 // Display a modal progress popup to indicate that the collection is being loaded
486 ModalProgressPopup create_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Creating_Collection"), Dictionary.get("CollectionManager.Creating_Collection_Please_Wait"));
487 create_collection_progress_popup.display();
488
489 // Create the collection on a separate thread so the progress bar updates correctly
490 (new CreateCollectionTask(description, email, name, title, base_collection_directory, metadata_sets, create_collection_progress_popup)).start();
491 }
492
493
494 private class CreateCollectionTask
495 extends Thread
496 {
497 private String description = null;
498 private String email = null;
499 private String name = null;
500 private String title = null;
501 private File base_collection_directory = null;
502 private ArrayList metadata_sets = null;
503 private ModalProgressPopup create_collection_progress_popup = null;
504
505 public CreateCollectionTask(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets, ModalProgressPopup create_collection_progress_popup)
506 {
507 this.description = description;
508 this.email = email;
509 this.name = name;
510 this.title = title;
511 this.base_collection_directory = base_collection_directory;
512 this.metadata_sets = metadata_sets;
513 this.create_collection_progress_popup = create_collection_progress_popup;
514 }
515
516 public void run()
517 {
518 createCollectionInternal(description, email, name, title, base_collection_directory, metadata_sets);
519 create_collection_progress_popup.close();
520 }
521 }
522
523
524 private void createCollectionInternal(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
525 {
526 try {
527 // first make sure that the collect directory exists
528 File collect_dir = new File(getDefaultCollectDirectory());
529 if (!collect_dir.exists()) {
530 collect_dir.mkdirs();
531 }
532
533 // Create the new collection
534 makeCollection(name, email);
535
536 // Check that the collection has been created successfully
537 String collection_directory_path = getCollectionDirectoryPath(name);
538 if (!new File(collection_directory_path).exists()) {
539 // If there is no collection directory then the creation was unsuccessful, or cancelled
540
541 return;
542 }
543
544 // Check for the existence of the collection configuration file
545 String file_name = ((Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG);
546 File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + file_name);
547
548 if (!collect_cfg_file.exists()) {
549 System.err.println("Error: no " + file_name + " file has been created!");
550 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);
551 return;
552 }
553
554 // ACTIVE_DIR/log/
555 File log_dir = new File(collection_directory_path + "log");
556 log_dir.mkdirs();
557
558 // Make sure an import folder exists
559 File collection_import_directory = new File(collection_directory_path + "import");
560 if (!collection_import_directory.exists()) {
561 collection_import_directory.mkdirs();
562 if (Gatherer.isGsdlRemote) {
563 Gatherer.remoteGreenstoneServer.newCollectionDirectory(name, collection_import_directory);
564 }
565 }
566
567 // Now create the collection object around the directory.
568 collection = new Collection(new File(collection_directory_path, name + ".col"));
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 = null;
1050 if ( CollectionDesignManager.isCompleteBuild() ) {
1051 cmdPrefix = "full-";
1052 CollectionDesignManager.setImportWasFull( true );
1053 } else {
1054 cmdPrefix = "incremental-";
1055 CollectionDesignManager.setImportWasFull( false );
1056 }
1057 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + cmdPrefix + "import.pl");
1058 }
1059
1060 command_parts_list.add("-gli");
1061 command_parts_list.add("-language");
1062 command_parts_list.add(Configuration.getLanguage());
1063 command_parts_list.add("-collectdir");
1064 command_parts_list.add(getCollectDirectory());
1065
1066 String[] import_options = collection.import_options.getValues();
1067 for (int i = 0; i < import_options.length; i++) {
1068 System.err.println( "Tacking on option: " + import_options[i] );
1069 command_parts_list.add(import_options[i]);
1070 }
1071
1072 command_parts_list.add(collection.getName());
1073
1074 // Run the import.pl command
1075 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1076 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1077 //shell.setEventProperty("is_incremental", Boolean.toString(is_incremental));
1078 shell.addGShellListener(Gatherer.g_man.create_pane);
1079 shell.addGShellListener(Gatherer.g_man.format_pane);
1080 shell.start();
1081 DebugStream.println("CollectionManager.importCollection().return");
1082
1083 importing = false;
1084 }
1085
1086
1087 public void importMetadataSet(MetadataSet external_metadata_set)
1088 {
1089 // Copy the .mds file into the collection's "metadata" folder...
1090 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1091
1092 // ...but not if it is the redundant "hidden.mds" file
1093 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1094 return;
1095 }
1096
1097 // ...and only if it doesn't already exist
1098 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1099 if (!metadata_set_file.exists()) {
1100 try {
1101 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1102
1103 // If we're using a remote Greenstone server, upload the metadata file
1104 if (Gatherer.isGsdlRemote) {
1105 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection.getName(), metadata_set_file);
1106 }
1107 }
1108 catch (Exception exception) {
1109 DebugStream.printStackTrace(exception);
1110 }
1111
1112 // Load it into the MetadataSetManager
1113 MetadataSetManager.loadMetadataSet(metadata_set_file);
1114 }
1115 }
1116
1117
1118 /** 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.
1119 * @return true if the gli is currently importing
1120 */
1121 public boolean isImporting() {
1122 return importing;
1123 }
1124
1125
1126 public void loadCollection(String collection_file_path)
1127 {
1128 // Display a modal progress popup to indicate that the collection is being loaded
1129 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1130 load_collection_progress_popup.display();
1131
1132 // Load the collection on a separate thread so the progress bar updates correctly
1133 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1134 }
1135
1136
1137 private class LoadCollectionTask
1138 extends Thread
1139 {
1140 private String collection_file_path = null;
1141 private ModalProgressPopup load_collection_progress_popup = null;
1142
1143 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1144 {
1145 this.collection_file_path = collection_file_path;
1146 this.load_collection_progress_popup = load_collection_progress_popup;
1147 }
1148
1149 public void run()
1150 {
1151 loadCollectionInternal(collection_file_path);
1152 load_collection_progress_popup.close();
1153 Gatherer.setMenuBarEnabled(true);
1154 }
1155 }
1156
1157
1158 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1159 * @param location The path to the collection as a <strong>String</strong>.
1160 * @see org.greenstone.gatherer.Configuration
1161 * @see org.greenstone.gatherer.Gatherer
1162 * @see org.greenstone.gatherer.collection.Collection
1163 * @see org.greenstone.gatherer.util.Utility
1164 */
1165 private void loadCollectionInternal(String location)
1166 {
1167 DebugStream.println("Loading collection " + location + "...");
1168
1169 if (Gatherer.isGsdlRemote) {
1170 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
1171 if (Gatherer.remoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1172 return;
1173 }
1174 }
1175
1176 // Check we have actually been given a .col file.
1177 if (!location.endsWith(".col")) {
1178 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1179 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1180 return;
1181 }
1182
1183 // Check that the collection configuration file is available
1184 File collection_file = new File(location);
1185
1186 // Ensure that the directory exists
1187 File collection_directory = collection_file.getParentFile();
1188
1189 if (collection_directory == null || !collection_directory.exists()) {
1190 // We can't open this
1191 System.err.println("CollectionManager.loadCollection: No collection directory.");
1192 return;
1193 }
1194
1195 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1196 File collection_config_file = new File(collection_directory, file_str);
1197 if (!collection_config_file.exists()) {
1198 System.err.println("CollectionManager.loadCollection: No config file.");
1199 collection_directory = null;
1200 collection_config_file = null;
1201 return;
1202 }
1203
1204 // Ensure that an import directory exists for this collection
1205 File collection_import_directory = new File(collection_directory, "import");
1206 if (!collection_import_directory.exists()) {
1207 collection_import_directory.mkdir();
1208 }
1209
1210 // Special case of a user trying to open an old greenstone collection.
1211 boolean non_gli_collection = false;
1212 File collection_metadata_directory = new File(collection_directory, "metadata");
1213 if (!collection_metadata_directory.exists()) {
1214 DebugStream.println("Loading non-gatherer collection...");
1215 // Show a warning message in case user wants to quit now
1216 non_gli_collection = true;
1217 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1218 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1219 legacy_dialog.dispose();
1220 collection_directory = null;
1221 collection_config_file = null;
1222 return;
1223 }
1224 legacy_dialog.dispose();
1225
1226 }
1227
1228 // Now determine if a lock already exists on this collection.
1229 String collection_name = collection_directory.getName();
1230 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1231 if (lock_file.exists()) {
1232 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1233 int choice = dialog.getChoice();
1234 dialog.dispose();
1235 dialog = null;
1236
1237 if (choice != LockFileDialog.YES_OPTION) {
1238 // user has cancelled
1239 lock_file = null;
1240 collection_directory = null;
1241 collection_config_file = null;
1242 return;
1243 }
1244
1245 lock_file.delete();
1246 }
1247
1248 try {
1249 // Create a lock file.
1250 createLockFile(lock_file);
1251 // This lock file may not have been created so check
1252 if(!lock_file.canWrite()) {
1253 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1254 System.err.println("Cannot write lock file!");
1255 String args[] = new String[2];
1256 args[0] = location;
1257 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1258 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1259 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1260 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1261 //}
1262 }
1263 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1264 args = null;
1265 return;
1266 }
1267
1268 if (canDoScheduling()) {
1269 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1270
1271 //First, see if "Schedule" exists in the XMl File...
1272 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1273 boolean flag = false;
1274 try {
1275 String stmp = new String();
1276
1277 while((stmp = bir.readLine()) != null) {
1278 stmp = stmp.trim();
1279 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1280 flag = true;
1281 break;
1282 }
1283 }
1284 bir.close();
1285
1286 } catch (IOException ioe) {
1287 DebugStream.printStackTrace(ioe);
1288 }
1289
1290 //modify if old .col (i.e. no Schedule exists in XML file)
1291 if(!flag) {
1292 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1293
1294
1295 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1296 bir = new BufferedReader(new FileReader(collection_file));
1297
1298 try {
1299 String stmp = new String();
1300 while((stmp = bir.readLine()) != null) {
1301 String stmp2 = stmp.trim();
1302 if(stmp2.startsWith("<!ELEMENT Argument")) {
1303 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1304 }
1305 else if(stmp2.equals("</BuildConfig>")) {
1306 bor.write(" <Schedule/>\n");
1307 }
1308
1309 bor.write(stmp + "\n");
1310
1311 }
1312 bir.close();
1313 bor.close();
1314 } catch (IOException ioe) {
1315 DebugStream.printStackTrace(ioe);
1316 }
1317
1318 //copy over tmp.col to replace
1319 try {
1320 collection_file.delete();
1321 new_collection_file.renameTo(collection_file);
1322 } catch (Exception e) {
1323 DebugStream.printStackTrace(e);
1324 }
1325 }
1326 }
1327
1328 // Open the collection file
1329 this.collection = new Collection(collection_file);
1330 if (collection.error) {
1331 collection = null;
1332 // Remove lock file
1333 if (lock_file.exists()) {
1334 lock_file.delete();
1335 }
1336 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1337 }
1338
1339 if (canDoScheduling()) {
1340 scheduling();
1341 }
1342
1343 // These may have been set in the past, but are no longer used
1344 // by GLI
1345 collection.import_options.removeValue("removeold");
1346 collection.import_options.removeValue("keepold");
1347
1348 MetadataSetManager.clearMetadataSets();
1349 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1350
1351 // Make sure we always have the extracted metadata set
1352 addRequiredMetadataSets();
1353
1354 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1355
1356 // If this is a non-GLI (legacy) collection, load the default metadata sets
1357 if (non_gli_collection) {
1358 addDefaultMetadataSets();
1359
1360 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1361 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1362 }
1363
1364 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1365 MetadataXMLFileManager.clearMetadataXMLFiles();
1366 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1367
1368
1369 // get rid of the previous scan through docxml files
1370 DocXMLFileManager.clearDocXMLFiles();
1371
1372 if (Configuration.fedora_info.isActive()) { // FLI case
1373 // Read through the docmets.xml files in the export directory
1374 File collection_export_directory = new File(getLoadedCollectionExportDirectoryPath());
1375 DocXMLFileManager.loadDocXMLFiles(collection_export_directory,"docmets.xml");
1376 }
1377 else {
1378 // Read through the doc.xml files in the archives directory
1379 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1380 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory,"doc.xml");
1381 }
1382
1383
1384 // Get a list of the collection specific classifiers and plugins
1385 Classifiers.loadClassifiersList(collection_name);
1386 Plugins.loadPluginsList(collection_name);
1387
1388 collection.cdm = new CollectionDesignManager(collection_config_file);
1389 if (non_gli_collection) {
1390 // Change the classifiers to use the namespaced element names
1391 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1392 }
1393
1394 // We're done. Let everyone know.
1395 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1396 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1397 }
1398 catch (Exception error) {
1399 // There is obviously no existing collection present.
1400 DebugStream.printStackTrace(error);
1401 error.printStackTrace();
1402 if(error.getMessage() != null) {
1403 String[] args = new String[2];
1404 args[0] = location;
1405 //args[1] = error.getMessage();
1406 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1407 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1408 }
1409 else {
1410 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1411 }
1412 }
1413
1414 lock_file = null;
1415 collection_directory = null;
1416 collection_config_file = null;
1417 }
1418
1419 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1420 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1421 * more situations. */
1422 public static boolean canDoScheduling() {
1423 // Would be nice to support more of these, rather than returning false
1424 if(Gatherer.isGsdlRemote) {
1425 return false;
1426 }
1427 if(Gatherer.GS3) {
1428 return false;
1429 }
1430 if (Configuration.fedora_info.isActive()) {
1431 return false;
1432 }
1433
1434 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1435 // it assumes GLI is inside a GS2 installation
1436 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1437 if(!mcfg.exists()) {
1438 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1439 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1440 return false;
1441 }
1442
1443 return true;
1444 }
1445
1446 private void makeCollection(String name, String email)
1447 {
1448 // Generate the mkcol.pl command
1449 ArrayList command_parts_list = new ArrayList();
1450 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1451 command_parts_list.add(Configuration.perl_path);
1452 command_parts_list.add("-S");
1453 }
1454 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1455 if(Gatherer.GS3) {
1456 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1457 }
1458
1459 command_parts_list.add("-collectdir");
1460 command_parts_list.add(getDefaultCollectDirectory());
1461
1462 command_parts_list.add("-win31compat");
1463 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1464
1465 if (email != null && !email.equals("")) {
1466 command_parts_list.add("-creator");
1467 command_parts_list.add(email);
1468 }
1469
1470 command_parts_list.add(name);
1471
1472 // Run the mkcol.pl command
1473 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1474 //for(int i = 0; i < command_parts.length; i++) {
1475 ///ystem.err.println("\""+command_parts[i]+"\"");
1476 //}
1477
1478 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1479 process.run(); // Don't bother threading this... yet
1480 }
1481
1482
1483 /** 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.
1484 * @param event A <strong>GShellEvent</strong> which contains a the message.
1485 */
1486 public synchronized void message(GShellEvent event) {
1487
1488 }
1489
1490
1491 public void metadataChanged(CollectionTreeNode[] file_nodes)
1492 {
1493 if (collection != null) {
1494 collection.setMetadataChanged(true);
1495 }
1496 }
1497
1498
1499 public void openCollectionFromLastTime() {
1500 // If there was an open collection last session, reopen it
1501 if (Gatherer.open_collection_file_path != null) {
1502 // Load the collection now
1503 loadCollection(Gatherer.open_collection_file_path);
1504 }
1505
1506 }
1507
1508
1509 /** This call is fired whenever a process within a GShell created by this class begins.
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 processBegun(GShellEvent event) {
1516 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1517 ///ystem.err.println("ProcessBegun " + event.getType());
1518 // If this is one of the types where we wish to lock user control
1519 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1520 }
1521 /** This call is fired whenever a process within a GShell created by this class ends.
1522 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1523 * @see org.greenstone.gatherer.Gatherer
1524 * @see org.greenstone.gatherer.gui.GUIManager
1525 * @see org.greenstone.gatherer.shell.GShell
1526 */
1527 public synchronized void processComplete(GShellEvent event) {
1528 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1529 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1530 ///ystem.err.println("Received process complete event - " + event);
1531 // If we were running an import, now run a build.
1532 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1533 // Finish import.
1534 collection.setImported(true);
1535 collection.setFilesChanged(false);
1536 collection.setMetadataChanged(false);
1537 buildCollection();
1538 }
1539 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1540
1541 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1542 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1543 collection_built_warning_dialog.display();
1544 collection_built_warning_dialog.dispose();
1545 collection_built_warning_dialog = null;
1546 }
1547 // If we were running a build, now is when we move files across.
1548 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1549
1550 if ( CollectionDesignManager.buildcolWasFull() ) {
1551 if(installCollection()) {
1552 // If we have a local library running then ask it to add our newly create collection
1553 if (LocalLibraryServer.isRunning() == true) {
1554 LocalLibraryServer.addCollection(collection.getName());
1555 }
1556 else if (Gatherer.GS3) {
1557 //xiao comment out this: convertToGS3Collection();
1558 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1559 }
1560
1561 // Fire a collection changed first to update the preview etc buttons
1562 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1563
1564 // Now display a message dialog saying its all built
1565 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1566 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1567 collection_built_warning_dialog.display();
1568 collection_built_warning_dialog.dispose();
1569 collection_built_warning_dialog = null;
1570
1571 //Set nothing as needing rebuilding, as a build has just finished :-)
1572 CollectionDesignManager.resetRebuildTypeRequired();
1573 }
1574 else {
1575 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1576 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1577 DebugStream.println("Status is ok but !installCollection()");
1578 }
1579 }
1580 }
1581 else if (event.getStatus() == GShell.CANCELLED) {
1582 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1583 Gatherer.g_man.repaint();
1584 }
1585 else if (event.getStatus() == GShell.ERROR) {
1586 if (event.getType() == GShell.NEW) {
1587 String name = event.getMessage();
1588 String collectDir = getCollectionDirectoryPath(name);
1589 String errMsg = "";
1590 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1591 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1592 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1593 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1594 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1595 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1596 //}
1597 }
1598 } else {
1599 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1600 }
1601 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1602 }
1603 else if(event.getType() == GShell.SCHEDULE) {
1604 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1605 }
1606 else {
1607 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1608 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1609 }
1610
1611 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.
1612 }
1613 }
1614
1615
1616 /** Determine if the manager is ready for actions apon its collection.
1617 * @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.
1618 */
1619 static public synchronized boolean ready() {
1620 if(collection != null) {
1621 return true;
1622 }
1623 else {
1624 return false;
1625 }
1626 }
1627
1628
1629 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1630 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1631 */
1632 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1633 build_monitor = monitor;
1634 }
1635 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1636 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1637 */
1638 public void registerImportMonitor(GShellProgressMonitor monitor) {
1639 import_monitor = monitor;
1640 }
1641
1642 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1643 schedule_monitor = monitor;
1644 }
1645
1646
1647 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1648 {
1649 collection_contents_changed_listeners.remove(listener);
1650 }
1651
1652
1653 public void removeMetadataSet(MetadataSet metadata_set)
1654 {
1655 DebugStream.println("Removing metadata set...");
1656
1657 // Delete the .mds file from the collection's "metadata" folder...
1658 File metadata_set_file = metadata_set.getMetadataSetFile();
1659
1660 // ...but not if it is the "ex.mds" file
1661 if (metadata_set_file.getName().equals("ex.mds")) {
1662 return;
1663 }
1664
1665 // ...and only if it exists
1666 if (metadata_set_file.exists()) {
1667 metadata_set_file.delete();
1668
1669 // Unload it from the MetadataSetManager
1670 MetadataSetManager.unloadMetadataSet(metadata_set);
1671
1672 // If we're using a remote Greenstone server, delete the metadata file on the server
1673 if (Gatherer.isGsdlRemote) {
1674 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getName(), metadata_set_file);
1675 }
1676 }
1677 }
1678
1679
1680 /** Used to check whether all open collections have a 'saved' state.
1681 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1682 * @see org.greenstone.gatherer.collection.Collection
1683 */
1684 public boolean saved() {
1685 boolean result = true;
1686 if(collection != null) {
1687 result = collection.getSaved();
1688 }
1689 return result;
1690 }
1691
1692
1693 /** Saves the currently loaded collection. */
1694 public void saveCollection()
1695 {
1696
1697 if (collection == null) return;
1698
1699 DebugStream.println("Saving collection " + collection.getName() + "...");
1700
1701 // Change cursor to hourglass
1702 Gatherer.g_man.wait(true);
1703
1704 // Create a backup of the collection file, just in case anything goes wrong
1705 File collection_file = new File(getLoadedCollectionColFilePath());
1706 if (collection_file.exists()) {
1707 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1708 if (!collection_file.renameTo(collection_file_backup)) {
1709 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1710 }
1711 collection_file_backup.deleteOnExit();
1712 }
1713
1714 // Write out the collection file
1715 collection.save();
1716
1717 // Write out the collection configuration file
1718 collection.cdm.save();
1719
1720 // Change cursor back to normal
1721 Gatherer.g_man.wait(false);
1722 }
1723
1724
1725 /** 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] */
1726 private void addDefaultMetadataSets()
1727 {
1728 // Add dublin core which is the default metadata set. The user
1729 // can change this later
1730 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1731 if (dc_file.exists()) {
1732 importMetadataSet(new MetadataSet(dc_file));
1733 }
1734 }
1735
1736
1737 private void addRequiredMetadataSets()
1738 {
1739 // Always import the extracted metadata set
1740 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1741 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1742 }
1743
1744 private String getDefaultCollectDirectory() {
1745 String collect_dir = Gatherer.getCollectDirectoryPath();
1746 // Remove erroneous file windows file separator as it causes problems when running import.pl
1747 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1748 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1749 }
1750 return collect_dir;
1751 }
1752
1753 // used as arg in the perl scripts
1754 private String getCollectDirectory() {
1755
1756 String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
1757 return collect_dir;
1758 }
1759
1760
1761 /** Install collection by moving its files from building to index after a successful build.
1762 * @see org.greenstone.gatherer.Gatherer
1763 * @see org.greenstone.gatherer.util.Utility
1764 */
1765 private boolean installCollection()
1766 {
1767 if (Configuration.fedora_info.isActive()) {
1768 DebugStream.println("Fedora build complete. No need to move files.");
1769 return true;
1770 }
1771
1772
1773 DebugStream.println("Build complete. Moving files.");
1774
1775 try {
1776 // Ensure that the local library has released this collection so we can delete the index directory
1777 if (LocalLibraryServer.isRunning() == true) {
1778 LocalLibraryServer.releaseCollection(collection.getName());
1779 }
1780 // deactivate it in tomcat so that windows will release the index files
1781 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1782 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1783 }
1784 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1785 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1786
1787 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1788 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1789
1790 // Get the build mode from the build options
1791 String build_mode = collection.build_options.getValue("mode");
1792
1793 // Special case for build mode "all": replace index dir with building dir
1794 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1795 // Remove the old index directory
1796 if (index_dir.exists()) {
1797 Utility.delete(index_dir);
1798
1799 // Wait for a couple of seconds, just for luck
1800 wait(2000);
1801
1802 // Check the delete worked
1803 if (index_dir.exists()) {
1804 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1805 }
1806 }
1807
1808 if (Gatherer.isGsdlRemote) {
1809 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
1810 collection.getName(), new File(getLoadedCollectionIndexDirectoryPath()));
1811 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getName(),
1812 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1813 }
1814
1815 // Move the building directory to become the new index directory
1816 if (building_dir.renameTo(index_dir) == false) {
1817 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1818 }
1819 }
1820
1821 // Otherwise copy everything in the building dir into the index dir
1822 else {
1823 moveContentsInto(building_dir, index_dir);
1824 }
1825 }
1826 catch (Exception exception) {
1827 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1828 return false;
1829 }
1830 return true;
1831 }
1832
1833
1834 /** Moves all the files in one directory into another, overwriting existing files */
1835 private void moveContentsInto(File source_directory, File target_directory)
1836 {
1837 File[] source_files = source_directory.listFiles();
1838 for (int i = 0; i < source_files.length; i++) {
1839 File source_file = source_files[i];
1840 File target_file = new File(target_directory, source_file.getName());
1841
1842 if (source_file.isDirectory()) {
1843 moveContentsInto(source_file, target_file);
1844 source_file.delete();
1845 }
1846 else {
1847 if (target_file.exists()) {
1848 target_file.delete();
1849 }
1850
1851 source_file.renameTo(target_file);
1852 }
1853 }
1854 }
1855
1856 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1857 //In this method, the files base_cfg and new_cfg are all xml files.
1858
1859 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1860 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1861 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1862 Element collection_config = new_cfg_doc.getDocumentElement();
1863
1864 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1865 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1866 int num_nodes = classifier_children.getLength();
1867
1868 if (num_nodes < 1) {
1869 return;
1870 }
1871
1872 // Read in the classifier command watching for hfile, metadata and sort arguments.
1873 String buttonname = null;
1874 String hfile = null;
1875 String metadata = null;
1876 String sort = null;
1877
1878 for (int i=0; i<num_nodes; i++) {
1879 Element classifier_element = (Element)classifier_children.item(i);
1880 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1881 for (int j=0; j<option_children.getLength(); j++) {
1882 Element option_element = (Element)option_children.item(j);
1883 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1884 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1885
1886 if (name_str == null || name_str.equals("")) {
1887 continue;
1888 }
1889 if (name_str != null && value_str == null ) {
1890 value_str = "";
1891 }
1892 if (name_str.equals("hfile")) {
1893 hfile = value_str;
1894 }
1895 else if (name_str.equals("metadata") && value_str != null) {
1896 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1897 if (replacement != null && !replacement.equals("")) {
1898 metadata = replacement;
1899 }
1900 }
1901 else if (name_str.equals("sort") && value_str != null) {
1902 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1903 if (replacement != null && !replacement.equals("")) {
1904 sort = replacement;
1905 }
1906 }
1907 else if(name_str.equals("buttonname") && value_str != null) {
1908 buttonname = value_str;
1909 }
1910 }
1911 }
1912 for (int i=0; i<num_nodes; i++) {
1913 Element classifier_element = (Element)classifier_children.item(i);
1914 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1915 for (int j=0; j<option_children.getLength(); j++) {
1916 Element option_element = (Element)option_children.item(j);
1917 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1918
1919 if (name_str.equals("metadata") && metadata != null) {
1920 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1921 }
1922 else if (name_str.equals("hfile") && hfile != null) {
1923 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1924 }
1925 else if (name_str.equals("sort") && sort != null) {
1926 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1927 }
1928 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1929 // No buttonname has been specified. Lets create one using the metadata as its value
1930 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1931 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1932 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1933 classifier_element.appendChild(option);
1934 }
1935 }
1936 }
1937 }
1938
1939 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1940 {
1941 boolean first_name = true;
1942 boolean first_extra = true;
1943
1944 // 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.
1945 try {
1946 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1947 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1948 String command = null;
1949 while((command = in.readLine()) != null) {
1950 if (command.length()==0) {
1951 // output a new line
1952 out.newLine();
1953 continue;
1954 }
1955 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1956 while(command.trim().endsWith("\\")) {
1957 command = command.substring(0, command.lastIndexOf("\\"));
1958 String next_line = in.readLine();
1959 if(next_line != null) {
1960 command = command + next_line;
1961 }
1962 }
1963 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1964 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1965 String command_type_str = tokenizer.nextToken().toLowerCase();
1966
1967 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1968 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1969 StringBuffer new_command = new StringBuffer(command_type_str);
1970 String meta_name = tokenizer.nextToken();
1971 new_command.append(' ');
1972 new_command.append(meta_name);
1973 while (tokenizer.hasMoreTokens()) {
1974 new_command.append(' ');
1975 new_command.append(tokenizer.nextToken());
1976 }
1977 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)) {
1978 // dont save
1979 } else {
1980 write(out, new_command.toString());
1981 }
1982 new_command = null;
1983 continue;
1984 } // if collectionmeta
1985
1986 if (command_type_str.equals("classify")) {
1987 StringBuffer text = new StringBuffer(command_type_str);
1988 // Read in the classifier command watching for hfile, metadata and sort arguments.
1989 String buttonname = null;
1990 String hfile = null;
1991 String new_metadata = null;
1992 String old_metadata = null;
1993
1994 while(tokenizer.hasMoreTokens()) {
1995 String token = tokenizer.nextToken();
1996 if (token.equals("-hfile")) {
1997 if(tokenizer.hasMoreTokens()) {
1998 text.append(" ");
1999 text.append(token);
2000 token = tokenizer.nextToken();
2001 hfile = token;
2002 }
2003 }
2004 else if (token.equals("-metadata")) {
2005 if(tokenizer.hasMoreTokens()) {
2006 text.append(" ");
2007 text.append(token);
2008 String temp_metadata = tokenizer.nextToken();
2009 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2010 if (replacement != null && !replacement.equals("")) {
2011 token = replacement;
2012 old_metadata = temp_metadata;
2013 new_metadata = replacement;
2014 }
2015 else {
2016 token = temp_metadata;
2017 }
2018 temp_metadata = null;
2019 replacement = null;
2020 }
2021 }
2022 else if (token.equals("-sort")) {
2023 if(tokenizer.hasMoreTokens()) {
2024 text.append(" ");
2025 text.append(token);
2026 String temp_metadata = tokenizer.nextToken();
2027 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2028 if (replacement != null && !replacement.equals("")) {
2029 token = replacement;
2030 }
2031 else {
2032 token = temp_metadata;
2033 }
2034 temp_metadata = null;
2035 replacement = null;
2036 }
2037 }
2038 else if(token.equals("-buttonname")) {
2039 buttonname = token;
2040 }
2041 text.append(' ');
2042 text.append(token);
2043 token = null;
2044 }
2045
2046 // 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)!
2047 if(old_metadata != null && new_metadata != null && buttonname == null) {
2048 text.append(' ');
2049 text.append("-buttonname");
2050 text.append(' ');
2051 text.append(old_metadata);
2052 }
2053 command = text.toString();
2054 // Replace the hfile if we found it
2055 if(hfile != null && new_metadata != null) {
2056 command = command.replaceAll(hfile, new_metadata + ".txt");
2057 }
2058
2059 buttonname = null;
2060 hfile = null;
2061 new_metadata = null;
2062 old_metadata = null;
2063 write(out, command);
2064 } else {
2065 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2066 StringBuffer new_command = new StringBuffer(command_type_str);
2067 while (tokenizer.hasMoreTokens()) {
2068 new_command.append(' ');
2069 new_command.append(tokenizer.nextToken());
2070 }
2071
2072 command = new_command.toString();
2073
2074 // 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.
2075 // we really want to build up the whole command here
2076 boolean format_command = command_type_str.equals("format");
2077 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2078 if (metadata_mapping != null) {
2079 Iterator keys = metadata_mapping.keySet().iterator();
2080 while (keys.hasNext()) {
2081 String target = (String) keys.next();
2082 String replacement = (String) metadata_mapping.get(target);
2083 if (replacement != null && !replacement.equals("")) {
2084 if (format_command) {
2085 target = "\\[" + target + "\\]";
2086 replacement = "{Or}{[" + replacement + "]," + target + "}";
2087 }
2088 command = command.replaceAll(target, replacement);
2089 }
2090 }
2091 }
2092
2093 write(out, command);
2094 }
2095 tokenizer = null;
2096 }
2097 in.close();
2098 in = null;
2099 out.flush();
2100 out.close();
2101 out = null;
2102 }
2103 catch(Exception error) {
2104 DebugStream.printStackTrace(error);
2105 }
2106 // All done, I hope.
2107 }
2108
2109 private void write(BufferedWriter out, String message)
2110 throws Exception {
2111 out.write(message, 0, message.length());
2112 out.newLine();
2113 }
2114
2115
2116 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2117 private class FMTreeModelListener
2118 implements TreeModelListener {
2119 /** 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.
2120 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2121 */
2122 public void treeNodesChanged(TreeModelEvent event) {
2123 if(collection != null) {
2124 collection.setSaved(false);
2125 collection.setFilesChanged(true);
2126 }
2127 }
2128 /** 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.
2129 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2130 */
2131 public void treeNodesInserted(TreeModelEvent event) {
2132 if(collection != null) {
2133 collection.setSaved(false);
2134 collection.setFilesChanged(true);
2135 }
2136 }
2137 /** 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.
2138 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2139 */
2140 public void treeNodesRemoved(TreeModelEvent event) {
2141 if(collection != null) {
2142 collection.setSaved(false);
2143 collection.setFilesChanged(true);
2144
2145 }
2146 }
2147 /** 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.
2148 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2149 */
2150 public void treeStructureChanged(TreeModelEvent event) {
2151 if(collection != null) {
2152 collection.setSaved(false);
2153 }
2154 }
2155 }
2156}
Note: See TracBrowser for help on using the repository browser.