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

Last change on this file since 31638 was 31638, checked in by ak19, 7 years ago

Rewriting GShell.runLocal() to use SafeProcess instead of Process. This required overhaul of SafeProcess to correctly deal with interrupts as the build/import process launched in GShell can be cancelled from the CreatePane. SafeProcess now also keeps track of its internal process object and has static logging methods to simplify the changes required when swapping between the GS3 version and GS2 version of SafeProcess. May eventually call DebugStream methods from the log methods for GLI. Will add a DEBUG flag to allow verbose logging.

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