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

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