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

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

In the previous commit 1. Codec.java change was still related to commit 34241. 2. Fixed my own silly bug: it's windowClosed not windowClose. Because the real method was not overridden, it never got called when the configFileEditor was closed, as a result of which the GLI's GUI interface wasn't getting immediately repainted. 3. Fixed a bug in FileNode.java (nullpointer exception case). 4. Accidentally committed experimental work to export metadata from GLI to csv. This commit undoes the experimental stuff, only some of which is promising and still needs work.

  • Property svn:keywords set to Author Date Id Revision
File size: 98.5 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 * In the case of a remote GS, this method takes care of reuploading a modified mds file after its
1299 * Metadata Set has been edited.
1300 * This method is mostly a copy of importMetadataSet() above, except no need to handle the hidden.mds
1301 * file as that should not even have been made available for editing in GLI.
1302 * Nor any need for MetadataSetManager.loadMetadataSet(File) as that was already done by the caller,
1303 * MetadataSetDialog.EditButtonListener.actionPerformed().
1304 */
1305 public void updateMetadataSet(MetadataSet external_metadata_set) {
1306 try {
1307 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1308 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1309
1310 // If we're using a remote Greenstone server, upload the metadata file
1311 if (Gatherer.isGsdlRemote) {
1312 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1313 }
1314 } catch (Exception exception) {
1315 DebugStream.printStackTrace(exception);
1316 }
1317 }
1318
1319
1320 /** 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.
1321 * @return true if the gli is currently importing
1322 */
1323 public boolean isImporting() {
1324 return importing;
1325 }
1326
1327
1328 public void reloadAfterConfigFileEdited() {
1329 // Copying just the part of LoadCollectionInternal below that loads the config file
1330 // Need to reload the *existing* config file, however. So calling custom method reloadConfig()
1331
1332 // Don't see why this stuff here (vs LoadCollectionInternal) would need to happen in its own
1333 // Thread for my use: when the modal Edit > collectionConfig.xml dialog has saved and closed.
1334
1335 // reload current collection's config
1336 collection.cdm.reloadConfig();
1337
1338 // We're done. Let everyone know.
1339 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection.getName()));
1340 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1341 }
1342
1343 public void loadCollection(String collection_file_path)
1344 {
1345 // Display a modal progress popup to indicate that the collection is being loaded
1346 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1347 load_collection_progress_popup.display();
1348
1349 // Load the collection on a separate thread so the progress bar updates correctly
1350 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1351 //SwingUtilities.invokeLater(new LoadCollectionTask(collection_file_path, load_collection_progress_popup));
1352 }
1353
1354
1355 private class LoadCollectionTask
1356 extends Thread
1357 {
1358 private String collection_file_path = null;
1359 private ModalProgressPopup load_collection_progress_popup = null;
1360
1361 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1362 {
1363 this.collection_file_path = collection_file_path;
1364 this.load_collection_progress_popup = load_collection_progress_popup;
1365 }
1366
1367 public void run()
1368 {
1369 loadCollectionInternal(collection_file_path);
1370 load_collection_progress_popup.close();
1371 Gatherer.setMenuBarEnabled(true);
1372 }
1373 }
1374
1375
1376 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1377 * @param location The path to the collection as a <strong>String</strong>.
1378 * @see org.greenstone.gatherer.Configuration
1379 * @see org.greenstone.gatherer.Gatherer
1380 * @see org.greenstone.gatherer.collection.Collection
1381 * @see org.greenstone.gatherer.util.Utility
1382 */
1383 private void loadCollectionInternal(String location)
1384 {
1385 DebugStream.println("Loading collection " + location + "...");
1386
1387
1388 // Check we have actually been given a .col file.
1389 if (!location.endsWith(".col")) {
1390 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1391 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1392 return;
1393 }
1394
1395 // Check that the collection configuration file is available
1396 File collection_file = new File(location);
1397
1398 //String collection_name = collection_directory.getName();
1399 String collection_name = "";
1400 File collection_directory = collection_file.getParentFile();
1401
1402 // To get colname = (colgroup/)coltailname, subtract Gatherer.getCollectDirectoryPath() from collection_directory:
1403 int index = collection_directory.getAbsolutePath().indexOf(Gatherer.getCollectDirectoryPath());
1404 if(index == -1) {
1405 System.err.println("*** ERROR: collection directory " + collection_directory + " is not located in collect folder: " + Gatherer.getCollectDirectoryPath());
1406 } else {
1407 index += Gatherer.getCollectDirectoryPath().length();
1408 collection_name = collection_directory.getAbsolutePath().substring(index);
1409 }
1410
1411 if (Gatherer.isGsdlRemote) {
1412 if (Gatherer.remoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1413 return;
1414 }
1415 }
1416
1417 // Ensure that the collection directory exists
1418 if (collection_directory == null || !collection_directory.exists()) {
1419 // We can't open this
1420 System.err.println("CollectionManager.loadCollection: No collection directory.");
1421 return;
1422 }
1423
1424 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1425 File collection_config_file = new File(collection_directory, file_str);
1426 if (!collection_config_file.exists()) {
1427 System.err.println("CollectionManager.loadCollection: No config file.");
1428 collection_directory = null;
1429 collection_config_file = null;
1430 return;
1431 }
1432
1433 // Ensure that an import directory exists for this collection
1434 File collection_import_directory = new File(collection_directory, "import");
1435 if (!collection_import_directory.exists()) {
1436 collection_import_directory.mkdir();
1437 }
1438
1439 // Special case of a user trying to open an old greenstone collection.
1440 boolean non_gli_collection = false;
1441 File collection_metadata_directory = new File(collection_directory, "metadata");
1442 if (!collection_metadata_directory.exists()) {
1443 DebugStream.println("Loading non-gatherer collection...");
1444 // Show a warning message in case user wants to quit now
1445 non_gli_collection = true;
1446 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1447 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1448 legacy_dialog.dispose();
1449 collection_directory = null;
1450 collection_config_file = null;
1451 return;
1452 }
1453 legacy_dialog.dispose();
1454
1455 }
1456
1457 // Now determine if a lock already exists on this collection.
1458 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1459 if (lock_file.exists()) {
1460 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1461 TestingPreparation.setNamesRecursively(dialog);
1462 int choice = dialog.getChoice();
1463 dialog.dispose();
1464 dialog = null;
1465
1466 if (choice != LockFileDialog.YES_OPTION) {
1467 // user has cancelled
1468 lock_file = null;
1469 collection_directory = null;
1470 collection_config_file = null;
1471 return;
1472 }
1473
1474 lock_file.delete();
1475 }
1476
1477 // now we are using gli.col - old colls may have used the collection name
1478 if (!collection_file.exists()) {
1479 File old_coll_file = new File(collection_directory, collection_name+".col");
1480 if (old_coll_file.exists()) {
1481 try {
1482 old_coll_file.renameTo(collection_file);
1483 } catch (Exception e) {
1484 DebugStream.println("Couldn't rename "+old_coll_file.getName()+" to gli.col. Will just carry on with default gli.col");
1485 // but just carry on.
1486 }
1487 }
1488 }
1489
1490 try {
1491 // Create a lock file.
1492 createLockFile(lock_file);
1493 // This lock file may not have been created so check
1494 if(!lock_file.canWrite()) {
1495 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1496 System.err.println("Cannot write lock file!");
1497 String args[] = new String[2];
1498 args[0] = location;
1499 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1500 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1501 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1502 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1503 //}
1504 }
1505 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1506 args = null;
1507 return;
1508 }
1509
1510 // need to fix this up as currently it craps out if the .col file is not there, which is may not always be.
1511 if (canDoScheduling() && collection_file.exists()) {
1512 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1513 // Don't need to update anything if collection_file doesn't exist yet.
1514 //First, see if "Schedule" exists in the XMl File...
1515 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1516 boolean flag = false;
1517 try {
1518 String stmp = new String();
1519
1520 while((stmp = bir.readLine()) != null) {
1521 stmp = stmp.trim();
1522 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1523 flag = true;
1524 break;
1525 }
1526 }
1527 bir.close();
1528
1529 } catch (IOException ioe) {
1530 DebugStream.printStackTrace(ioe);
1531 }
1532
1533 //modify if old .col (i.e. no Schedule exists in XML file)
1534 if(!flag) {
1535 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1536
1537
1538 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1539 bir = new BufferedReader(new FileReader(collection_file));
1540
1541 try {
1542 String stmp = new String();
1543 while((stmp = bir.readLine()) != null) {
1544 String stmp2 = stmp.trim();
1545 if(stmp2.startsWith("<!ELEMENT Argument")) {
1546 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1547 }
1548 else if(stmp2.equals("</BuildConfig>")) {
1549 bor.write(" <Schedule/>\n");
1550 }
1551
1552 bor.write(stmp + "\n");
1553
1554 }
1555 bir.close();
1556 bor.close();
1557 } catch (IOException ioe) {
1558 DebugStream.printStackTrace(ioe);
1559 }
1560
1561 //copy over tmp.col to replace
1562 try {
1563 collection_file.delete();
1564 new_collection_file.renameTo(collection_file);
1565 } catch (Exception e) {
1566 DebugStream.printStackTrace(e);
1567 }
1568 }
1569 }
1570
1571 // Open the collection file
1572 this.collection = new Collection(collection_file);
1573 if (collection.error) {
1574 collection = null;
1575 // Remove lock file
1576 if (lock_file.exists()) {
1577 lock_file.delete();
1578 }
1579 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1580 }
1581
1582 if (canDoScheduling()) {
1583 scheduling();
1584 }
1585
1586 // These may have been set in the past, but are no longer used
1587 // by GLI
1588 collection.import_options.removeValue("removeold");
1589 collection.import_options.removeValue("keepold");
1590
1591 MetadataSetManager.clearMetadataSets();
1592 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1593
1594 // Make sure we always have the extracted metadata set
1595 addRequiredMetadataSets();
1596
1597 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1598
1599 // If this is a non-GLI (legacy) collection, load the default metadata sets
1600 if (non_gli_collection) {
1601 addDefaultMetadataSets();
1602
1603 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1604 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1605 }
1606
1607 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1608 MetadataXMLFileManager.clearMetadataXMLFiles();
1609 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1610
1611
1612 // get rid of the previous scan through docxml files
1613 DocXMLFileManager.clearDocXMLFiles();
1614
1615 if (Configuration.fedora_info.isActive()) { // FLI case
1616 // Read through the docmets.xml files in the export directory
1617 File collection_export_directory = new File(getLoadedCollectionExportDirectoryPath());
1618 DocXMLFileManager.loadDocXMLFiles(collection_export_directory,"docmets.xml");
1619 }
1620 else {
1621 // Read through the doc.xml files in the archives directory
1622 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1623 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory,"doc.xml");
1624 }
1625
1626
1627 // Get a list of the collection specific classifiers and plugins
1628 Classifiers.loadClassifiersList(collection_name);
1629 Plugins.loadPluginsList(collection_name);
1630
1631 collection.cdm = new CollectionDesignManager(collection_config_file);
1632 if (non_gli_collection) {
1633 // Change the classifiers to use the namespaced element names
1634 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1635 }
1636
1637 // We're done. Let everyone know.
1638 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1639 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1640 }
1641 catch (Exception error) {
1642 // There is obviously no existing collection present.
1643 DebugStream.printStackTrace(error);
1644 error.printStackTrace();
1645 if(error.getMessage() != null) {
1646 String[] args = new String[2];
1647 args[0] = location;
1648 args[1] = error.getMessage();
1649 //args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1650 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1651 }
1652 else {
1653 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1654 }
1655 }
1656
1657 lock_file = null;
1658 collection_directory = null;
1659 collection_config_file = null;
1660 }
1661
1662 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1663 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1664 * more situations. */
1665 public static boolean canDoScheduling() {
1666 // Would be nice to support more of these, rather than returning false
1667 if(Gatherer.isGsdlRemote) {
1668 return false;
1669 }
1670 if(Gatherer.GS3) {
1671 return false;
1672 }
1673 if (Configuration.fedora_info.isActive()) {
1674 return false;
1675 }
1676
1677 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1678 // it assumes GLI is inside a GS2 installation
1679 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1680 if(!mcfg.exists()) {
1681 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1682 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1683 return false;
1684 }
1685
1686 return true;
1687 }
1688
1689 private void makeCollection(String name, String email)
1690 {
1691 // Generate the mkcol.pl command
1692 ArrayList command_parts_list = new ArrayList();
1693 if (!Gatherer.isGsdlRemote) {
1694 command_parts_list.add(Configuration.perl_path);
1695 command_parts_list.add("-S");
1696 }
1697 command_parts_list.add(scriptPath + "mkcol.pl");
1698 if(Gatherer.GS3) {
1699 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1700 command_parts_list.add("-site");
1701 command_parts_list.add(Configuration.site_name);
1702 }
1703
1704 if(!Gatherer.isGsdlRemote) {
1705 command_parts_list.add("-collectdir");
1706 command_parts_list.add(getDefaultCollectDirectory());
1707 }
1708 command_parts_list.add("-win31compat");
1709 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1710
1711 if (email != null && !email.equals("")) {
1712 command_parts_list.add("-creator");
1713 command_parts_list.add(email);
1714 }
1715
1716 command_parts_list.add(name);
1717
1718 // Run the mkcol.pl command
1719 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1720 //for(int i = 0; i < command_parts.length; i++) {
1721 ///ystem.err.println("\""+command_parts[i]+"\"");
1722 //}
1723
1724 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1725 process.run(); // Don't bother threading this... yet
1726 }
1727
1728
1729 /** 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.
1730 * @param event A <strong>GShellEvent</strong> which contains a the message.
1731 */
1732 public synchronized void message(GShellEvent event) {
1733
1734 }
1735
1736
1737 public void metadataChanged(CollectionTreeNode[] file_nodes)
1738 {
1739 if (collection != null) {
1740 collection.setMetadataChanged(true);
1741
1742 // we're only going to refresh the tree's already visible nodes (and reselect them) IFF
1743 // gs.FilenameEncoding meta was set on any files/folders and the filenames of the
1744 // affected CollectionTreeNodes need to be recalculated
1745 if(FilenameEncoding.isRefreshRequired()) {
1746
1747 // refreshes the relevant part of the tree
1748 TreePath[] paths = collection_tree.getSelectionPaths();
1749 if(paths != null) {
1750 for(int i = 0; i < paths.length; i++) {
1751 collection_tree_model.refresh(paths[i]);
1752 collection_tree.setSelectionPath(paths[i]);
1753 }
1754 }
1755 // refreshed the tree, so turn off the requirement to refresh
1756 FilenameEncoding.setRefreshRequired(false);
1757 }
1758 }
1759 }
1760
1761
1762 public void openCollectionFromLastTime() {
1763 // If there was an open collection last session, reopen it.
1764 // (this method doesn't get called if there was no open collection or only a collect folder
1765 // instead of any previously-opened collection)
1766
1767 // Load the collection now
1768 loadCollection(Gatherer.open_collection_file_path);
1769 }
1770
1771
1772 /** This call is fired whenever a process within a GShell created by this class begins.
1773 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1774 * @see org.greenstone.gatherer.Gatherer
1775 * @see org.greenstone.gatherer.gui.GUIManager
1776 * @see org.greenstone.gatherer.shell.GShell
1777 */
1778 public synchronized void processBegun(GShellEvent event) {
1779 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1780 ///ystem.err.println("ProcessBegun " + event.getType());
1781 // If this is one of the types where we wish to lock user control
1782 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1783 }
1784 /** This call is fired whenever a process within a GShell created by this class ends.
1785 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1786 * @see org.greenstone.gatherer.Gatherer
1787 * @see org.greenstone.gatherer.gui.GUIManager
1788 * @see org.greenstone.gatherer.shell.GShell
1789 */
1790 public synchronized void processComplete(GShellEvent event) {
1791 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1792 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1793 ///ystem.err.println("Received process complete event - " + event);
1794 // If we were running an import, now run a build.
1795 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1796 // Finish import.
1797 collection.setImported(true);
1798 collection.setFilesChanged(false);
1799 collection.setMetadataChanged(false);
1800 buildCollection();
1801 }
1802 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1803
1804 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1805 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1806 collection_built_warning_dialog.display();
1807 collection_built_warning_dialog.dispose();
1808 collection_built_warning_dialog = null;
1809 }
1810 // If we were running a build, now is when we move files across.
1811 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1812
1813 if ( CollectionDesignManager.buildcolWasFull() ) {
1814
1815 // No installCollection() for GS3 solr collection: activate will take care of that
1816 // and no call to configGS3Server for solr collection
1817 if(CollectionManager.isSolrCollection()) {
1818
1819 DebugStream.println("Solr collection build complete: building already moved to index by activate.pl.");
1820
1821 // Finished building,
1822 // For now, for a GS3 solr collection, we'd have stopped the GS3 server before building
1823 // and will now need to restart it.
1824 /*GS3ServerThread thread = new GS3ServerThread(Configuration.gsdl3_src_path, "restart");
1825 thread.start();*/
1826
1827 // Give the GS3 server time to restart:
1828 // the GS3ServerThread above waits for the process to terminate. ant restart target calls the start-tomcat ant target
1829 // and that takes waits 5 seconds and polls to see if a GS3 server index page has loaded. So no need to sleep here
1830
1831 }
1832
1833 else if(installCollection()) {
1834 // If we have a local library running then ask it to add our newly created collection
1835 if (LocalLibraryServer.isRunning() == true) {
1836 LocalLibraryServer.addCollection(collection.getName());
1837 }
1838 else if (Gatherer.GS3) {
1839 //xiao comment out this: convertToGS3Collection();
1840 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1841 }
1842
1843 // Fire a collection changed first to update the preview etc buttons
1844 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1845
1846 // Now display a message dialog saying its all built
1847 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1848 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1849 collection_built_warning_dialog.display();
1850 collection_built_warning_dialog.dispose();
1851 collection_built_warning_dialog = null;
1852
1853 //Set nothing as needing rebuilding, as a build has just finished :-)
1854 CollectionDesignManager.resetRebuildTypeRequired();
1855 }
1856 else {
1857 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1858 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1859 DebugStream.println("Status is ok but !installCollection()");
1860 }
1861 }
1862 }
1863
1864 else if(event.getType() == GShell.DELETE) {
1865
1866 // we can only get here if we tried to delete a fedora collection
1867
1868 if(event.getStatus() == GShell.ERROR) { // error purging the collection from fedora
1869
1870 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Fedora_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1871 delete_collection_name = null; // re-zero
1872 }
1873
1874 else if(event.getStatus() == GShell.OK) { // fedora purge was successful
1875
1876 if(delete_collection_name != null) {
1877 if (Gatherer.isGsdlRemote) {
1878 Gatherer.remoteGreenstoneServer.deleteCollection(delete_collection_name);
1879 }
1880
1881 // if Greenstone3, need to deactivate the collection on the server
1882 if (Gatherer.GS3) {
1883 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + delete_collection_name);
1884 }
1885
1886 // Now at last, can delete the collection directory as for a normal collection
1887 boolean success = Utility.delete(new File(getCollectionDirectoryPath(delete_collection_name)));
1888
1889 if (!success) {
1890 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1891 }
1892 delete_collection_name = null; // re-zero
1893 }
1894
1895 }
1896 }
1897
1898 else if (event.getStatus() == GShell.CANCELLED) {
1899 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1900 Gatherer.g_man.repaint();
1901 }
1902 else if (event.getStatus() == GShell.ERROR) {
1903 if (event.getType() == GShell.NEW) {
1904 String name = event.getMessage();
1905 String collectDir = getCollectionDirectoryPath(name);
1906 String errMsg = "";
1907 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1908 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1909 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1910 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1911 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1912 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1913 //}
1914 }
1915 } else {
1916 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1917 }
1918 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1919 }
1920 else if(event.getType() == GShell.SCHEDULE) {
1921 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1922 }
1923 else {
1924 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1925 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1926 }
1927
1928 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.
1929 }
1930 }
1931
1932
1933 /** Determine if the manager is ready for actions apon its collection.
1934 * @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.
1935 */
1936 static public synchronized boolean ready() {
1937 if(collection != null) {
1938 return true;
1939 }
1940 else {
1941 return false;
1942 }
1943 }
1944
1945
1946 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1947 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1948 */
1949 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1950 build_monitor = monitor;
1951 }
1952 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1953 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1954 */
1955 public void registerImportMonitor(GShellProgressMonitor monitor) {
1956 import_monitor = monitor;
1957 }
1958
1959 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1960 schedule_monitor = monitor;
1961 }
1962
1963
1964 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1965 {
1966 collection_contents_changed_listeners.remove(listener);
1967 }
1968
1969
1970 public void removeMetadataSet(MetadataSet metadata_set)
1971 {
1972 DebugStream.println("Removing metadata set...");
1973
1974 // Delete the .mds file from the collection's "metadata" folder...
1975 File metadata_set_file = metadata_set.getMetadataSetFile();
1976
1977 // ...but not if it is the "ex.mds" file
1978 if (metadata_set_file.getName().equals("ex.mds")) {
1979 return;
1980 }
1981
1982 // ...and only if it exists
1983 if (metadata_set_file.exists()) {
1984 metadata_set_file.delete();
1985
1986 // Unload it from the MetadataSetManager
1987 MetadataSetManager.unloadMetadataSet(metadata_set);
1988
1989 // If we're using a remote Greenstone server, delete the metadata file on the server
1990 if (Gatherer.isGsdlRemote) {
1991 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1992 }
1993 }
1994 }
1995
1996
1997 /** Used to check whether all open collections have a 'saved' state.
1998 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1999 * @see org.greenstone.gatherer.collection.Collection
2000 */
2001 public boolean saved() {
2002 boolean result = true;
2003 if(collection != null) {
2004 result = collection.getSaved();
2005 }
2006 return result;
2007 }
2008
2009
2010 /** Saves the currently loaded collection. */
2011 public void saveCollection()
2012 {
2013
2014 if (collection == null) return;
2015
2016 DebugStream.println("Saving collection " + collection.getName() + "...");
2017
2018 // Change cursor to hourglass
2019 Gatherer.g_man.wait(true);
2020
2021 // Create a backup of the collection file, just in case anything goes wrong
2022 File collection_file = new File(getLoadedCollectionColFilePath());
2023 if (collection_file.exists()) {
2024 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
2025 if (!collection_file.renameTo(collection_file_backup)) {
2026 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
2027 }
2028 collection_file_backup.deleteOnExit();
2029 }
2030
2031 // Write out the collection file
2032 collection.save();
2033
2034 // Write out the collection configuration file
2035 collection.cdm.save();
2036
2037 // Change cursor back to normal
2038 Gatherer.g_man.wait(false);
2039 }
2040
2041
2042 /** 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] */
2043 // now add in greenstone metadata set too.
2044 private void addDefaultMetadataSets()
2045 {
2046 // Add dublin core which is the default metadata set. The user
2047 // can change this later
2048 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
2049 if (dc_file.exists()) {
2050 importMetadataSet(new MetadataSet(dc_file));
2051 }
2052 File gs_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"greenstone.mds");
2053 if (gs_file.exists()) {
2054 importMetadataSet(new MetadataSet(gs_file));
2055 }
2056 }
2057
2058
2059 private void addRequiredMetadataSets()
2060 {
2061 // Always import the extracted metadata set
2062 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
2063 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
2064 }
2065
2066 private String getDefaultCollectDirectory() {
2067 String collect_dir = Gatherer.getCollectDirectoryPath();
2068 // Remove erroneous file windows file separator as it causes problems when running import.pl
2069 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
2070 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
2071 }
2072 return collect_dir;
2073 }
2074
2075 // used as arg in the perl scripts
2076 private String getCollectDirectory() {
2077 String collect_dir = Gatherer.getCollectDirectoryPath();
2078 return collect_dir.substring(0, collect_dir.length()-1); // remove trailing slash
2079
2080 // the following will stick any colgroup at the end of the collect directory, making it no longer
2081 // possible to get the real collect dir in a general manner if this were located outside greenstone
2082 //String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
2083 //return collect_dir;
2084 }
2085
2086 public static String getBuildType() {
2087 String buildType = (new CollectionMeta( CollectionDesignManager.collect_config.getBuildType() )).getValue(CollectionMeta.TEXT);
2088 return buildType;
2089 }
2090
2091 public static boolean isSolrCollection() {
2092 return (Gatherer.GS3 && CollectionManager.getBuildType().equals("solr"));
2093 }
2094
2095
2096 /** Install collection by moving its files from building to index after a successful build.
2097 * @see org.greenstone.gatherer.Gatherer
2098 * @see org.greenstone.gatherer.util.Utility
2099 */
2100 private boolean installCollection()
2101 {
2102 if (Configuration.fedora_info.isActive()) {
2103 DebugStream.println("Fedora build complete. No need to move files.");
2104 return true;
2105 }
2106
2107 DebugStream.println("Build complete. Moving files.");
2108
2109 try {
2110 // Ensure that the local library has released this collection so we can delete the index directory
2111 if (LocalLibraryServer.isRunning() == true) {
2112 LocalLibraryServer.releaseCollection(getLoadedCollectionName(true)); // URL style slash //collection.getName());
2113 }
2114 // deactivate it in tomcat so that windows will release the index files
2115 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
2116 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
2117 }
2118 /*
2119 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
2120 DebugStream.println("Index = " + index_dir.getAbsolutePath());
2121
2122 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
2123 DebugStream.println("Building = " + building_dir.getAbsolutePath());
2124
2125 // Get the build mode from the build options
2126 String build_mode = collection.build_options.getValue("mode");
2127
2128 // Special case for build mode "all": replace index dir with building dir
2129 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
2130 // Remove the old index directory
2131 if (index_dir.exists()) {
2132 Utility.delete(index_dir);
2133
2134 // Wait for a couple of seconds, just for luck
2135 wait(2000);
2136
2137 // Check the delete worked
2138 if (index_dir.exists()) {
2139 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
2140 }
2141 }
2142
2143 if (Gatherer.isGsdlRemote) {
2144 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
2145 collection.getGroupQualifiedName(false), new File(getLoadedCollectionIndexDirectoryPath()));
2146 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getGroupQualifiedName(false),
2147 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
2148 }
2149
2150 // Move the building directory to become the new index directory
2151 if (building_dir.renameTo(index_dir) == false) {
2152 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
2153 }
2154 }
2155
2156 // Otherwise copy everything in the building dir into the index dir
2157 else {
2158 moveContentsInto(building_dir, index_dir);
2159 }
2160
2161 // move oai tmpdb to oai livedb
2162 */
2163
2164 }
2165 catch (Exception exception) {
2166 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
2167 return false;
2168 }
2169 return true;
2170 }
2171
2172
2173 /** Moves all the files in one directory into another, overwriting existing files */
2174 private void moveContentsInto(File source_directory, File target_directory)
2175 {
2176 File[] source_files = source_directory.listFiles();
2177 for (int i = 0; i < source_files.length; i++) {
2178 File source_file = source_files[i];
2179 File target_file = new File(target_directory, source_file.getName());
2180
2181 if (source_file.isDirectory()) {
2182 moveContentsInto(source_file, target_file);
2183 source_file.delete();
2184 }
2185 else {
2186 if (target_file.exists()) {
2187 target_file.delete();
2188 }
2189
2190 source_file.renameTo(target_file);
2191 }
2192 }
2193 }
2194
2195 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
2196 //In this method, the files base_cfg and new_cfg are all xml files.
2197
2198 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
2199 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
2200 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
2201 Element collection_config = new_cfg_doc.getDocumentElement();
2202
2203 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
2204 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
2205 int num_nodes = classifier_children.getLength();
2206
2207 if (num_nodes < 1) {
2208 return;
2209 }
2210
2211 // Read in the classifier command watching for hfile, metadata and sort arguments.
2212 String buttonname = null;
2213 String hfile = null;
2214 String metadata = null;
2215 String sort = null;
2216
2217 for (int i=0; i<num_nodes; i++) {
2218 Element classifier_element = (Element)classifier_children.item(i);
2219 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2220 for (int j=0; j<option_children.getLength(); j++) {
2221 Element option_element = (Element)option_children.item(j);
2222 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2223 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
2224
2225 if (name_str == null || name_str.equals("")) {
2226 continue;
2227 }
2228 if (name_str != null && value_str == null ) {
2229 value_str = "";
2230 }
2231 if (name_str.equals("hfile")) {
2232 hfile = value_str;
2233 }
2234 else if (name_str.equals("metadata") && value_str != null) {
2235 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2236 if (replacement != null && !replacement.equals("")) {
2237 metadata = replacement;
2238 }
2239 }
2240 else if (name_str.equals("sort") && value_str != null) {
2241 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2242 if (replacement != null && !replacement.equals("")) {
2243 sort = replacement;
2244 }
2245 }
2246 else if(name_str.equals("buttonname") && value_str != null) {
2247 buttonname = value_str;
2248 }
2249 }
2250 }
2251 for (int i=0; i<num_nodes; i++) {
2252 Element classifier_element = (Element)classifier_children.item(i);
2253 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2254 for (int j=0; j<option_children.getLength(); j++) {
2255 Element option_element = (Element)option_children.item(j);
2256 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2257
2258 if (name_str.equals("metadata") && metadata != null) {
2259 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2260 }
2261 else if (name_str.equals("hfile") && hfile != null) {
2262 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
2263 }
2264 else if (name_str.equals("sort") && sort != null) {
2265 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
2266 }
2267 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
2268 // No buttonname has been specified. Lets create one using the metadata as its value
2269 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
2270 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
2271 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2272 classifier_element.appendChild(option);
2273 }
2274 }
2275 }
2276 }
2277
2278 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
2279 {
2280 boolean first_name = true;
2281 boolean first_extra = true;
2282
2283 // 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.
2284 try {
2285 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
2286 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
2287 String command = null;
2288 while((command = in.readLine()) != null) {
2289 if (command.length()==0) {
2290 // output a new line
2291 out.newLine();
2292 continue;
2293 }
2294 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
2295 while(command.trim().endsWith("\\")) {
2296 command = command.substring(0, command.lastIndexOf("\\"));
2297 String next_line = in.readLine();
2298 if(next_line != null) {
2299 command = command + next_line;
2300 }
2301 }
2302 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
2303 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
2304 String command_type_str = tokenizer.nextToken().toLowerCase();
2305
2306 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
2307 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
2308 StringBuffer new_command = new StringBuffer(command_type_str);
2309 String meta_name = tokenizer.nextToken();
2310 new_command.append(' ');
2311 new_command.append(meta_name);
2312 while (tokenizer.hasMoreTokens()) {
2313 new_command.append(' ');
2314 new_command.append(tokenizer.nextToken());
2315 }
2316 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)) {
2317 // dont save
2318 } else {
2319 write(out, new_command.toString());
2320 }
2321 new_command = null;
2322 continue;
2323 } // if collectionmeta
2324
2325 if (command_type_str.equals("classify")) {
2326 StringBuffer text = new StringBuffer(command_type_str);
2327 // Read in the classifier command watching for hfile, metadata and sort arguments.
2328 String buttonname = null;
2329 String hfile = null;
2330 String new_metadata = null;
2331 String old_metadata = null;
2332
2333 while(tokenizer.hasMoreTokens()) {
2334 String token = tokenizer.nextToken();
2335 if (token.equals("-hfile")) {
2336 if(tokenizer.hasMoreTokens()) {
2337 text.append(" ");
2338 text.append(token);
2339 token = tokenizer.nextToken();
2340 hfile = token;
2341 }
2342 }
2343 else if (token.equals("-metadata")) {
2344 if(tokenizer.hasMoreTokens()) {
2345 text.append(" ");
2346 text.append(token);
2347 String temp_metadata = tokenizer.nextToken();
2348 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2349 if (replacement != null && !replacement.equals("")) {
2350 token = replacement;
2351 old_metadata = temp_metadata;
2352 new_metadata = replacement;
2353 }
2354 else {
2355 token = temp_metadata;
2356 }
2357 temp_metadata = null;
2358 replacement = null;
2359 }
2360 }
2361 else if (token.equals("-sort")) {
2362 if(tokenizer.hasMoreTokens()) {
2363 text.append(" ");
2364 text.append(token);
2365 String temp_metadata = tokenizer.nextToken();
2366 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2367 if (replacement != null && !replacement.equals("")) {
2368 token = replacement;
2369 }
2370 else {
2371 token = temp_metadata;
2372 }
2373 temp_metadata = null;
2374 replacement = null;
2375 }
2376 }
2377 else if(token.equals("-buttonname")) {
2378 buttonname = token;
2379 }
2380 text.append(' ');
2381 text.append(token);
2382 token = null;
2383 }
2384
2385 // 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)!
2386 if(old_metadata != null && new_metadata != null && buttonname == null) {
2387 text.append(' ');
2388 text.append("-buttonname");
2389 text.append(' ');
2390 text.append(old_metadata);
2391 }
2392 command = text.toString();
2393 // Replace the hfile if we found it
2394 if(hfile != null && new_metadata != null) {
2395 command = command.replaceAll(hfile, new_metadata + ".txt");
2396 }
2397
2398 buttonname = null;
2399 hfile = null;
2400 new_metadata = null;
2401 old_metadata = null;
2402 write(out, command);
2403 } else {
2404 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2405 StringBuffer new_command = new StringBuffer(command_type_str);
2406 while (tokenizer.hasMoreTokens()) {
2407 new_command.append(' ');
2408 new_command.append(tokenizer.nextToken());
2409 }
2410
2411 command = new_command.toString();
2412
2413 // 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.
2414 // we really want to build up the whole command here
2415 boolean format_command = command_type_str.equals("format");
2416 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2417 if (metadata_mapping != null) {
2418 Iterator keys = metadata_mapping.keySet().iterator();
2419 while (keys.hasNext()) {
2420 String target = (String) keys.next();
2421 String replacement = (String) metadata_mapping.get(target);
2422 if (replacement != null && !replacement.equals("")) {
2423 if (format_command) {
2424 target = "\\[" + target + "\\]";
2425 replacement = "{Or}{[" + replacement + "]," + target + "}";
2426 }
2427 command = command.replaceAll(target, replacement);
2428 }
2429 }
2430 }
2431
2432 write(out, command);
2433 }
2434 tokenizer = null;
2435 }
2436 in.close();
2437 in = null;
2438 out.flush();
2439 out.close();
2440 out = null;
2441 }
2442 catch(Exception error) {
2443 DebugStream.printStackTrace(error);
2444 }
2445 // All done, I hope.
2446 }
2447
2448 private void write(BufferedWriter out, String message)
2449 throws Exception {
2450 out.write(message, 0, message.length());
2451 out.newLine();
2452 }
2453
2454
2455 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2456 private class FMTreeModelListener
2457 implements TreeModelListener {
2458 /** 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.
2459 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2460 */
2461 public void treeNodesChanged(TreeModelEvent event) {
2462 if(collection != null) {
2463 collection.setSaved(false);
2464 collection.setFilesChanged(true);
2465 }
2466 }
2467 /** 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.
2468 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2469 */
2470 public void treeNodesInserted(TreeModelEvent event) {
2471 if(collection != null) {
2472 collection.setSaved(false);
2473 collection.setFilesChanged(true);
2474 }
2475 }
2476 /** 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.
2477 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2478 */
2479 public void treeNodesRemoved(TreeModelEvent event) {
2480 if(collection != null) {
2481 collection.setSaved(false);
2482 collection.setFilesChanged(true);
2483
2484 }
2485 }
2486 /** 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.
2487 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2488 */
2489 public void treeStructureChanged(TreeModelEvent event) {
2490 if(collection != null) {
2491 collection.setSaved(false);
2492 }
2493 }
2494 }
2495}
Note: See TracBrowser for help on using the repository browser.