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

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

correcting for whether to copy building to index

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