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

Last change on this file since 34168 was 34168, checked in by ak19, 4 years ago

Stupid oversight on my part yesterday: when fixing up client-GLI so that it could use a variable library servlet (whichever is the current one, instead of always the default 'library') to contact when activating a collection, I should have thought of fixing it for the local GLI with local Greenstone case too. Fortunately caught a possible bug in my previous fix related to this (svn revision 34158), which would pass the library_name to activate for GS3 as well as GS2. But only GS3 uses library servlets.

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