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

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