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

Last change on this file since 37419 was 37419, checked in by davidb, 14 months ago

In the case of webswing, we want the GS3 logged in username, not the backend system username (which is whatever user is running tomcat, not what we want in this cas); some whitespace also introduced

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