source: gli/branches/glicolgroup/src/org/greenstone/gatherer/collection/CollectionManager.java@ 19668

Last change on this file since 19668 was 19668, checked in by ak19, 15 years ago

Not working. Changes made for collectiongroup.

  • Property svn:keywords set to Author Date Id Revision
File size: 84.6 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.getGroupQualifiedName(true), 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 is 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((MetadataSecollection_namet) 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.getGroupQualifiedName(true), 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 System.err.println("*** Loading collection " + location + "...");
1172
1173 if (Gatherer.isGsdlRemote) {
1174 //String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
1175 String collection_name = location.substring(0, location.lastIndexOf(File.separator));
1176 collection_name = Gatherer.remoteGreenstoneServer.getPathRelativeToDirectory(new File(collection_name), getDefaultCollectDirectory());
1177 if (Gatherer.remoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1178 return;
1179 }
1180 }
1181
1182 // Check we have actually been given a .col file.
1183 if (!location.endsWith(".col")) {
1184 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1185 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1186 return;
1187 }
1188
1189 // Check that the collection configuration file is available
1190 File collection_file = new File(location);
1191
1192 // Ensure that the directory exists
1193 File collection_directory = collection_file.getParentFile();
1194
1195 if (collection_directory == null || !collection_directory.exists()) {
1196 // We can't open this
1197 System.err.println("CollectionManager.loadCollection: No collection directory.");
1198 return;
1199 }
1200
1201 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1202 File collection_config_file = new File(collection_directory, file_str);
1203 if (!collection_config_file.exists()) {
1204 System.err.println("CollectionManager.loadCollection: No config file.");
1205 collection_directory = null;
1206 collection_config_file = null;
1207 return;
1208 }
1209
1210 // Ensure that an import directory exists for this collection
1211 File collection_import_directory = new File(collection_directory, "import");
1212 if (!collection_import_directory.exists()) {
1213 collection_import_directory.mkdir();
1214 }
1215
1216 // Special case of a user trying to open an old greenstone collection.
1217 boolean non_gli_collection = false;
1218 File collection_metadata_directory = new File(collection_directory, "metadata");
1219 if (!collection_metadata_directory.exists()) {
1220 DebugStream.println("Loading non-gatherer collection...");
1221 // Show a warning message in case user wants to quit now
1222 non_gli_collection = true;
1223 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1224 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1225 legacy_dialog.dispose();
1226 collection_directory = null;
1227 collection_config_file = null;
1228 return;
1229 }
1230 legacy_dialog.dispose();
1231
1232 }
1233
1234 // Now determine if a lock already exists on this collection.
1235 String collection_name = collection_directory.getName();
1236 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1237 if (lock_file.exists()) {
1238 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1239 int choice = dialog.getChoice();
1240 dialog.dispose();
1241 dialog = null;
1242
1243 if (choice != LockFileDialog.YES_OPTION) {
1244 // user has cancelled
1245 lock_file = null;
1246 collection_directory = null;
1247 collection_config_file = null;
1248 return;
1249 }
1250
1251 lock_file.delete();
1252 }
1253
1254 try {
1255 // Create a lock file.
1256 createLockFile(lock_file);
1257 // This lock file may not have been created so check
1258 if(!lock_file.canWrite()) {
1259 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1260 System.err.println("Cannot write lock file!");
1261 String args[] = new String[2];
1262 args[0] = location;
1263 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1264 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1265 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1266 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1267 //}
1268 }
1269 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1270 args = null;
1271 return;
1272 }
1273
1274 if (canDoScheduling()) {
1275 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1276
1277 //First, see if "Schedule" exists in the XMl File...
1278 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1279 boolean flag = false;
1280 try {
1281 String stmp = new String();
1282
1283 while((stmp = bir.readLine()) != null) {
1284 stmp = stmp.trim();
1285 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1286 flag = true;
1287 break;
1288 }
1289 }
1290 bir.close();
1291
1292 } catch (IOException ioe) {
1293 DebugStream.printStackTrace(ioe);
1294 }
1295
1296 //modify if old .col (i.e. no Schedule exists in XML file)
1297 if(!flag) {
1298 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1299
1300
1301 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1302 bir = new BufferedReader(new FileReader(collection_file));
1303
1304 try {
1305 String stmp = new String();
1306 while((stmp = bir.readLine()) != null) {
1307 String stmp2 = stmp.trim();
1308 if(stmp2.startsWith("<!ELEMENT Argument")) {
1309 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1310 }
1311 else if(stmp2.equals("</BuildConfig>")) {
1312 bor.write(" <Schedule/>\n");
1313 }
1314
1315 bor.write(stmp + "\n");
1316
1317 }
1318 bir.close();
1319 bor.close();
1320 } catch (IOException ioe) {
1321 DebugStream.printStackTrace(ioe);
1322 }
1323
1324 //copy over tmp.col to replace
1325 try {
1326 collection_file.delete();
1327 new_collection_file.renameTo(collection_file);
1328 } catch (Exception e) {
1329 DebugStream.printStackTrace(e);
1330 }
1331 }
1332 }
1333
1334 // Open the collection file
1335 this.collection = new Collection(collection_file);
1336 if (collection.error) {
1337 collection = null;
1338 // Remove lock file
1339 if (lock_file.exists()) {
1340 lock_file.delete();
1341 }
1342 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1343 }
1344
1345 if (canDoScheduling()) {
1346 scheduling();
1347 }
1348
1349 MetadataSetManager.clearMetadataSets();
1350 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1351
1352 // Make sure we always have the extracted metadata set
1353 addRequiredMetadataSets();
1354
1355 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1356
1357 // If this is a non-GLI (legacy) collection, load the default metadata sets
1358 if (non_gli_collection) {
1359 addDefaultMetadataSets();
1360
1361 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1362 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1363 }
1364
1365 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1366 MetadataXMLFileManager.clearMetadataXMLFiles();
1367 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1368
1369
1370 // get rid of the previous scan through docxml files
1371 DocXMLFileManager.clearDocXMLFiles();
1372
1373 if (Configuration.fedora_info.isActive()) { // FLI case
1374 // Read through the docmets.xml files in the export directory
1375 File collection_export_directory = new File(getLoadedCollectionExportDirectoryPath());
1376 DocXMLFileManager.loadDocXMLFiles(collection_export_directory,"docmets.xml");
1377 }
1378 else {
1379 // Read through the doc.xml files in the archives directory
1380 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1381 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory,"doc.xml");
1382 }
1383
1384
1385 // Get a list of the collection specific classifiers and plugins
1386 Classifiers.loadClassifiersList(collection_name);
1387 Plugins.loadPluginsList(collection_name);
1388
1389 collection.cdm = new CollectionDesignManager(collection_config_file);
1390 if (non_gli_collection) {
1391 // Change the classifiers to use the namespaced element names
1392 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1393 }
1394
1395 // We're done. Let everyone know.
1396 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1397 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1398 }
1399 catch (Exception error) {
1400 // There is obviously no existing collection present.
1401 DebugStream.printStackTrace(error);
1402 error.printStackTrace();
1403 if(error.getMessage() != null) {
1404 String[] args = new String[2];
1405 args[0] = location;
1406 //args[1] = error.getMessage();
1407 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1408 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1409 }
1410 else {
1411 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1412 }
1413 }
1414
1415 lock_file = null;
1416 collection_directory = null;
1417 collection_config_file = null;
1418 }
1419
1420 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1421 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1422 * more situations. */
1423 public static boolean canDoScheduling() {
1424 // Would be nice to support more of these, rather than returning false
1425 if(Gatherer.isGsdlRemote) {
1426 return false;
1427 }
1428 if(Gatherer.GS3) {
1429 return false;
1430 }
1431 if (Configuration.fedora_info.isActive()) {
1432 return false;
1433 }
1434
1435 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1436 // it assumes GLI is inside a GS2 installation
1437 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1438 if(!mcfg.exists()) {
1439 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1440 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1441 return false;
1442 }
1443
1444 return true;
1445 }
1446
1447 private void makeCollection(String name, String email)
1448 {
1449 // Generate the mkcol.pl command
1450 ArrayList command_parts_list = new ArrayList();
1451 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1452 command_parts_list.add(Configuration.perl_path);
1453 command_parts_list.add("-S");
1454 }
1455 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1456 if(Gatherer.GS3) {
1457 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1458 }
1459
1460 command_parts_list.add("-collectdir");
1461 command_parts_list.add(getDefaultCollectDirectory());
1462
1463 command_parts_list.add("-win31compat");
1464 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1465
1466 if (email != null && !email.equals("")) {
1467 command_parts_list.add("-creator");
1468 command_parts_list.add(email);
1469 }
1470
1471 command_parts_list.add(name);
1472
1473 // Run the mkcol.pl command
1474 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1475 //for(int i = 0; i < command_parts.length; i++) {
1476 ///ystem.err.println("\""+command_parts[i]+"\"");
1477 //}
1478
1479 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1480 process.run(); // Don't bother threading this... yet
1481 }
1482
1483
1484 /** 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.
1485 * @param event A <strong>GShellEvent</strong> which contains a the message.
1486 */
1487 public synchronized void message(GShellEvent event) {
1488
1489 }
1490
1491
1492 public void metadataChanged(CollectionTreeNode[] file_nodes)
1493 {
1494 if (collection != null) {
1495 collection.setMetadataChanged(true);
1496 }
1497 }
1498
1499
1500 public void openCollectionFromLastTime() {
1501 // If there was an open collection last session, reopen it
1502 if (Gatherer.open_collection_file_path != null) {
1503 // Load the collection now
1504 loadCollection(Gatherer.open_collection_file_path);
1505 }
1506
1507 }
1508
1509
1510 /** This call is fired whenever a process within a GShell created by this class begins.
1511 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1512 * @see org.greenstone.gatherer.Gatherer
1513 * @see org.greenstone.gatherer.gui.GUIManager
1514 * @see org.greenstone.gatherer.shell.GShell
1515 */
1516 public synchronized void processBegun(GShellEvent event) {
1517 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1518 ///ystem.err.println("ProcessBegun " + event.getType());
1519 // If this is one of the types where we wish to lock user control
1520 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1521 }
1522 /** This call is fired whenever a process within a GShell created by this class ends.
1523 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1524 * @see org.greenstone.gatherer.Gatherer
1525 * @see org.greenstone.gatherer.gui.GUIManager
1526 * @see org.greenstone.gatherer.shell.GShell
1527 */
1528 public synchronized void processComplete(GShellEvent event) {
1529 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1530 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1531 ///ystem.err.println("Received process complete event - " + event);
1532 // If we were running an import, now run a build.
1533 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1534 // Finish import.
1535 collection.setImported(true);
1536 collection.setFilesChanged(false);
1537 collection.setMetadataChanged(false);
1538 buildCollection();
1539 }
1540 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1541
1542 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1543 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1544 collection_built_warning_dialog.display();
1545 collection_built_warning_dialog.dispose();
1546 collection_built_warning_dialog = null;
1547 }
1548 // If we were running a build, now is when we move files across.
1549 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1550
1551 if ( CollectionDesignManager.buildcolWasFull() ) {
1552 if(installCollection()) {
1553 // If we have a local library running then ask it to add our newly create collection
1554 if (LocalLibraryServer.isRunning() == true) {
1555 LocalLibraryServer.addCollection(collection.getName());
1556 }
1557 else if (Gatherer.GS3) {
1558 //xiao comment out this: convertToGS3Collection();
1559 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1560 }
1561
1562 // Fire a collection changed first to update the preview etc buttons
1563 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1564
1565 // Now display a message dialog saying its all built
1566 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1567 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1568 collection_built_warning_dialog.display();
1569 collection_built_warning_dialog.dispose();
1570 collection_built_warning_dialog = null;
1571
1572 //Set nothing as needing rebuilding, as a build has just finished :-)
1573 CollectionDesignManager.resetRebuildTypeRequired();
1574 }
1575 else {
1576 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1577 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1578 DebugStream.println("Status is ok but !installCollection()");
1579 }
1580 }
1581 }
1582 else if (event.getStatus() == GShell.CANCELLED) {
1583 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1584 Gatherer.g_man.repaint();
1585 }
1586 else if (event.getStatus() == GShell.ERROR) {
1587 if (event.getType() == GShell.NEW) {
1588 String name = event.getMessage();
1589 String collectDir = getCollectionDirectoryPath(name);
1590 String errMsg = "";
1591 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1592 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1593 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1594 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1595 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1596 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1597 //}
1598 }
1599 } else {
1600 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1601 }
1602 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1603 }
1604 else if(event.getType() == GShell.SCHEDULE) {
1605 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1606 }
1607 else {
1608 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1609 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1610 }
1611
1612 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.
1613 }
1614 }
1615
1616
1617 /** Determine if the manager is ready for actions apon its collection.
1618 * @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.
1619 */
1620 static public synchronized boolean ready() {
1621 if(collection != null) {
1622 return true;
1623 }
1624 else {
1625 return false;
1626 }
1627 }
1628
1629
1630 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1631 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1632 */
1633 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1634 build_monitor = monitor;
1635 }
1636 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1637 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1638 */
1639 public void registerImportMonitor(GShellProgressMonitor monitor) {
1640 import_monitor = monitor;
1641 }
1642
1643 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1644 schedule_monitor = monitor;
1645 }
1646
1647
1648 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1649 {
1650 collection_contents_changed_listeners.remove(listener);
1651 }
1652
1653
1654 public void removeMetadataSet(MetadataSet metadata_set)
1655 {
1656 DebugStream.println("Removing metadata set...");
1657
1658 // Delete the .mds file from the collection's "metadata" folder...
1659 File metadata_set_file = metadata_set.getMetadataSetFile();
1660
1661 // ...but not if it is the "ex.mds" file
1662 if (metadata_set_file.getName().equals("ex.mds")) {
1663 return;
1664 }
1665
1666 // ...and only if it exists
1667 if (metadata_set_file.exists()) {
1668 metadata_set_file.delete();
1669
1670 // Unload it from the MetadataSetManager
1671 MetadataSetManager.unloadMetadataSet(metadata_set);
1672
1673 // If we're using a remote Greenstone server, delete the metadata file on the server
1674 if (Gatherer.isGsdlRemote) {
1675 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getGroupQualifiedName(true), metadata_set_file);
1676 }
1677 }
1678 }
1679
1680
1681 /** Used to check whether all open collections have a 'saved' state.
1682 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1683 * @see org.greenstone.gatherer.collection.Collection
1684 */
1685 public boolean saved() {
1686 boolean result = true;
1687 if(collection != null) {
1688 result = collection.getSaved();
1689 }
1690 return result;
1691 }
1692
1693
1694 /** Saves the currently loaded collection. */
1695 public void saveCollection()
1696 {
1697
1698 if (collection == null) return;
1699
1700 DebugStream.println("Saving collection " + collection.getName() + "...");
1701
1702 // Change cursor to hourglass
1703 Gatherer.g_man.wait(true);
1704
1705 // Create a backup of the collection file, just in case anything goes wrong
1706 File collection_file = new File(getLoadedCollectionColFilePath());
1707 if (collection_file.exists()) {
1708 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1709 if (!collection_file.renameTo(collection_file_backup)) {
1710 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1711 }
1712 collection_file_backup.deleteOnExit();
1713 }
1714
1715 // Write out the collection file
1716 collection.save();
1717
1718 // Write out the collection configuration file
1719 collection.cdm.save();
1720
1721 // Change cursor back to normal
1722 Gatherer.g_man.wait(false);
1723 }
1724
1725
1726 /** 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] */
1727 private void addDefaultMetadataSets()
1728 {
1729 // Add dublin core which is the default metadata set. The user
1730 // can change this later
1731 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1732 if (dc_file.exists()) {
1733 importMetadataSet(new MetadataSet(dc_file));
1734 }
1735 }
1736
1737
1738 private void addRequiredMetadataSets()
1739 {
1740 // Always import the extracted metadata set
1741 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1742 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1743 }
1744
1745 private String getDefaultCollectDirectory() {
1746 String collect_dir = Gatherer.getCollectDirectoryPath();
1747 // Remove erroneous file windows file separator as it causes problems when running import.pl
1748 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1749 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1750 }
1751 return collect_dir;
1752 }
1753
1754 // used as arg in the perl scripts
1755 private String getCollectDirectory() {
1756
1757 String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
1758 return collect_dir;
1759 }
1760
1761
1762 /** Install collection by moving its files from building to index after a successful build.
1763 * @see org.greenstone.gatherer.Gatherer
1764 * @see org.greenstone.gatherer.util.Utility
1765 */
1766 private boolean installCollection()
1767 {
1768 if (Configuration.fedora_info.isActive()) {
1769 DebugStream.println("Fedora build complete. No need to move files.");
1770 return true;
1771 }
1772
1773
1774 DebugStream.println("Build complete. Moving files.");
1775
1776 try {
1777 // Ensure that the local library has released this collection so we can delete the index directory
1778 if (LocalLibraryServer.isRunning() == true) {
1779 LocalLibraryServer.releaseCollection(collection.getName());
1780 }
1781 // deactivate it in tomcat so that windows will release the index files
1782 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1783 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1784 }
1785 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1786 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1787
1788 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1789 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1790
1791 // Get the build mode from the build options
1792 String build_mode = collection.build_options.getValue("mode");
1793
1794 // Special case for build mode "all": replace index dir with building dir
1795 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1796 // Remove the old index directory
1797 if (index_dir.exists()) {
1798 Utility.delete(index_dir);
1799
1800 // Wait for a couple of seconds, just for luck
1801 wait(2000);
1802
1803 // Check the delete worked
1804 if (index_dir.exists()) {
1805 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1806 }
1807 }
1808
1809 if (Gatherer.isGsdlRemote) {
1810 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
1811 collection.getGroupQualifiedName(true), new File(getLoadedCollectionIndexDirectoryPath()));
1812 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getGroupQualifiedName(true),
1813 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1814 }
1815
1816 // Move the building directory to become the new index directory
1817 if (building_dir.renameTo(index_dir) == false) {
1818 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1819 }
1820 }
1821
1822 // Otherwise copy everything in the building dir into the index dir
1823 else {
1824 moveContentsInto(building_dir, index_dir);
1825 }
1826 }
1827 catch (Exception exception) {
1828 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1829 return false;
1830 }
1831 return true;
1832 }
1833
1834
1835 /** Moves all the files in one directory into another, overwriting existing files */
1836 private void moveContentsInto(File source_directory, File target_directory)
1837 {
1838 File[] source_files = source_directory.listFiles();
1839 for (int i = 0; i < source_files.length; i++) {
1840 File source_file = source_files[i];
1841 File target_file = new File(target_directory, source_file.getName());
1842
1843 if (source_file.isDirectory()) {
1844 moveContentsInto(source_file, target_file);
1845 source_file.delete();
1846 }
1847 else {
1848 if (target_file.exists()) {
1849 target_file.delete();
1850 }
1851
1852 source_file.renameTo(target_file);
1853 }
1854 }
1855 }
1856
1857 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1858 //In this method, the files base_cfg and new_cfg are all xml files.
1859
1860 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1861 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1862 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1863 Element collection_config = new_cfg_doc.getDocumentElement();
1864
1865 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1866 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1867 int num_nodes = classifier_children.getLength();
1868
1869 if (num_nodes < 1) {
1870 return;
1871 }
1872
1873 // Read in the classifier command watching for hfile, metadata and sort arguments.
1874 String buttonname = null;
1875 String hfile = null;
1876 String metadata = null;
1877 String sort = null;
1878
1879 for (int i=0; i<num_nodes; i++) {
1880 Element classifier_element = (Element)classifier_children.item(i);
1881 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1882 for (int j=0; j<option_children.getLength(); j++) {
1883 Element option_element = (Element)option_children.item(j);
1884 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1885 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1886
1887 if (name_str == null || name_str.equals("")) {
1888 continue;
1889 }
1890 if (name_str != null && value_str == null ) {
1891 value_str = "";
1892 }
1893 if (name_str.equals("hfile")) {
1894 hfile = value_str;
1895 }
1896 else if (name_str.equals("metadata") && value_str != null) {
1897 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1898 if (replacement != null && !replacement.equals("")) {
1899 metadata = replacement;
1900 }
1901 }
1902 else if (name_str.equals("sort") && value_str != null) {
1903 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1904 if (replacement != null && !replacement.equals("")) {
1905 sort = replacement;
1906 }
1907 }
1908 else if(name_str.equals("buttonname") && value_str != null) {
1909 buttonname = value_str;
1910 }
1911 }
1912 }
1913 for (int i=0; i<num_nodes; i++) {
1914 Element classifier_element = (Element)classifier_children.item(i);
1915 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1916 for (int j=0; j<option_children.getLength(); j++) {
1917 Element option_element = (Element)option_children.item(j);
1918 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1919
1920 if (name_str.equals("metadata") && metadata != null) {
1921 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1922 }
1923 else if (name_str.equals("hfile") && hfile != null) {
1924 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1925 }
1926 else if (name_str.equals("sort") && sort != null) {
1927 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1928 }
1929 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1930 // No buttonname has been specified. Lets create one using the metadata as its value
1931 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1932 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1933 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1934 classifier_element.appendChild(option);
1935 }
1936 }
1937 }
1938 }
1939
1940 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1941 {
1942 boolean first_name = true;
1943 boolean first_extra = true;
1944
1945 // 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.
1946 try {
1947 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1948 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1949 String command = null;
1950 while((command = in.readLine()) != null) {
1951 if (command.length()==0) {
1952 // output a new line
1953 out.newLine();
1954 continue;
1955 }
1956 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1957 while(command.trim().endsWith("\\")) {
1958 command = command.substring(0, command.lastIndexOf("\\"));
1959 String next_line = in.readLine();
1960 if(next_line != null) {
1961 command = command + next_line;
1962 }
1963 }
1964 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1965 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1966 String command_type_str = tokenizer.nextToken().toLowerCase();
1967
1968 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1969 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1970 StringBuffer new_command = new StringBuffer(command_type_str);
1971 String meta_name = tokenizer.nextToken();
1972 new_command.append(' ');
1973 new_command.append(meta_name);
1974 while (tokenizer.hasMoreTokens()) {
1975 new_command.append(' ');
1976 new_command.append(tokenizer.nextToken());
1977 }
1978 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)) {
1979 // dont save
1980 } else {
1981 write(out, new_command.toString());
1982 }
1983 new_command = null;
1984 continue;
1985 } // if collectionmeta
1986
1987 if (command_type_str.equals("classify")) {
1988 StringBuffer text = new StringBuffer(command_type_str);
1989 // Read in the classifier command watching for hfile, metadata and sort arguments.
1990 String buttonname = null;
1991 String hfile = null;
1992 String new_metadata = null;
1993 String old_metadata = null;
1994
1995 while(tokenizer.hasMoreTokens()) {
1996 String token = tokenizer.nextToken();
1997 if (token.equals("-hfile")) {
1998 if(tokenizer.hasMoreTokens()) {
1999 text.append(" ");
2000 text.append(token);
2001 token = tokenizer.nextToken();
2002 hfile = token;
2003 }
2004 }
2005 else if (token.equals("-metadata")) {
2006 if(tokenizer.hasMoreTokens()) {
2007 text.append(" ");
2008 text.append(token);
2009 String temp_metadata = tokenizer.nextToken();
2010 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2011 if (replacement != null && !replacement.equals("")) {
2012 token = replacement;
2013 old_metadata = temp_metadata;
2014 new_metadata = replacement;
2015 }
2016 else {
2017 token = temp_metadata;
2018 }
2019 temp_metadata = null;
2020 replacement = null;
2021 }
2022 }
2023 else if (token.equals("-sort")) {
2024 if(tokenizer.hasMoreTokens()) {
2025 text.append(" ");
2026 text.append(token);
2027 String temp_metadata = tokenizer.nextToken();
2028 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2029 if (replacement != null && !replacement.equals("")) {
2030 token = replacement;
2031 }
2032 else {
2033 token = temp_metadata;
2034 }
2035 temp_metadata = null;
2036 replacement = null;
2037 }
2038 }
2039 else if(token.equals("-buttonname")) {
2040 buttonname = token;
2041 }
2042 text.append(' ');
2043 text.append(token);
2044 token = null;
2045 }
2046
2047 // 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)!
2048 if(old_metadata != null && new_metadata != null && buttonname == null) {
2049 text.append(' ');
2050 text.append("-buttonname");
2051 text.append(' ');
2052 text.append(old_metadata);
2053 }
2054 command = text.toString();
2055 // Replace the hfile if we found it
2056 if(hfile != null && new_metadata != null) {
2057 command = command.replaceAll(hfile, new_metadata + ".txt");
2058 }
2059
2060 buttonname = null;
2061 hfile = null;
2062 new_metadata = null;
2063 old_metadata = null;
2064 write(out, command);
2065 } else {
2066 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2067 StringBuffer new_command = new StringBuffer(command_type_str);
2068 while (tokenizer.hasMoreTokens()) {
2069 new_command.append(' ');
2070 new_command.append(tokenizer.nextToken());
2071 }
2072
2073 command = new_command.toString();
2074
2075 // 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.
2076 // we really want to build up the whole command here
2077 boolean format_command = command_type_str.equals("format");
2078 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2079 if (metadata_mapping != null) {
2080 Iterator keys = metadata_mapping.keySet().iterator();
2081 while (keys.hasNext()) {
2082 String target = (String) keys.next();
2083 String replacement = (String) metadata_mapping.get(target);
2084 if (replacement != null && !replacement.equals("")) {
2085 if (format_command) {
2086 target = "\\[" + target + "\\]";
2087 replacement = "{Or}{[" + replacement + "]," + target + "}";
2088 }
2089 command = command.replaceAll(target, replacement);
2090 }
2091 }
2092 }
2093
2094 write(out, command);
2095 }
2096 tokenizer = null;
2097 }
2098 in.close();
2099 in = null;
2100 out.flush();
2101 out.close();
2102 out = null;
2103 }
2104 catch(Exception error) {
2105 DebugStream.printStackTrace(error);
2106 }
2107 // All done, I hope.
2108 }
2109
2110 private void write(BufferedWriter out, String message)
2111 throws Exception {
2112 out.write(message, 0, message.length());
2113 out.newLine();
2114 }
2115
2116
2117 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2118 private class FMTreeModelListener
2119 implements TreeModelListener {
2120 /** 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.
2121 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2122 */
2123 public void treeNodesChanged(TreeModelEvent event) {
2124 if(collection != null) {
2125 collection.setSaved(false);
2126 collection.setFilesChanged(true);
2127 }
2128 }
2129 /** 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.
2130 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2131 */
2132 public void treeNodesInserted(TreeModelEvent event) {
2133 if(collection != null) {
2134 collection.setSaved(false);
2135 collection.setFilesChanged(true);
2136 }
2137 }
2138 /** 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.
2139 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2140 */
2141 public void treeNodesRemoved(TreeModelEvent event) {
2142 if(collection != null) {
2143 collection.setSaved(false);
2144 collection.setFilesChanged(true);
2145
2146 }
2147 }
2148 /** 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.
2149 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2150 */
2151 public void treeStructureChanged(TreeModelEvent event) {
2152 if(collection != null) {
2153 collection.setSaved(false);
2154 }
2155 }
2156 }
2157}
Note: See TracBrowser for help on using the repository browser.