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

Last change on this file since 20960 was 20960, checked in by ak19, 14 years ago

3 changes: 1. A few more instances where perl should be launched for all OS with perl -S, since there's now a tarred up Perl available for Linux users in case their system perl is not the right one. 2. Incremental- and full-build and incremental- and full-import need not add the -collectdir parameter for the Remote Greenstone case, since the remote side will work out the path to the collection directory. 3. Calls to LocalGreenstone.getBinScriptDirectoryPath() are restricted to the local Greenstone case, so the path to the local bin script is no longer used in Remote Greenstone cases.

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